7

I'm having some trouble scrolling to the top of a ListView in Xamarin Forms. I can scroll to the first item by calling ScrollTo and passing the first item. The problem is that when the list has a header item, I can't find a way to scroll to the header. Is this possible? The only work around I can think of is to not use the header and just have another item at the start of the ItemSource list that acts as a header but I'd rather use the header if possible. Thanks.

3 Answers 3

15

So I've solved this myself now. My solution was to subclass ListView and add a public ScrollToTop method which invokes an internal ScrollToTopRequestedEvent when called. I then subclassed the ListViewRenderer on each platform and registered for the event.

In the Android renderer I'm then calling Control.SmoothScrollToPositionFromTop(0, 0) to scroll to top.

In the iOS rendered I'm calling Control.ScrollRectToVisible(new CoreGraphics.CGRect(0, 0, 1, 1), true).

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Gareth that put me on the right track! I ended up using an Action instead of an event, but this works perfectly ;)
Can you please provide the code? I'm Android developer and newbie in Xamarin :)
5

Wah all credits @Gareth Wynn, man that was cool thx. Anyway here's the code for everyone to use, change class names and namespace, iOS not included, do same as for Android just using Gareth Wynn's hint in parallel answer:

SHARED NiftyListView.cs :

        using System;
        using Xamarin.Forms;

            namespace AppoMobi
            {
                public class NiftyListView : CListView
                {
                    public event EventHandler EventScrollToTop;

                    //-------------------------------------------------------------------
                    public void ScrollToTop(bool animate=true)
                    //-------------------------------------------------------------------
                    {
                        //bool animate is not used at this stage, it's always animated.
                        EventScrollToTop?.Invoke(this, EventArgs.Empty);
                    }
                }
            }

ANDROID NiftyListView.Android.cs :

using System;
using AppoMobi;
using AppoMobi.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using ListView = Xamarin.Forms.ListView;

[assembly: ExportRenderer(typeof(NiftyListView), typeof(NiftyListViewRenderer))]
namespace AppoMobi.Droid.Renderers
{
    //-------------------------------------------------------------------
    class NiftyListViewRenderer : ListViewRenderer
    //-------------------------------------------------------------------
    {
        protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
        {
            base.OnElementChanged(e);

            var view = (NiftyListView)Element;
            if (view == null) return;

            view.EventScrollToTop += OnScrollToTop;

        }

        //-------------------------------------------------------------------------------------------
        public async void OnScrollToTop(object sender, EventArgs eventArgs)
        //-------------------------------------------------------------------------------------------
        {
            Control.SmoothScrollToPositionFromTop(0, 0);
        }

    }
}

2 Comments

Hey, it's great that you shared the code. From memory, I think that SmoothScroll is quite slow for lists with a large number of items. I swapped it for another method but I don't remember what it was. I'll see if I can dig my code out and post that as well.
@GarethWynn For Android I used Control.SetSelectionAfterHeaderView() for non-smooth scrolling.
0

ScrollTo(Object, Object, ScrollToPosition, Boolean) Scrolls the ListView to the item in the group https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.listview.scrollto?view=xamarin-forms

Model for each group:

public class Notification {
 public int Id { get; set; }
 public string Title { get; set; };
 public Notification(int id, string title) {
    Id = id;
    Title = title;
 }
}

Group-Model for ItemSource:

public class NotificationGroup: List<Notification> {
 public string Title { get; set; }
 public string ShortTitle { get; set; }
 public NotificationGroup(string title) {
    Title = title;
 }
}

Sample Data & Usage:

//SAMPLE DATA
var notifications = new ObservableCollection <NotificationGroup> {
 new NotificationGroup("Group-01") {
   new Notification(1, "Item-1"),
   new Notification(2, "Item-2")
 },
 new NotificationGroup("Group-02") {
   new Notification(3, "Item-3"),
   new Notification(4, "Item-4")
 }
};
YourListViewName.ItemSource = notifications;

//USING
YourListViewName.ScrollTo(notifications.First()[0], notifications.First(), ScrollToPosition.Start, true);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.