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
22.26k stars 1.76k forks source link

PanGestureRecognizer behaves differently on Windows to other platforms #24252

Open beeradmoore opened 3 months ago

beeradmoore commented 3 months ago

Description

On macOS, iOS, and Android, if you have overlapping PanGestureRecognizers only the top most will fire. Internally I assume MAUI is stopping the event propegating to lower views. On Windows it allows the both PanGestureRecognizers to run.

I am unsure if this is specific to PanGestureRecognizer or if overlapped TapGestureRecognizer would do the same.

EDIT: I tested with TapGestureRecognizer and it behaves correctly across all 4 platforms.

Steps to Reproduce

  1. Add a gesture recognizer to a view (in my case PanGestureRecognizer)
  2. Add a gesture recognizer to a child view (in my case PanGestureRecognizer again)
  3. Run the application and click on the overlapping gesture recognizers

Link to public reproduction project repository

https://github.com/beeradmoore/maui-issue-PanGesutreHandling

Version with bug

8.0.80 SR8

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Windows

Affected platform versions

Windows 11

Did you find any workaround?

The project I discovered this I had a image and I want to select the image corners to resize, and anywhere else to resize.

My planned workaround is to instead make a 3x3 grid over the image where the 4 corners will handle resize, and the other 5 positions will handle pan.

Relevant log output

N/A

Sample videos

Tested on multiple platforms. Text in the top left of the screen will show what gesture recognizer is active.

Windows

https://github.com/user-attachments/assets/6ee5cc0d-a9ce-4aea-b569-9906a8ded620

macOS

https://github.com/user-attachments/assets/d87a225b-1fe2-41f7-a3ce-673599065ca5

iOS

I tested on iOS sumulator and device. This screen recording is iOS simulator.

https://github.com/user-attachments/assets/fadb86d3-08b9-4430-9278-dcbd6b79f0b3

Android

I only tested on emulator. Android exhibits its own problems with my drag implementation. But it does not trigger multiple pan gestures running at once.

(EDIT: The flickering on Android appears to be related to #20772. The sample code in this comment fixes the flicking)

https://github.com/user-attachments/assets/f47d51e6-fffb-4c95-8c2b-b566a1191650

github-actions[bot] commented 3 months ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Open similar issues:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

beeradmoore commented 3 months ago

Eyeballing the source it looks like in GesturePlatformManager.Windows.cs when OnTap is called it will process the tap for all children and if one is found it will stop.

        void OnTap(object sender, RoutedEventArgs e)
        {
            .....
            var children =
                (view as IGestureController)?.GetChildElements(new Point(tapPosition.Value.X, tapPosition.Value.Y))?.
                GetChildGesturesFor<TapGestureRecognizer>(ValidateGesture);

            if (ProcessGestureRecognizers(children))
                return;
            .....
        }

And inside ProcessGestureRecognizers it looks like e.SetHandled(true); handled = true; are both handled. However for HandlePan (and also HandleSwipe and HandlePinch as they are all handled in OnManipulationDelta) it does not look like this is set so it look like they all get handed.

I am unsure how this code works though, and this may be called per view and not handled like how ProcessGestureRecognizers handles and early exits.

EDIT: I tried to debug this further, but attempting to open MAUI on Windows crashes Visual Studio. I can open and build MAUI on macOS, but that is no good here 😂

ninachen03 commented 3 months ago

I can repro this issue on the latest 17.11.0 Preview 7.0( 8.0.80 & 8.0.71 & 8.0.3).

MartyIX commented 3 months ago

(@beeradmoore i think that the previous version of VS 2022 works ok on MAUI source code. The current version (released yesterday) had issues in its preview versions, i haven't had a chance to test the new release yet though.)

beeradmoore commented 3 months ago

@MartyIX , I can confirm, Visual Studio 2022 v17.11.0 will crashes when opening Microsoft.Maui.sln. Rolling back to v17.10.5 allows it to open. I am unable to build build Controls.Sample.Sandbox. Errors about not being able to build for macOS.

I tried Microsoft.Maui-dev.sln (I am not sure what one I am meant to open), but Visual Studio never loads the dropdown for me to select the sandbox project. It is not reported as unresponsive by Windows, it just doesn't load.

With all of that, I won't be albe to look into this from my end unfortunatly.

MartyIX commented 3 months ago

I would make sure to build tasks first: https://github.com/dotnet/maui/blob/main/.github/DEVELOPMENT.md#building-the-build-tasks and then open this solution https://github.com/dotnet/maui/blob/main/.github/DEVELOPMENT.md#windows-1

beeradmoore commented 3 months ago

Thanks heaps for that info, I'm in!

I can see the 2 places I messed up.

1 - I missed the development guide dispite looking for it. I think I skipped over the link thinking development guide was style guide. 2 - I have never used a .slnf. On my computer the icon is a blank file icon not a VS icon. I assumed they were just metadata/config files.

When I tried to run it I get the exception saying

.NET MAUI Maps is currently not implemented for Windows. For more information, please see: https://aka.ms/maui-maps-no-windows

I was able to get around that by removing .UseMauiMaps().

beeradmoore commented 3 months ago

I can confirm that adding e.Handled = true; to the bottom if HandlePan method in GesturePlatformManager.Windows.cs does prevent the issue happening. I am unsure what else may happen as a result and if there is a better way to handle that.

https://github.com/user-attachments/assets/a6ae3b38-4913-4aa3-8896-4431cd1b6d33

If that is the fix then I think HandleSwipe and HandlePinch may also need it. I don't know how to perform a pinch on Windows though so I would be unable to test that. (EDIT: I have an ROG Ally, if the system is working as intended I could test all of those)

I am also thinking that HandleSwipe, HandlePinch, and HandlePan should internallly have a

if (e.Handled == true)
    return;

as they are all called within OnManipulationDelta one after the other. Without adding that it could be possible to have Pinch and Pan gesutres fire at once, assuming Windows App SDK would allow that (I would hope it does not). If it did allow that then order of operations would also need to be consdered to make sure a the ideal method is called first.

MartyIX commented 3 months ago

You can create a PR. It's often the best way to get feedback from the MAUI team. :)

beeradmoore commented 3 months ago

Sounds good to me. I should get time to work on that in the next few days.