Xamarin.Forms -应用程序级别上的全局tapped事件

c9x0cxw0  于 2022-12-07  发布在  其他
关注(0)|答案(3)|浏览(146)

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?

gxwragnw

gxwragnw1#

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....

06odsfpq

06odsfpq2#

使用SushiHangover分辨率,对于iOS,它将是这样的:

    • 在AppDelegate.cs中实现IUI手势识别器委托**
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUIGestureRecognizerDelegate
{
    • 在AppDelegate.cs类内的FinishedLaunching方法中添加以下内容:**
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;
    • 在AppDelegate.cs中添加此方法:**
[Export("gestureRecognizer:shouldReceiveTouch:")]
public bool ShouldReceiveTouch(UIGestureRecognizer gestureRecognizer, UITouch touch)
{
    Xamarin.Forms.DependencyService.Get<IGlobalTouch>().TapScreen();
    return false;
}
    • 将此添加到GlobalTouch:**
EventHandler globalTouchHandler;

public void TapScreen()
{
    globalTouchHandler?.Invoke(this, null);
}
    • 将此添加到IGlobalTouch:**
void TapScreen();
cyej8jka

cyej8jka3#

SushiHangover解决方案的iOS部分:

    • 触摸坐标识别器. cs:**
public class TouchCoordinatesRecognizer : UIGestureRecognizer
{
    public override void TouchesBegan(NSSet touches, UIEvent evt)
    {
        base.TouchesBegan(touches, evt);
        SendCoords(touches);
    }

    public override void TouchesMoved(NSSet touches, UIEvent evt)
    {
        base.TouchesMoved(touches, evt);
        SendCoords(touches);
    }

    public override void TouchesEnded(NSSet touches, UIEvent evt)
    {
        base.TouchesEnded(touches, evt);
        SendCoords(touches);
    }

    public override void TouchesCancelled(NSSet touches, UIEvent evt)
    {
        base.TouchesCancelled(touches, evt);
        SendCoords(touches);
    }

    void SendCoords(NSSet touches)
    {
        foreach (UITouch touch in touches.Cast<UITouch>())
        {
            var window = UIApplication.SharedApplication.KeyWindow;
            var vc = window.RootViewController;

            AppDelegate.Current.globalTouchHandler?.Invoke(null,
                new TouchEventArgs<Point>(
                    new Point(
                        touch.LocationInView(vc.View).X,
                        touch.LocationInView(vc.View).Y)));
            return;
        }
    }
}
    • 应用代理. cs:**
public static AppDelegate Current { get; private set; }

public EventHandler globalTouchHandler;

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Current = this;

    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());
    var res = base.FinishedLaunching(app, options);
    app.KeyWindow.AddGestureRecognizer(new TouchCoordinatesRecognizer()); // <--
    return res;
}
    • 全球触摸. cs:**
public class GlobalTouch : IGlobalTouch
{
    public void Subscribe(EventHandler handler) => AppDelegate.Current.globalTouchHandler += handler;

    public void Unsubscribe(EventHandler handler) => AppDelegate.Current.globalTouchHandler -= handler;
}

不要忘记在android和iOS部件的必要位置将x和y坐标除以DeviceDisplay. MainDisplayInfo. Density

相关问题