在ListView Xamarin表单中获取ViewCell的滚动位置

时间:2017-12-01 14:17:39

标签: uitableview xamarin.forms coordinates scroll-position screen-positioning

我想知道ListView中ViewCell的滚动位置。

尝试各种各样的方法,但总是给我0值。

我的意图是让ViewCell在屏幕上的位置。为了解决这个问题,尝试获取它的滚动位置,然后我将此值添加到ListView对象的Y值。

在这种情况下,有人可以帮助我吗?

2 个答案:

答案 0 :(得分:0)

你必须制作ViewCell的自定义渲染器,将位置发送到pcl有点棘手,然后我们在视图中订阅该事件,这是我的代码

<强> PCL

    public class SAChatViewCell : ViewCell
{
    public delegate int[] IntEventHandler(object sender, float[] postion);
    public event IntEventHandler OnCellItemLongClicked;
    public event EventHandler OnCellItemTouched;


    public void InvokeOnCellItemLongClicked(object sender, float[] e)
    {
        //send the current grid
        OnCellItemLongClicked?.Invoke(sender, e);
    }
    public void InvokeOnCellItemTouched(object sender, EventArgs e)
    {
        //send the current grid
        OnCellItemTouched?.Invoke(sender, e);
    }

}

Android渲染器

class SAChatViewCellRenderer : ViewCellRenderer
    {
        private bool selected;
        ClickListener handler = new ClickListener();
        static Android.Widget.ListView listView;
        Xamarin.Forms.ListView listviewforms;
        static SAChatViewCell cellElement;
        Android.Views.View cellControl;

        protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, Android.Views.ViewGroup parent, Android.Content.Context context)
        {
            try
            {
                if (cellControl == null)
                {
                    cellControl = base.GetCellCore(item, convertView, parent, context);
                }

                cellElement = item as SAChatViewCell;
                selected = false;


                listviewforms = cellElement.View.Parent.Parent as Xamarin.Forms.ListView;
                if (listviewforms == null)
                {
                    return null;
                }
                if (listviewforms.BackgroundColor.ToAndroid() == Color.Transparent.ToAndroid())
                {
                    cellControl.SetBackgroundColor(Color.White.ToAndroid());
                }
                else
                {

                    cellControl.SetBackgroundColor(listviewforms.BackgroundColor.ToAndroid());
                }


                cellControl.SetOnLongClickListener(handler);
                cellControl.SetOnTouchListener(handler);

                return cellControl;
            }

            catch (Exception ex)
            {
                return null;
            }
        }

        protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
        { 
            base.OnCellPropertyChanged(sender, args);
            if (args.PropertyName == "IsSelected")
            {
                // I had to create a property to track the selection because cellCore.Selected is always false.
                // Toggle selection
                selected = !selected;
                var selectedBackground = cellElement.SelectedBackgroundColor.ToAndroid();
                if (selected)
                {
                    if (selectedBackground == Color.Transparent.ToAndroid())
                    {
                        cellControl.SetBackgroundColor(Color.White.ToAndroid());
                        return;
                    }
                    cellControl.SetBackgroundColor(selectedBackground);
                }
                else
                {
                    if (listviewforms.BackgroundColor.ToAndroid() == Color.Transparent.ToAndroid())
                    {
                        cellControl.SetBackgroundColor(Color.White.ToAndroid());
                    }
                    else
                    {

                        cellControl.SetBackgroundColor(listviewforms.BackgroundColor.ToAndroid());
                    }
                }
            }
        }

        internal class ClickListener : Java.Lang.Object, IOnLongClickListener, IOnTouchListener
        {
            //event priority Touch - LongClick - Click
            //NOTE: return true to indicate that we have handled the event and it should stop here;
            public bool OnLongClick(Android.Views.View sender)
            {

                var cellItem = sender as INativeElementView;
                var viewCell = sender as Android.Views.View;

                float[] location = new float[] { 0, 0 };

                Android.Views.View parentRow = (Android.Views.View)viewCell.Parent;

                listView = (Android.Widget.ListView)parentRow.Parent;
                int position = listView.GetPositionForView(parentRow);
                var x = parentRow.Right;
                var y = (parentRow.Top - listView.DividerHeight) <= 0 ? parentRow.Bottom : parentRow.Top;

                int view_height = parentRow.Height;
                location[0] = (x / MainActivity.Current.Resources.DisplayMetrics.Density);
                location[1] = y / MainActivity.Current.Resources.DisplayMetrics.Density;
                //send current cell

                cellElement.InvokeOnCellItemLongClicked((cellItem.Element as ViewCell).View, location);
                listView.Scroll += ListView_Scroll;

                return true;
            }


            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);
                if (listView != null)
                {
                    listView.Scroll -= ListView_Scroll;
                }
            }
            private void ListView_Scroll(object sender, Android.Widget.AbsListView.ScrollEventArgs e)
            {
                cellElement.InvokeOnCellItemTouched(cellElement.View, EventArgs.Empty);
            }

            //return false if you have not handled it and/or the event should continue to any other on-click listeners.
            public bool OnTouch(Android.Views.View v, MotionEvent e)
            {
                if (e.Action == MotionEventActions.Down)
                {
                    cellElement.InvokeOnCellItemTouched(cellElement.View, EventArgs.Empty);
                    //cellCore.SetOnTouchListener(this);
                }
                return false;
            }
        }
    }
}

iOS渲染器

  class SAUITableViewCell : UITableViewCell
{
    public override void TouchesBegan(NSSet touches, UIEvent evt)
    {
        base.TouchesBegan(touches, evt);

    }
}
//When you scroll, your cells are created in real time. cells aren't created from scratch, instead iOS just takes a cell that has just left the screen and sends it through
class SAChatViewCellRenderer : ViewCellRenderer, IUIGestureRecognizerDelegate
{
    UITableView TV;
    SAChatViewCell cellElement;

    public IntPtr Handle => new IntPtr();

    public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
    {
        try
        {
            UITableViewCell cell = base.GetCell(item, reusableCell, tv);
            TV = tv;
            var uiTapGestureRecognize = new UITapGestureRecognizer(OnClick);
            var uiLongPressGestureRecognizer = new UILongPressGestureRecognizer(OnLongClick);
            uiLongPressGestureRecognizer.MinimumPressDuration = 0.5;
            cell.AddGestureRecognizer(uiTapGestureRecognize);
            cell.AddGestureRecognizer(uiLongPressGestureRecognizer);

            cellElement = item as SAChatViewCell;
            cell.BackgroundColor = UIColor.Clear;

            if (cellElement.SelectedBackgroundColor == Color.Transparent)
            { 
                cell.SelectionStyle = UITableViewCellSelectionStyle.None;
            }
            else
            {
                cell.SelectedBackgroundView = new UIView
                {
                    BackgroundColor = cellElement.SelectedBackgroundColor.ToUIColor() ?? default(UIColor)

                };
            }

            return cell;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }



    private void OnLongClick(UILongPressGestureRecognizer arg)
    {
        //get the current touch coords based on listview 
         CGPoint coords = arg.LocationInView(TV);
        //current cell
        if (arg.State != UIGestureRecognizerState.Began)
        { 
            var indexPath = TV.IndexPathForRowAtPoint(coords);

            CGRect Rect = TV.RectForRowAtIndexPath(indexPath);
            //delete the listview offset
            Rect.Offset(-TV.ContentOffset.X, -TV.ContentOffset.Y);
            var CurrentViewCell = (arg.View as UIKit.UITableViewCell).Superview;

            //Note : xamarin forms cell element  MonoTouch creates it's own internal delegate type for UIScrollView so we either override the uiviewtable or trigger the ondisappear event
            var cellItem = arg.View as INativeElementView; 
            (((cellItem.Element as ViewCell).Parent) as ListView).ItemDisappearing += (s, o) =>
            {
                cellElement.InvokeOnCellItemTouched(cellElement.View, EventArgs.Empty);
            };
            float[] location = new float[] { 0, 0 };
            location[0] = (float)Rect.X;
            var Y = Rect.Top <= 0 ? Rect.Bottom : Rect.Top;
            location[1] = (float)Y;

            cellElement.InvokeOnCellItemLongClicked((cellItem.Element as ViewCell).View, location);
        } 
    }
    private void OnClick()
    {
        cellElement.InvokeOnCellItemTouched(cellElement.View, EventArgs.Empty);
    }

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

}

答案 1 :(得分:0)

我找到了解决方案,

问题:

  

我的意图是让ViewCell在屏幕上的位置

解决方案:

  
      
  • 步骤1:将scrollview保持在Relative布局中。
  •   
  • 步骤2:当用户点击滚动视图的ViewCell时,保存相对布局的触摸点(X,Y)。在Y坐标中,添加相对布局的顶部位置,这样您将获得相对于整个屏幕的触摸点。
  •   
  • 步骤3:当用户点击滚动视图的ViewCell时,调用XYZ()方法。
  •   
  • 步骤4:在XYZ()方法内部,执行(X,Y)坐标所需的任何功能。 (注意:在XYZ()方法中执行功能会延迟300ms,因为步骤2需要一些时间进行保存   接触点。)
  •