Search code examples
c#androidxamarinscrollviewonscrolllistener

Xamarin android C# ScrollView OnScrollChanged event


In Xamarin Android how can we extend the ScrollView in order to use the protected OnScrollChanged event?

Specifically, How do we extend the ScrollView to allow an EventHandler to be registered to the OnScrollChanged event? What other methods of ScrollView need to be implemented in a class that extends ScrollView?

Reasons:

The Android ScrollView does not have a way to listen for a scroll event. There have been various questions regarding how to extend ScrollView in native Android Java, however, there is not a question and answer addressing how to apply this to Xamarin.


Solution

  • In order to extend ScrollView in this way we should implement 3 constructors

    public UsefulScrollView(Context context)
    public UsefulScrollView(Context context, IAttributeSet attrs)
    public UsefulScrollView(Context context, IAttributeSet attrs, int defStyle)
    

    We also need to override the OnDraw method

    protected override void OnDraw(Android.Graphics.Canvas canvas)
    

    To achieve the functionality of an event that we can respond to when the user scrolls we need to override the OnScrollChanged method.

    protected override void OnScrollChanged(int l, int t, int oldl, int oldt)
    

    There are multiple ways to allow event listening and handling, but in order to be consistent with Xamarin we can add a public EventHandler property to our class.

    public EventHandler<T> ScrollEventHandler { get; set; }
    

    We will want to pass along the values from OnScrollChanged to the EventHandler, so let's extend EventArgs

    public class UsefulScrollEventArgs : EventArgs{
        public int l { get; set; }
        public int t { get; set; }
        public int oldl { get; set; }
        public int oldt { get; set; }
    }
    

    Finally, don't forget to initialize our handler in each of our constructors

    ScrollEventHandler = (object sender, UsefulScrollEventArgs e) => {};
    

    Put it all together and it might look something like this

    Extended EventArgs class

    public class UsefulScrollEventArgs : EventArgs{
        public int l { get; set; }
        public int t { get; set; }
        public int oldl { get; set; }
        public int oldt { get; set; }
    }
    

    Extended ScrollView class

    public class UsefulScrollView : ScrollView
    {
        public EventHandler<UsefulScrollEventArgs> ScrollEventHandler { get; set; }
        public UsefulScrollView (Context context)
        : base(context)
        {
            ScrollEventHandler = (object sender, UsefulScrollEventArgs e) => {};
        }
        public UsefulScrollView (Context context, IAttributeSet attrs)
        : base(context, attrs) {
            ScrollEventHandler = (object sender, UsefulScrollEventArgs e) => {};
    
        }
        public UsefulScrollView(Context context, IAttributeSet attrs, int defStyle)
        : base(context, attrs, defStyle) {
            ScrollEventHandler = (object sender, UsefulScrollEventArgs e) => {};
    
        }
        protected override void OnScrollChanged(int l, int t, int oldl, int oldt)
        {
            ScrollEventHandler (this, 
                       new UsefulScrollEventArgs ()
                       {l=l,t=t,oldl=oldl,oldt=oldt});
            base.OnScrollChanged (l, t, oldl, oldt);
        }
        protected override void OnDraw(Android.Graphics.Canvas canvas)
        {
    
        }
    }
    

    This Q&A was helpful in figuring this problem out: Scrollview listener is not working in Xamarin for Android?