iosformslistviewxamarinscroll-position

How to set a ListView Scroll position to bottom, before ListView will appears in Xamarin Forms iOS?


In Xamarin Forms for iOS, I try to set Scroll-position for ListView before it will appears. When the ListView shown, triggered the visibly scrolling to bottom. Is there any ideas, how to set the scroll position before the ListView will appear?

[assembly: ExportRenderer(typeof(MyListView), typeof(NativeiOSListViewRenderer))]
namespace MyApp.iOS.Renderers
{ 
    public class NativeiOSListViewRenderer : ListViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
        {
            base.OnElementChanged(e); 

            if (e.NewElement != null)
            { 
                var element = e.NewElement as MyListView;

                if (element.ItemsSource is IList items && items.Count > 0)
                { 
                    var tableView = Control as UITableView;
                    var indexPath = NSIndexPath.FromItemSection(itemIndexitems.Count - 1, 0);
                    tableView.ScrollToRow(indexPath, UITableViewScrollPosition.Bottom, false);
                } 
            }
        } 
    }
}

Solution

  • Cause:

    When you call the code which scroll the listview to buttom in method OnElementChanged.The listview have not finished init. So it didn't work.

    Solution:

    You can use MessagingCenter to send notification to scroll the listview in the method OnAppearing.

    in your contentPage

     protected override void OnAppearing()
     {
       base.OnAppearing();
       MessagingCenter.Send<Object>(this, "ScrollToButtom");
     }
    

    in iOS Renderer

    public class NativeiOSListViewRenderer : ListViewRenderer
    {
        public NativeiOSListViewRenderer ()
        {
            MessagingCenter.Subscribe<Object>(this, "ScrollToButtom", (obj) => {
                var element = Element as MyListView;
                if (element.ItemsSource is IList<string> items && items.Count > 0)
                {
                    var tableView = Control as UITableView;
                    var indexPath = NSIndexPath.FromItemSection(items.Count - 1, 0);
                    tableView.ScrollToRow(indexPath, UITableViewScrollPosition.Bottom, false);
                }
            });
        }
    
    }
    

    Update: The solution works fine on my device.If it still didn't work on your project.You can override the method WillDisplay

    public class MyListViewRenderer:ListViewRenderer,IUITableViewDelegate
    {
    
        bool isFirstLoad = true;
    
        public MyListViewRenderer()
        {
    
    
        }
    
        [Export("tableView:willDisplayCell:forRowAtIndexPath:")]
        public void WillDisplay(UITableView tableView,UITableViewCell cell,NSIndexPath indexPath)
        {
           if(isFirstLoad)
            {
    
                var element = Element as MyListView;
    
                if (element.ItemsSource is IList<string> items && items.Count > 0)
                {
    
                 if(indexPath.Row!=items.Count-1)
                    {
                        NSIndexPath nSIndexPath = NSIndexPath.FromItemSection(indexPath.Row + 1, 0);
                        tableView.ScrollToRow(nSIndexPath, UITableViewScrollPosition.Bottom, false);
    
                    }
                 else
                    {
                        isFirstLoad = false;
                    }
                }
    
            }
        }
    
        protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
        {
            base.OnElementChanged(e);
    
            if(Control!=null)
            {
                Control.WeakDelegate = this;
            }
    
        }
    
    }
    

    I have uploaded my sample here ,you can download and have a try.