Xamarin.forms: [Android] TapGestureRecognizer do not fire the tapped event on "normal" tap/click.

Created on 21 Jan 2018  Â·  13Comments  Â·  Source: xamarin/Xamarin.Forms

Bug report best practices: https://github.com/xamarin/Xamarin.Forms/wiki/Submitting-Issues

Description

On Android the TapGestureRecognizer do not fire the tapped event on "normal" tap/click.
The finger is always sliding a little over the screen when you are tapping it, the TapGestureRecognizer have a very small "sliding"-tolerance. This makes the TapGestureRecognizer to only fire a tapped event if you click much more carefully than on a normal button.

Steps to Reproduce

  1. Device: Samsung SM-T580 (Galaxy Tab A)
  2. OS: Android 7.0
  3. Enable developer options: Show Touches and Show Pointer location.

Create any basic Xamarin.Forms project and apply a TapGestureRecognizer to any basic element (Text, StackLayout etc.)

Expected Behavior

The tapped event should be fired even if a little sliding occurs, just like normal buttons do.

Actual Behavior

No event is fired when a little sliding occurs, like it does on buttons.

Basic Information

  • Version with issue: Xamarin.Forms 2.5.0.122203
  • Platform Target Frameworks:

    • Android: 7.0

  • Android Support Library Version: Xamarin.Android.Support.v4 (26.1.0.1), Xamarin.Android.Support.v7.AppCompat (26.1.0.1)
  • Affected Devices: Samsung SM-T580 (Galaxy Tab A)

Screenshots

Reproduction Link

gestures 🖖 3 help wanted high impact Android proposal-accepted enhancement ➕ up-for-grabs

Most helpful comment

I made this class to work around the problem:

public class MicroSwipeOrTapListener
{
        private readonly double _microSwipeMaxLength;
        public event EventHandler MicroSwipeOrTapHasHappened;
        private double _translatedX, _translatedY;

        public MicroSwipeOrTapListener(View view)
        {
            // If swipe was less than a 20th of the screen, we consider it a tap
            _microSwipeMaxLength = App.DisplayScreenWidth / 20d;
            // Only listen for micro swipes on android
            if (Device.RuntimePlatform == Device.Android)
            {
                var panRecognizer = new PanGestureRecognizer();
                panRecognizer.PanUpdated += OnPanUpdated;
                view.GestureRecognizers.Add(panRecognizer);
            }
            // Listen for taps on both platforms(on ios, this includes micro swipes)
            var tapRecognizer = new TapGestureRecognizer();
            tapRecognizer.Tapped += OnTapped;
            view.GestureRecognizers.Add(tapRecognizer);
        }

        private void OnTapped(object sender, EventArgs e)
        {
            MicroSwipeOrTapHasHappened?.Invoke(sender, e);
        }

        void OnPanUpdated(object sender, PanUpdatedEventArgs e)
        {
            switch (e.StatusType)
            {
                case GestureStatus.Running:
                    _translatedX = e.TotalX;
                    _translatedY = e.TotalY;
                    break;

                case GestureStatus.Completed:
                    // If all movements(regardless of direction) was less than treshold: fire microswipe event
                    if (Math.Max(Math.Abs(_translatedX), Math.Abs(_translatedY)) <= _microSwipeMaxLength)
                    {
                        MicroSwipeOrTapHasHappened?.Invoke(this, e);
                    }
                    break;
                case GestureStatus.Started:
                    break;
                case GestureStatus.Canceled:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }            
        }
}

All 13 comments

When will Xamarin Forms support the tap event on Android ? It's a pretty basic feature for a mobile development framework.

App14.zip

Reproduction of the behavior which is as described.

A button will recognize any gesture as a click regardless of how much sliding occurs so long as the sliding starts and stops within the button.

A label with a tap gesture recognizer will register a tap with only a few pixels of sliding tolerance.

@jassmith says we should add a knob to allow users to control sliding tolerance for the tap gesture recognizer. I doubt we'll go as far as making the tap gesture recognizer logic match that of a button.

I am glad to hear that this is being dealt with. A setting for the sliding tolerance would be appreciated, right now i am getting allot of complaints about people not being able to use our app because the users think they cant click on the items.

@mathias3d which event fires instead of the tap? we have the same problem. I'd say it happens about every 5th time for me that the the tap is no firing.

Possibly releated: #3173

Also bitten by this. Getting complaints from users(only on android).

I will probably have to make my own "ButtonTapGestureRecognizer"(or perhaps "TapGestureRecognizerThatWorksAsExpectedOnAndroid")...

This definitely works different on ios and android, and should be considered a bug IMHO.

I made this class to work around the problem:

public class MicroSwipeOrTapListener
{
        private readonly double _microSwipeMaxLength;
        public event EventHandler MicroSwipeOrTapHasHappened;
        private double _translatedX, _translatedY;

        public MicroSwipeOrTapListener(View view)
        {
            // If swipe was less than a 20th of the screen, we consider it a tap
            _microSwipeMaxLength = App.DisplayScreenWidth / 20d;
            // Only listen for micro swipes on android
            if (Device.RuntimePlatform == Device.Android)
            {
                var panRecognizer = new PanGestureRecognizer();
                panRecognizer.PanUpdated += OnPanUpdated;
                view.GestureRecognizers.Add(panRecognizer);
            }
            // Listen for taps on both platforms(on ios, this includes micro swipes)
            var tapRecognizer = new TapGestureRecognizer();
            tapRecognizer.Tapped += OnTapped;
            view.GestureRecognizers.Add(tapRecognizer);
        }

        private void OnTapped(object sender, EventArgs e)
        {
            MicroSwipeOrTapHasHappened?.Invoke(sender, e);
        }

        void OnPanUpdated(object sender, PanUpdatedEventArgs e)
        {
            switch (e.StatusType)
            {
                case GestureStatus.Running:
                    _translatedX = e.TotalX;
                    _translatedY = e.TotalY;
                    break;

                case GestureStatus.Completed:
                    // If all movements(regardless of direction) was less than treshold: fire microswipe event
                    if (Math.Max(Math.Abs(_translatedX), Math.Abs(_translatedY)) <= _microSwipeMaxLength)
                    {
                        MicroSwipeOrTapHasHappened?.Invoke(this, e);
                    }
                    break;
                case GestureStatus.Started:
                    break;
                case GestureStatus.Canceled:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }            
        }
}

@samhouts You moved the issue to "Needs Specification". What exactly would you like to have specified?

This is huge, since we use TapGestureRecognizer for all the events. With a small drag, the event will simply not fire.

Also, not sure if need to open a new issue but: Pressed and Released Events in TapGesture, is it possible?

Any news about this?

Same issue here. TapGestureRecognizer is needed lots of time on customized pages. Just a little move during tap and the gesture is not fired! May you can provide a property " double TapSlideSensitivity" similar to NumberOfTapsRequired where it is possible to define how many x & y coordinates are tolerated between Down and Up event to fire a TapGesture finally.

Was this page helpful?
0 / 5 - 0 ratings