Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin.Forms - Global tapped event on application level

How can I intercept a tapped/clicked event on application level in an Xamarin.Forms app?

I tried on the MainPage to use something like

    <Grid.GestureRecognizers>
        <TapGestureRecognizer Command="{Binding TappedCommand}" Tapped="TapGestureRecognizer_OnTapped"></TapGestureRecognizer>
    </Grid.GestureRecognizers>

but it works only if I tap empty areas, touching a button doesn't fire the events.

Additionally I often navigate by changing the MainPage, so I would have to add such recognizer even if it worked.

I want to handle any touch/tap/click event in my app globally, is it possible in Xamarin.Forms?

like image 666
alek kowalczyk Avatar asked Dec 19 '16 04:12

alek kowalczyk


2 Answers

This can be easily setup within the platform-specific apps and then use a Xamarin.Forms dependency service to subscribe/unsubscribe to the events.

What you capture within those events is up to your needs, in this example I am just capturing and eventing the x/y values.

A generic EventArgs Class and DP Interface:

public class TouchEventArgs<T> : EventArgs
{
    public T EventData { get; private set; }

    public TouchEventArgs(T EventData)
    {
        this.EventData = EventData;
    }
}

public interface IGlobalTouch
{
    void Subscribe(EventHandler handler);
    void Unsubscribe(EventHandler handler);
}

Add the following to the MainActivity of your Xamarin.Android application:

public EventHandler globalTouchHandler;
public override bool DispatchTouchEvent(MotionEvent ev)
{
    globalTouchHandler?.Invoke(null, new TouchEventArgs<Point>(new Point(ev.GetX(), ev.GetY())));
    return base.DispatchTouchEvent(ev);
}

Android Dependency Implementation:

public class GlobalTouch : IGlobalTouch
{
    public GlobalTouch() {}

    public void Subscribe(EventHandler handler)
    {
        (Forms.Context as MainActivity).globalTouchHandler += handler;
    }

    public void Unsubscribe(EventHandler handler)
    {
        (Forms.Context as MainActivity).globalTouchHandler -= handler;
    }
}

Usage in your Xamarin.Forms project:

DependencyService.Get<IGlobalTouch>().Subscribe((sender, e) =>
{
    var point = (e as TouchEventArgs<Point>).EventData;
    System.Diagnostics.Debug.WriteLine($"{point.X}:{point.Y}");
});

Note: You should be assigning a delegate so can unsubscribe...

Output:

307.628997802734:365.563842773438
309.280151367188:365.197265625
311.883605957031:365.390991210938
312.694641113281:380.148590087891
308.030578613281:387.823364257813
291.513244628906:396.339416503906
286.220489501953:396.339416503906
282.100006103516:396.339416503906

The same technique can be used for iOS, there are TouchesBegan, TouchesEnded, TouchesMoved and TouchesCancelled that you can attach to depending upon your needs....

like image 68
SushiHangover Avatar answered Nov 03 '22 04:11

SushiHangover


Using SushiHangover resolution, for iOS, it would be something like this:

In AppDelegate.cs implement IUIGestureRecognizerDelegate

public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUIGestureRecognizerDelegate
{

Inside AppDelegate.cs class, in FinishedLaunching method, add this:

Xamarin.Forms.DependencyService.Register<GlobalTouch>();
bool ret = base.FinishedLaunching(app, options);
if (ret)
{
    UITapGestureRecognizer tap = new UITapGestureRecognizer(Self, new ObjCRuntime.Selector("gestureRecognizer:shouldReceiveTouch:"));
    tap.Delegate = (IUIGestureRecognizerDelegate)Self;
    app.KeyWindow.AddGestureRecognizer(tap);
}
return ret;

Add this method in AppDelegate.cs:

[Export("gestureRecognizer:shouldReceiveTouch:")]
public bool ShouldReceiveTouch(UIGestureRecognizer gestureRecognizer, UITouch touch)
{
    Xamarin.Forms.DependencyService.Get<IGlobalTouch>().TapScreen();
    return false;
}

Add this into GlobalTouch:

EventHandler globalTouchHandler;

public void TapScreen()
{
    globalTouchHandler?.Invoke(this, null);
}

Add this into IGlobalTouch:

void TapScreen();
like image 2
Osiris Pujols Avatar answered Nov 03 '22 04:11

Osiris Pujols