简体   繁体   中英

Get scroll position of ViewCell inside ListView Xamarin Form

I would like to know the scroll position of ViewCell inside the ListView.

Tried with various ways but always that gives me 0 value.

My intension is to get ViewCell's position in screen. In order to resolve this problem trying to get it's scroll position and then i will add this value to the Y value of ListView object.

Can anybody please help me in this case?

you have to make custom renderer of the ViewCell its kinda tricky to send the positions to pcl then we subscribe to the event in the view here's my code

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 Renderer

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 Renderer

  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();
    }
}

}

I have found a solution,

Problem :

My intension is to get ViewCell's position in screen

Solution :

  • Step 1 : Keep scrollview inside the Relative layout.
  • Step 2 : When user click on scroll view's ViewCell, save touch point (X, Y) of relative layout. In Y co-ordinate, add top position of relative layout so you will get touch point relative to whole screen.
  • Step 3 : When user click on scroll view's ViewCell, call XYZ() method.
  • Step 4 : Inside XYZ() method, do whatever functionality which required on (X, Y) co-ordinate. (Note : put 300ms delay in doing functionality in XYZ() method, as step-2 required some time in saving touch points.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM