dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.83k stars 1.67k forks source link

Android Border CustomHandler Drag Event #21186

Open AaronBastian opened 3 months ago

AaronBastian commented 3 months ago

Description

We have some code that we're converting over from Xamarin Forms. That old code had very specific behaviors per platform that occurred on an element drag and drop that forced us to move away from the Xamarin Forms drag and drop functionality and use Custom Renderers instead. We have converted these custom renderers to Custom Handlers off of a Border, and all works beautifully for iOS. However, Android's Drag event never fires. There also seems to be intermittent interference with the LongClick event handler as well. It works most of the time and does not sometimes.

Steps to Reproduce

  1. Create a MAUI app with a view that contains a border element
  2. Create a custom border handler for iOS and for android Android handler:

    public partial class BorderHandler : Microsoft.Maui.Handlers.BorderHandler
    {
    protected override void ConnectHandler(ContentViewGroup platformView)
    {
        PlatformView.LongClick += OnLongClick; // fires on long click
        PlatformView.Touch += OnTouch; // fires on touch
        PlatformView.Drag += OnDrag; // never ever fires
        base.ConnectHandler(platformView);
    }
    
    private void OnTouch(object? sender, View.TouchEventArgs e)
    {
        if (VirtualView is Border border)
        {
            border.BackgroundColor = Colors.Red;
        }
    }
    
    private void OnDrag(object? sender, View.DragEventArgs e)
    {
        if (VirtualView is Border border)
        {
            border.BackgroundColor = Colors.Gold;
        }
    }
    
    private void OnLongClick(object? sender, View.LongClickEventArgs e)
    {
        if (VirtualView is Border border)
        {
            border.BackgroundColor = Colors.Aqua;
        }
    }
    
    protected override void DisconnectHandler(ContentViewGroup platformView)
    {
        PlatformView.LongClick -= OnLongClick;
        PlatformView.Drag -= OnDrag;
        PlatformView.Touch -= OnTouch;
    
        base.DisconnectHandler(platformView);
    }
    }

iOS Handler:

public partial class BorderHandler : Microsoft.Maui.Handlers.BorderHandler
{
    private readonly UILongPressGestureRecognizer _longPressGestureRecognizer;
    private readonly UIPanGestureRecognizer _panGestureRecognizer;
    private readonly UITapGestureRecognizer _tapGestureRecognizer;

    public BorderHandler()
    {
        _longPressGestureRecognizer = new UILongPressGestureRecognizer(HandleLongClick);
        _panGestureRecognizer = new UIPanGestureRecognizer(HandleDrag);
        _tapGestureRecognizer = new UITapGestureRecognizer(HandleTap);
    }

    protected override void ConnectHandler(ContentView platformView)
    {
        PlatformView.UserInteractionEnabled = true;
        PlatformView.AddGestureRecognizer(_longPressGestureRecognizer);
        PlatformView.AddGestureRecognizer(_panGestureRecognizer);
        PlatformView.AddGestureRecognizer(_tapGestureRecognizer);
        base.ConnectHandler(platformView);
    }

    protected override void DisconnectHandler(ContentView platformView)
    {
        PlatformView.RemoveGestureRecognizer(_longPressGestureRecognizer);
        PlatformView.RemoveGestureRecognizer(_panGestureRecognizer);
        PlatformView.RemoveGestureRecognizer(_tapGestureRecognizer);
        PlatformView.UserInteractionEnabled = false;
        base.DisconnectHandler(platformView);
    }

    private void HandleLongClick(UILongPressGestureRecognizer sender)
    {
        if (VirtualView is Border border)
        {
            border.BackgroundColor = Colors.Aqua;
        }
    }

    private void HandleDrag(UIPanGestureRecognizer sender)
    {
        if (VirtualView is Border border)
        {
            border.BackgroundColor = Colors.Gold;
        }
    }

    private void HandleTap(UITapGestureRecognizer sender)
    {
        if (VirtualView is Border border)
        {
            border.BackgroundColor = Colors.Red;
        }
    }
}
  1. Add handlers in the MauiApp.cs
    
    public static class MauiProgram
    {
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });
        builder.ConfigureMauiHandlers(handlers =>
        {
            handlers.AddHandler(typeof(Border), typeof(BorderHandler));
        });

if DEBUG

    builder.Logging.AddDebug();

endif

    return builder.Build();
}

}


4. Run the app in iOS and see the background colors of the border change color when touching, long pressing, or dragging.
5. Run the app in Android and see the background colors of the border change when touching, long pressing, **but not dragging**
6. Put breakpoints on the `OnDrag` method of the Android handler and see that they never get hit.

### Link to public reproduction project repository

https://github.com/AaronBastian/MauiAndroidDragEventBug

### Version with bug

8.0.6 SR1

### Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

### Last version that worked well

Unknown/Other

### Affected platforms

Android

### Affected platform versions

_No response_

### Did you find any workaround?

Considering adding MAUI Drag/Drop behavior for only Android, building Android specific behaviors in the MAUI code, and using a compiler directive to hook up the Handler or the MAUI code based on which platform is being built.

### Relevant log output

_No response_
XamlTest commented 2 months ago

Verified this on VS 17.10.0 Preview 2.0(8.0.14). Android 14.0-API34: Touching works, long pressing doesn't work, OnDrag method never get hit. iOS 17.2: Touching, long pressing and dragging all works as expected.

MauiAndroidDragEventBug.zip