maui icon indicating copy to clipboard operation
maui copied to clipboard

TapGestureRecognizer not working on a Frame in a grid on iOS or Mac

Open JohnHDev opened this issue 2 years ago • 9 comments

Description

TapGestureRecognizer not working on a Frame in a grid.

Steps to Reproduce

Try the following code:

var frame = new Frame(); frame.GestureRecognizers.Add(new TapGestureRecognizer() { Command = new Command(() => Debug.WriteLine("dfg")) });

Add the frame to a grid, run iOS or Mac and attempt to tap/click on it. [EDIT], It might be more complex, it needs to be in a scrollview that spans all columns in the grid and in a custom layout control. Will put together an example when I get time. [EDIT 2] Ok, nothing to do with my custom control. A grid, containing scrollview that spans columns, containing a frame that has a tap gesture recogniser added will show the problem.

This is using VSforMac, so the .net version is 6.0.301.

Version with bug

Unknown/Other (please specify)

Last version that worked well

Unknown/Other

Affected platforms

iOS, macOS

Affected platform versions

iOS 15

Did you find any workaround?

Nope

Relevant log output

No response

JohnHDev avatar Jun 25 '22 18:06 JohnHDev

Hi @JohnHDev. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

ghost avatar Jun 27 '22 20:06 ghost

Hi, @JohnHDev - thanks for opening this issue! Looking forward to investigating further once you share the example with us

rachelkang avatar Jun 27 '22 20:06 rachelkang

@rachelkang apologies for the delay, here you go. In the page constructor add the following code. You will see that the tap gesture on the frames don't work at all. But also, I found that setting the page content itself to a frame, the tap gesture doesn't work either. So it could be as simple as that to replicate:

            var grid = new Grid();
            grid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star));
            grid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star));
            grid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star));
            grid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star));
            grid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star));

            grid.RowDefinitions.Add(new RowDefinition(GridLength.Star));
            grid.RowDefinitions.Add(new RowDefinition(GridLength.Star));
            grid.RowDefinitions.Add(new RowDefinition(GridLength.Star));
            grid.RowDefinitions.Add(new RowDefinition(GridLength.Star));
            grid.RowDefinitions.Add(new RowDefinition(GridLength.Star));

            var scrollView = new ScrollView()
            {
                BackgroundColor = Colors.Blue
            };
            Grid.SetRow(scrollView, 0);
            Grid.SetColumn(scrollView, 0);
            Grid.SetColumnSpan(scrollView, 5);
            grid.Children.Add(scrollView);

            var frame1 = new Frame
            {
                BackgroundColor = Colors.Red
            };

            frame1.GestureRecognizers.Add(new TapGestureRecognizer() { Command = new Command(() => Debug.WriteLine("frame1")) });

            scrollView.Content = frame1;

            var frame2 = new Frame
            {
                BackgroundColor = Colors.Green
            };
            frame2.GestureRecognizers.Add(new TapGestureRecognizer() { Command = new Command(() => Debug.WriteLine("frame2")) });
            Grid.SetRow(frame2, 1);
            Grid.SetColumn(frame2, 0);
            Grid.SetColumnSpan(frame2, 5);
            grid.Children.Add(frame2);
            
            Content = grid;

Let me know how you get on!

Thanks John

JohnHDev avatar Jul 01 '22 20:07 JohnHDev

Further info, swapping Frame for Border, the tap gestures work but you can't 'see' the border view. [EDIT] Ok to see the background of the border view you must add a StrokeShape, which covers the shape of the border and has nothing to do with the background colour. You might want to take a look at that as well.

JohnHDev avatar Jul 01 '22 20:07 JohnHDev

verified not working on IOS. repro project: MauiApp5.zip

kristinx0211 avatar Jul 12 '22 06:07 kristinx0211

Verified not working on Windows10. I have a grid, column 0 is npx column 1 is *. Adding a BoxView into column 0 and a TapGestureRecognizer on that boxview works as expected. Adding a BoxView into column 1 and a TapGestureRecognizer on that boxview does not get recognized. Spanning the first BoxView across column 0 and one only is clickable in column1. Below is a code example of this anonymized out of our code base.

Edit: When I change the * in the ColumnDefinitions to be some absolute number of px it works perfectly as expected. (Auto works too but doesn't give me the layout behavior of filling the rest of what's available.) So It must have to do with EventHandlers on grid cells declared using *.

Hope this helps!

<Grid RowDefinitions="50"
      ColumnDefinitions="50, *">
    <BoxView Grid.Row="0"
             Grid.Column="0"
             HorizontalOptions="Fill"
             VerticalOptions="Fill"
             Color="Green">
        <BoxView.GestureRecognizers>
            <TapGestureRecognizer Command="{Binding ThisOneClicks}" />
        </BoxView.GestureRecognizers>
    </BoxView>
    <BoxView Grid.Row="0"
             Grid.Column="1"
             HorizontalOptions="Fill"
             VerticalOptions="Fill"
             Color="Yellow">
        <BoxView.GestureRecognizers>
            <TapGestureRecognizer Command="{Binding ThisOneDoesntClick}" />
        </BoxView.GestureRecognizers>
    </BoxView>
</Grid>

TimVanDyke avatar Sep 12 '22 16:09 TimVanDyke

We have run into what may be a related issue. If a Frame element with a border is added to the screen in Android or iOS, the frame is rendered and the TapGestureRecognizer works. However, if a Frame element with the same characteristics is added to a ListView, the frame's border is drawn and taps work in Android, but on iOS the frame's border is not drawn and the frame does not respond to taps.

A demo project with these issues can be found here: https://github.com/awalker-dsg/MauiTestApp4_Frame

We saw these results on a Samsung S10e running Android 12 and on the iOS simulator with iPhone13 Pro Max iOS 15.4. This image in the same project repo shows a side-by-side comparison of the Android and iOS screens.

awalker-dsg avatar Sep 19 '22 17:09 awalker-dsg

Hello. I'm facing the issue on Android device when Frame is inside a ListView's ItemTemplate, the tap event doesn't get called when item is tapped.

SunshineSpring666 avatar Nov 03 '22 03:11 SunshineSpring666

@jsuarezruiz when might this get picked up? It is disheartening to see so many simple issues not being resolved in a timely manner.

JohnHDev avatar Nov 26 '22 07:11 JohnHDev

So this is the thing that is making it not work: https://github.com/dotnet/maui/blob/193924bc4de53ba8270d0c6acf4eba7c9dadcb6d/src/Controls/src/Core/Compatibility/Handlers/iOS/FrameRenderer.cs#L203-L212

This is basically telling the Frame that the only things that count are the taps on child views. You can also test this by adding an empty Grid to the Frame. Now all the taps work.

This was added years ago in Xamarin.Forms: https://github.com/xamarin/Xamarin.Forms/blame/adf65d8b893f410cad4b17202dd8930879794914/Xamarin.Forms.Platform.iOS/Renderers/FrameRenderer.cs#L188

Did it ever work? Should it work? It was added in this commit by @PureWeen: https://github.com/xamarin/Xamarin.Forms/commit/9287c69c3d0696947cf6ab4499e6e3a80e8879aa

The only comment on the commit/PR is:

Use PointInside to forward touch events

Doesn't the UIView automatically forward touch events? Like, how does Border work as it uses the same base ContentView?

mattleibow avatar Dec 13 '22 01:12 mattleibow

@awalker-dsg I moved your issue to https://github.com/dotnet/maui/issues/12044

I think your issue is a layout one where the frame is not rendered at all - and neither is the grid. The fact the label is there is amazing. Switching to a Border or a CollectionView seems to make it work again.

@SunshineSpring666 this may be you too. Just check if the frame is even rendered.

mattleibow avatar Dec 13 '22 02:12 mattleibow

@PureWeen is this Frame not having gestures working when there is no child items a "feature" or "compatibility feature" of Frame? As far as I can tell, this is how Xamarin.Forms worked.

Adding a child or switching to Border makes it work again. How do we make a call on this issue?

mattleibow avatar Dec 13 '22 02:12 mattleibow

@mattleibow, re your comment, "As far as I can tell, this is how Xamarin.Forms worked." We discovered this while migrating our code from Xamarin to MAUI. The Xamarin version of our app uses Frame in this way, and it does work on iOS as well as on Android.

Following up on your earlier comment, "Switching to a Border or a CollectionView seems to make it work again", I modified the test code from my original post to use CollectionView instead of ListView. When I ran it on an iPhone 7 with iOS 15.6.1 and an emulated iPhone 14 with iOS 16.0, the app crashed on startup. I then restored it to use ListView and the app ran as before -- i.e. the Frame ignores clicks, but the app didn't crash on startup. These tests were done using VS 17.4.2.

awalker-dsg avatar Dec 13 '22 11:12 awalker-dsg

@awalker-dsg I was testing with the internal bits of 17.4.3 and maui 7.0.52. Both of these just shipped a few hours ago.

Maybe you have a more complex CollectionView so that may still have a crash. However, you can use a Border.

I will re-investigate this and see if I can try figure out why Xamarin.Forms worked and this does not as it is the same code...

mattleibow avatar Dec 13 '22 23:12 mattleibow

Just tested on iOS with Xamarin.Forms and indeed the touches work. Now the trick is to figure out why it is not working in MAUI...

mattleibow avatar Dec 14 '22 00:12 mattleibow

@mattleibow, I updated to VS 17.4.3 on my PC to see if that addressed the crash described in my previous post. That also forced me to update Xcode from 14.0.1 to 14.2 on our Mac.

The bad news is that our test app still crashes on iOS if the ListView is replaced with a CollectionView.

However, there is good news. Per your earlier suggestion, I changed the Frame to a Border, and now our custom button DOES respond to click events when the compound control is in a ListView.

Also, once I discovered that setting the Border control attribute StrokeShape="RoundRectangle 10" was equivalent to the Frame control's CornerRadius="10", the resulting control looks the same as it did on Xamarin using Frame. So, Border seems to be a viable workaround for Frame for the scenario described in my original post.

Many thanks for your help.

awalker-dsg avatar Dec 14 '22 17:12 awalker-dsg