Search code examples
xamarinxamarin.formsxamarin.androidcarouselrenderer

How to disable Carousel Page scrolling in Android


Using a custom renderer one can disable the swiping gesture of an CarouselPage on iOS like so:

using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
namespace App.iOS
{
    public class CustomCarouselPageRenderer : CarouselPageRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            UIView view = this.NativeView;
            UIScrollView scrollView = (UIKit.UIScrollView)view.Subviews[0];
            scrollView.ScrollEnabled = false;
        }
    }
}

How to accomplish the same on Android?

using Android.Content;
using XamFormsApp.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
namespace StixApp.Droid.Renderers
{
    public class CustomCarouselPageRenderer : VisualElementRenderer<CarouselPage>
    {
        public CustomCarouselPageRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
        {
            base.OnElementChanged(e);
            var view = this.RootView;
            X
            X
        }
    }
}

There appears to be no way to access Subviews in the same way. One can access Children like so

Android.Views.View view = (Android.Views.View)GetChildAt(i);

How to know which Child is ScrollView if any?

Using a loop to check for this, like so,

for (int i = 0; i < ChildCount; ++i)
{
    Android.Views.View view = (Android.Views.View)GetChildAt(i);
    if (view is ScrollView)
    {
    }
}

Yields the following: "The given expression is never of the provided (ScrollView) type"

So! How to disable CarouselPage swipe/scrolling as is done in iOS quite elegantly?

UPDATE: Please see sample solution.


Solution

  • A couple of things.

    For Android the view you are looking for is not a ScrollView but a ViewPager.

    This can be found under the index 0 with the GetChildAt method.

    Also, why are you using VisualElementRenderer<CarouselPage> as the parent class of your CustomCarouselPageRenderer. Instead use the CarouselPageRenderer as you did with iOS.

    One last thing is that on Android the Scroll of a ViewPager cannot be disabled. To get this behavior you can listen to the Touch event. Setting the Handled property of TouchEventArgs to true will prevent the scrolling from happening.

    Your whole class would look something like:

    [assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
    namespace StixApp.Droid.Renderers
    {
        public class CustomCarouselPageRenderer : CarouselPageRenderer
        {
            private bool _canScroll = false;
    
            public CustomCarouselPageRenderer(Context context) : base(context)
            {
            }
    
            public CustomCarouselPageRenderer()
            {
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
            {
                base.OnElementChanged(e);
    
                if (this.ChildCount > 0  && this.GetChildAt(0) is ViewPager viewPager)
                {
                    viewPager.Touch -= ViewPagerTouched;
                    viewPager.Touch += ViewPagerTouched;
                }
            }
    
            private void ViewPagerTouched(object sender, TouchEventArgs e)
            {
                e.Handled = !_canScroll;
            }
        }
    }
    

    Just change the value of _canScroll to true to allow the scrolling.

    Hope this helps.-