0

I have equipped a Shape object in Xamarin Forms with a Tap Gesture Recognizer to react on tap events, however, it does not work. I have tried with Path, Polygone and Polyline objects. Wrapping the shape in a Frame works - but only if I tap on the area outside the shape. That's not what I want. Wrapping in a ContentView shows also no effect. Maybe that's all because shapes are still experimental in XF (you must set the Shapes_Experimental flag in the App class to use shapes)?

Here's a simple example working for the box but not for the triangle, tested on iOS:

public class TestPage : ContentPage
    {
        public TestPage()
        {
            var tgr = new TapGestureRecognizer();
            tgr.Tapped += async (s, e) => {
                await DisplayAlert("Info", "Tapped", "OK");
            };

            Polygon triangle = new Polygon
            {
                Points = new PointCollection(),
                Fill = Brush.Blue,
            };
            triangle.Points.Add(new Point(0, 0));
            triangle.Points.Add(new Point(100, 0));
            triangle.Points.Add(new Point(50, 50));

            triangle.GestureRecognizers.Add(tgr);

            BoxView box = new BoxView
            {
                HeightRequest = 50,
                Color = Color.Red
            };

            box.GestureRecognizers.Add(tgr);

            Content = new StackLayout
            {
                Children = { triangle, box },
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center
            };
        }
    }

Does anyone knows a solution or workaround how to make gestures work with shapes?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Frank Zielen
  • 67
  • 10
  • I think it's a problem of Xamarin.forms and I found a relevant [issue](https://github.com/xamarin/Xamarin.Forms/issues/10623) here. I checked the [renderer and native control class](https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/renderers#views) of Polygon and I find it is a CALayer in iOS. A CALayer won't response to a TapGesture and I think this is probably the cause. – nevermore Oct 09 '20 at 02:55
  • I thought that Shape class is inherited from View class and so tap gesture events would be included automatically - independent from the fact that Polygon is CALayer in iOS. But I am not so familiar with iOS framework to understand this to the full. – Frank Zielen Oct 09 '20 at 06:42

2 Answers2

2

This is a bug on the iOS implementation of Polygon/Polyline.

For a workaround, wrap the Shape in another view and set InputTransparent on the Polygon to true. When the Shape is in another element, the Shape is still on top and still gets the tap from the user, so you have to pass the tap down to the wrapping container, whether a Frame or ContentView. E.g.:

    var tgr = new TapGestureRecognizer();
    tgr.Tapped += async (s, e) => {
        await DisplayAlert("Info", "Tapped", "OK");
    };

    Polygon triangle = new Polygon
    {
        Points = new PointCollection(),
        Fill = Brush.Blue,
    };
    triangle.Points.Add(new Point(0, 0));
    triangle.Points.Add(new Point(100, 0));
    triangle.Points.Add(new Point(50, 50));
    triangle.InputTransparent = true;  // <------------------------set InputTransparent to True

    var frame= new Frame(); 
    frame.Content = triangle; // <--------------------- add to Frame
 
    frame.GestureRecognizers.Add(tgr); // <-----------TapGestureRecognizer on Frame

    Content = new StackLayout
    {
        Children = { frame }, // <------------------------ add Frame to view heirarchy
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center
    };

UPDATE: If you need to only have the tap work when the actual triangle is being tapped, then you will need to do that in platform specific renderers and use the iOS/Android/UWP SDK APIs to do hit tests.

Since a Xamarin.Forms Shape is a View, and a View is rectangular, adding a TapGestureRecognizer to a Shape will trigger the Tap for the View box, not for the shape inside of it. This is what happens on Android when the Shape is not wrapped in a Frame, etc.

There is a discussion of getting the tap coordinates in Xamarin.Forms on the Xamarin Forums: https://forums.xamarin.com/discussion/17767/touch-coordinates-in-tapgesturerecognizer

Docs on handling touch events in Xamarin.iOS: https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/touch/ Docs on handling touch events in Xamarin.Android: https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/touch/touch-in-android Docs on handling touch events in UWP: https://learn.microsoft.com/en-us/windows/uwp/design/input/touch-interactions

Alternately you could use SkiaSharp for your shapes: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/touch

And there is a paid plugin, noted in the Xamarin Forums discussion linked above (I can't vouch for it) that claims to enable determining where the touch occurred: https://www.mrgestures.com/

jgoldberger - MSFT
  • 5,978
  • 2
  • 20
  • 44
  • Thx @jgoldberger! The **InputTransparent** property was the missing link to make wrapping in a **Frame** or **ContentView** work. However, the workaround is still not perfect (for my application) because **Frame** and **ContentView** have rectangular shapes. E.g. for the triangle I can now tap on the area outside the triangle but inside the wrapping object to fire the event. Is there a possibility to wrap seamlessly around the shape? – Frank Zielen Oct 20 '20 at 12:09
  • The Shape, since it derives from VIew, is also rectangular so you will have the same thing even without the wrapper. Try it on Android, where you do not need to wrap the Shape, and you will see the same. I will add some more info to my answer above for alternatives. – jgoldberger - MSFT Oct 20 '20 at 19:28
  • Thx @jgoldberger-MSFT That helps me to understand the behaviour! – Frank Zielen Oct 20 '20 at 20:12
0

Why dont you wrap a Frame around your Triangle and add the TabGestureRecognizer there?

Daniel Klauser
  • 384
  • 3
  • 16
  • I have already wrapped the Triangle in a Frame but this works only in the area of the frame outside the triangle, i.e. if I tap the triangle the event is not fired, however, if I tap the complement area (frame minus triangle) it works. But this is not what I am looking for. Wrapping in a ContentView does also not work for me. – Frank Zielen Oct 09 '20 at 06:33