.net MAUI: Disable scrolling on Android

.net MAUI: Disable scrolling on Android

A quick one today!

So for a new drag and drop component I needed to temporary disable the scrolling of a parent ScrollView.

Ok no biggies I went just scrollView.IsEnable = false.

But, hey!! Nothing happens like WTFudge REALLY MAUI???

I then went to MAUI sources and saw that:

public partial class ScrollViewHandler : IScrollViewHandler
{
    public static IPropertyMapper<IScrollView, IScrollViewHandler> Mapper = new PropertyMapper<IScrollView, IScrollViewHandler>(ViewMapper)
    {
        [nameof(IScrollView.Content)] = MapContent,
        [nameof(IScrollView.HorizontalScrollBarVisibility)] = MapHorizontalScrollBarVisibility,
        [nameof(IScrollView.VerticalScrollBarVisibility)] = MapVerticalScrollBarVisibility,
        [nameof(IScrollView.Orientation)] = MapOrientation,
#if __IOS__
        [nameof(IScrollView.IsEnabled)] = MapIsEnabled,
#endif
    };
    
    ...
}

WHAT? Only supported for iOS???

AAAAAHHH.... Ok... Then I remembered.

There is indeed no way to support this natively in Android. Even Android programmers have to tweak the ScrollView in order to achieve this: you have to override touch events methods and return false.

So in Xamarin.Forms we all had a nice renderer called MySuperScrollViewRenderer which was dealing with this. Our solution is easy: just create a MAUI handler for this!

Here it is.

First create a ScrollViewEnableHandler in your_project > Platforms > Android > Handlers directory (maybe you will have a create the Handlers directory). Yes the naming sucks, I'm not lazy, it's an homage.

using _Microsoft.Android.Resource.Designer;
using global::Android.Content;
using global::Android.Runtime;
using global::Android.Util;
using global::Android.Views;

using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;

public class ScrollViewEnableHandler : ScrollViewHandler
{
    public ScrollViewEnableHandler()
    {
        Mapper.AppendToMapping(
            nameof(IScrollView.IsEnabled),
            (handler, view) =>
                ((MauiScrollViewEnable)handler.PlatformView)
                    .UpdateIsEnabled(view.IsEnabled));
    }

    protected override MauiScrollView CreatePlatformView()
    {
        var scrollView = new MauiScrollViewEnable(
            new ContextThemeWrapper(MauiContext!.Context, ResourceConstant.Style.scrollViewTheme),
            null!,
            ResourceConstant.Attribute.scrollViewStyle)
        {
            ClipToOutline = true,
            FillViewport = true,
        };

        return scrollView;
    }
}

Then create your MauiScrollViewEnable at the same location:

public class MauiScrollViewEnable : MauiScrollView
{
    private bool _disableScrolling;

    public MauiScrollViewEnable(Context context)
        : base(context)
    {
    }

    public MauiScrollViewEnable(Context context, IAttributeSet attrs)
        : base(context, attrs)
    {
    }

    public MauiScrollViewEnable(Context context, IAttributeSet attrs, int defStyleAttr)
        : base(context, attrs, defStyleAttr)
    {
    }

    protected MauiScrollViewEnable(IntPtr javaReference, JniHandleOwnership transfer)
        : base(javaReference, transfer)
    {
    }

    public void UpdateIsEnabled(bool isEnabled)
    {
        _disableScrolling = !isEnabled;
    }

    public override bool OnInterceptTouchEvent(MotionEvent? ev)
    {
        if (_disableScrolling)
        {
            return false;
        }

        return base.OnInterceptTouchEvent(ev);
    }

    public override bool OnTouchEvent(MotionEvent? ev)
    {
        if (_disableScrolling)
        {
            return false;
        }

        return base.OnTouchEvent(ev);
    }
}

And finally, update your MauiProgram file:

var builder = MauiApp.CreateBuilder();

builder
    ...
    .ConfigureMauiHandlers(handlers =>
    {
        ...
#if ANDROID
        handlers.AddHandler<ScrollView, ScrollViewEnableHandler>();     
#endif
    })

And ZOUBILOU you're done! Just like that.

You could also wait for this issue to be resolved: https://github.com/dotnet/maui/issues/18418. And then you will be able to set Orientation="Neither".