【问题标题】:Get scroll position of ViewCell inside ListView Xamarin Form获取 ListView Xamarin Form 中 ViewCell 的滚动位置
【发布时间】:2018-05-15 16:10:01
【问题描述】:

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

尝试了各种方法,但总是给我 0 价值。

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

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

【问题讨论】:

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


    【解决方案1】:

    您必须使 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();
        }
    }
    

    }

    【讨论】:

    • 谢谢。但是我没有创建原生渲染器就解决了。你的解决方案我没试过,可能也可以优化解决方案。
    【解决方案2】:

    我找到了解决办法,

    问题:

    我的意图是获取 ViewCell 在屏幕中的位置

    解决方案:

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

    【讨论】:

    • 目前我无法使用该代码,但编写代码来实现上述步骤将使您获得预期的 X、Y 坐标。
    猜你喜欢
    • 2019-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    相关资源
    最近更新 更多