How to scroll to last item in ListView

nerowareneroware USMember ✭✭
edited June 2015 in Xamarin.Forms

Hello. I'm using Forms 1.4.2.6359 and I have a ListView with HasUnevenRows = true. I'm trying to get the ListView to scroll to the last item in the list after its ItemSource is asynchronously populated after the view initially loads, but I'm not sure it's working as expected. I should also mention that the row heights vary widely.

Is there anything wrong with the following code -- am I using the ListView.ScrollTo method incorrectly or am I missing something here?

public Task NotifyDataLoadedAsync ()
{
    var lastMessage = this.MessagesListView.ItemsSource.Cast<object> ().LastOrDefault ();
    if (null != lastMessage) {
        this.MessagesListView.ScrollTo (lastMessage, ScrollToPosition.End, true);
    }

    return Task.FromResult (0);
}

Answers

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @neroware:

    I use it this way (to scroll to top):

    int indexToScrollTo = 0;
    lvErgebnisAnzeige.ScrollTo(GV.PL_Empfehlungen[indexToScrollTo], ScrollToPosition.Start, false);
    

    where GV.PL_Empfehlungen is the bound list.
    I would try it with set indexToScrollTo to the index of the last item in the List and ScrollToPosition.End

  • nerowareneroware USMember ✭✭

    Hi @FredyWenger, thanks for the reply. LastOrDefault() is returning the last item in the bound collection, and the item to which I want the ListView to scroll. As you can see, I'm already using ScrollToPosition.End in my example, so no luck there. Setting the animate parameter to false does scroll the ListView closer to the last item, but I'm not sure I want to resort to losing the animation and it doesn't solve the problem at any rate.

  • yuqitianyuqitian CNMember

    When I use listview in Android, I found the following bug. Is any people known how to fix it?

    Xamarin.Forms 1.4
    Android ListView ScrollTo method exception:

    MyCode

    lastItem = listView.ItemsSource.OfType().Last();
    listView.ScrollTo(lastItem, ScrollToPosition.End, false);

    [MonoDroid] UNHANDLED EXCEPTION:
    [MonoDroid] System.MissingMethodException: Method 'AbsListView.SetSelectionFromTop' not found.
    [MonoDroid] at Xamarin.Forms.ListView.OnScrollToRequested (Xamarin.Forms.ScrollToRequestedEventArgs)
    [MonoDroid] at Xamarin.Forms.ListView.ScrollTo (object,Xamarin.Forms.ScrollToPosition,bool)
    [MonoDroid] at ListViewScrollToDemo.TestPage/<>c__DisplayClass8.<.ctor>b__7 (object,System.EventArgs) [0x00024] in c:\Users\yuqit\Downloads\ListViewScrollToDemo\ListViewScrollToDemo\ListViewScrollToDemo\ListViewScrollToDemo\TestPage.cs:49
    [MonoDroid] at Xamarin.Forms.Button.Xamarin.Forms.IButtonController.SendClicked ()
    [MonoDroid] at Xamarin.Forms.Platform.Android.ButtonRenderer/ButtonClickListener.OnClick (Android.Views.View)
    [MonoDroid] at Android.Views.View/IOnClickListenerInvoker.n_OnClick_Landroid_view_View_ (intptr,intptr,intptr) [0x00011] in /Users/builder/data/lanes/2058/58099c53/source/monodroid/src/Mono.Android/platforms/android-19/src/generated/Android.Views.View.cs:1745
    [MonoDroid] at (wrapper dynamic-method) object.abe245bf-73a6-474b-ae01-915c7f9d3c4a (intptr,intptr,intptr)
    [AndroidRuntime] Shutting down VM

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @neroware Is this on iOS?

  • Darth_AaronDarth_Aaron USMember

    I'm using version 2.01 and getting this same exception No Method AbsListView.SetSelectionFromTop

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭
    edited January 2016

    @neroware - In terms of the code that you posted above, it looks fine. I popped the following into my app to check, and it worked ok on WinRT (which is usually the most troublesome platform).

            var v = _listView.ItemsSource.Cast<object>().LastOrDefault();
            _listView.ScrollTo(v, ScrollToPosition.End, true);
    

    However, there is a bug in XF on iOS, so when I tried the same code on iOS it failed to scroll. This could be what you are hitting if you are running on iOS. It is logged in bugzilla at https://bugzilla.xamarin.com/show_bug.cgi?id=28277

    If that's not it, then:

    If you are testing on WinRT, there are definitely problems with ScrollTo and ScrollToAsync on ScrollViews on WinRT (I have logged two in bugzilla), although I do wonder if ListView does not share the scrolling code with ScrollView, as the snippet above works fine, even on WinRT.

    Also, if you can, you might want to try upgrading to XF 2.0 as, if I remember correctly, 1.4.2.6359 was the most troublesome version that I used since starting with XF at the end of 2014.

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    @yuqitian - Have a look at these two threads:

    http://forums.xamarin.com/discussion/32372/debug-error
    where Jason Smith says
    "The error seen at the top of the thread indicates the build targets are set incorrectly in the project configuration."

    and
    https://forums.xamarin.com/discussion/41625/listview-scrollto-not-working-on-android
    where Kent Green from the support team went into more detail about what needs to be done.

  • KarineROBINOTKarineROBINOT USMember

    Does anybody find a solution for iOs ?

    It works fine for android app but not for iOs.

    I tried with a StartTimer :
    Device.StartTimer(TimeSpan.FromMilliseconds(50), () => this.MessagesListView.ScrollTo(vm.Messages.LastOrDefault(), ScrollToPosition.End, false)); but it does'nt go at the end

  • In case anyone else ends up here searching for answers like I did... I found that changing the ScrollToPosition parameter to ScrollToPosition.MakeVisible got it working for me on Android and iOS. Using the logical option (ScrollToPosition.End) was not making the last item fully visible.

    var last = documentList.ItemsSource.Cast<object>().LastOrDefault();
    documentList.ScrollTo(last, ScrollToPosition.MakeVisible, true);
    
  • RianDutraRianDutra USMember ✭✭

    @N_Nightingale said:
    In case anyone else ends up here searching for answers like I did... I found that changing the ScrollToPosition parameter to ScrollToPosition.MakeVisible got it working for me on Android and iOS. Using the logical option (ScrollToPosition.End) was not making the last item fully visible.

    var last = documentList.ItemsSource.Cast<object>().LastOrDefault();
    documentList.ScrollTo(last, ScrollToPosition.MakeVisible, true);
    

    I got this exception, even if my listview is not empty:
    System.ArgumentNullException: Value cannot be null.

  • RianDutraRianDutra USMember ✭✭

    I had to create a custom ListView.

  • JosephHarveyJosephHarvey USMember

    I found i had to invoke an event notification after i added the List or added to the list, and pass the List Member object with the notification, then on the page code behind I handled that event and used the passed object in the Scroll to.

    public partial class ConversationPage : ContentPage
            {
                public ConversationPage()
                {
                    InitializeComponent();
                    MainListView.ItemTapped += OnItemTapped;
                    Appearing += ConversationPage_Appearing;
                }
    
                private void ConversationPage_Appearing(object sender, System.EventArgs e)
                {
                    if (BindingContext != null)
                    {
                        var viewModel = (ConversationViewModel)BindingContext;
                        viewModel.NotifyScrollToBottom += ViewModel_NotifyScrollToBottom;
                    }
                }
    
                private void ViewModel_NotifyScrollToBottom(Api.Models.Chat.Message Message)
                {
                    MainListView.ScrollTo(Message, ScrollToPosition.End, true);
                }
        }
    public partial class ConversationPage : ContentPage
            {
                public ConversationPage()
                {
                    InitializeComponent();
                    MainListView.ItemTapped += OnItemTapped;
                    Appearing += ConversationPage_Appearing;
                }
    
                private void ConversationPage_Appearing(object sender, System.EventArgs e)
                {
                    if (BindingContext != null)
                    {
                        var viewModel = (ConversationViewModel)BindingContext;
                        viewModel.NotifyScrollToBottom += ViewModel_NotifyScrollToBottom;
                    }
                }
    
                private void ViewModel_NotifyScrollToBottom(Api.Models.Chat.Message Message)
                {
                    MainListView.ScrollTo(Message, ScrollToPosition.End, true);
                }
        }
    
      public class ConversationViewModel : ViewModelBase
        {
    
    private void _chatService_NotifyMessageHistroyForChannel(List<Message> List, Channel Channel)
            {
                MessageList = new ObservableCollection<Message>(List);
                if(MessageList.Count > 0)
                    NotifyScrollToBottom?.Invoke(MessageList[MessageList.Count-1]);
                IsRefreshing = false;
            }
    
            private void _chatService_NotifyReceivedMessageFromUser(Message Message, string ChannelUrl, Member FromUser)
            {
                MessageList.Add(Message);
                NotifyScrollToBottom?.Invoke(Message);
    
            }
    
        }
    

    It works in Android, havent checked iOS. I hope this helps someone

  • uday_Suddhalauday_Suddhala USMember ✭✭

    generate a event in your constructor like this

    ((INotifyCollectionChanged)myList.ItemsSource).CollectionChanged += MyGroupTickets_CollectionChanged;

    then implement your method like this:

    private void MyGroupTickets_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            List<MessageData> someVar = ((IEnumerable<MessageData>)this.myList.ItemsSource).ToList();
            myList.ScrollTo(someVar[someVar.Count - 1], ScrollToPosition.End, true);
        }
    

    it will scroll to your last item in list whenever you add any item.

Sign In or Register to comment.