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?
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.
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);
}
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);
}
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;
}
}
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...
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....
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With