Forum Xamarin.Forms

TapGestureRecognizer not restricting multiple rapid clicks?!

betcssbetcss Member ✭✭
edited February 20 in Xamarin.Forms

Currently with the NumberOfTapsRequired = 1 and tapping rapidly I get at least 3 pages opened in succession.

The question is how should I prevent multiple rapid clicks e.g. on an entry View - (Focused View gives the same obviously)?

Should I refer to the Lock mechanism ?

Thanks in advance.

Best Answer

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai

    Try to use lock statement to detect if the view has been tapped.

    bool IsClicked = false;
    object _lock= new object();
    private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
    {
        lock (_lock)
        {
    
            if (IsClicked)
                return;
            else
                IsClicked = true;
    
        }
        //do the work
    
        IsClicked = false;
    }
    
  • betcssbetcss Member ✭✭

    @Jarvan

    Tried it already, it doesn't work for the rapid multi-click on an entry, at least; still opens > 1 page.

  • betcssbetcss Member ✭✭
    edited February 21

    I've done something like this:

    Page page = new GivenPage();
    
    private void OnEntryChange(object sender, EventArgs e)
    {
        var stack= page.Navigation.NavigationStack;
    
            if(stack.Count > 0)
            {
                if(stack[stack.Count - 1].GetType() != typeof(GivenPage))
                {
                       Navigation.PushAsync(new GivenPage());
                }
                return;
             }
             else
                  Navigation.PushAsync(page);
    }
    

    I don't think it's correct though. I'm confused about the parent page part...

  • JohnHardmanJohnHardman GBUniversity mod
    edited February 21

    @betcss

    You don't need that page variable at all. Your OnEntryChange is presumably within the context of a ContentPage, so you can just use Navigation (or this.Navigation) rather than page.Navigation.

    I've never needed the if(stack.Count > 0) test either, as there'd already be at least one page on the NavigationStack when called from an event handler in an existing page.

  • betcssbetcss Member ✭✭
    edited February 21

    @John You're right. Can you tell me why the solution with lock statement can't work and how can I improve this even further e.g. make it faster?

    Best regards.

  • JohnHardmanJohnHardman GBUniversity mod
    edited February 21

    @betcss said:
    @John You're right. Can you tell me why the solution with lock statement can't work and how can I improve this even further e.g. make it faster?

    The "solution" with lock statements doesn't work because the "//do the work" bit would be asynchronous. Call PushAsync there and the PushAsync returns before the new page is actually displayed. The current page remains responsive for a brief period before the new one appears. Because the current page is still responsive for that brief period, the user can (accidentally or intentionally) tap the View again. That results in TapGestureRecognizer_Tapped being called again. Once the awaited PushAsync has returned, IsClicked is set to false. If timing of things happening is such that IsClicked is false when TapGestureRecognizer_Tapped is called again, another page will be pushed.

    Using the test for the type of page at the top of the NavigationStack avoids this problem.

  • betcssbetcss Member ✭✭

    Last question: How could you make this even faster ?

  • JohnHardmanJohnHardman GBUniversity mod

    @betcss said:
    Last question: How could you make this even faster ?

    You cannot , or put another way, if you find a way, let me know :-)

Sign In or Register to comment.