You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在SKCanvasView上同时使用Xamarin手势识别器与OnTouch方法的问题

解决SKCanvasView中OnTouch与Xamarin GestureRecognizers共存的问题

你遇到的核心矛盾是:Android平台下为了让SKTouchAction.Pressed后能触发Moved事件,必须设置e.Handled = true,但这会阻断Xamarin自带GestureRecognizers的事件传递。以下是几种可行的解决方案:

方案一:Android平台自定义Renderer控制事件分发

针对Android平台单独处理触摸事件的传递逻辑,让SKCanvasView的OnTouch和GestureRecognizers都能处理事件:

  1. 在Android项目中创建自定义Renderer:
[assembly: ExportRenderer(typeof(GestureContainer), typeof(GestureContainerRenderer))]
namespace YourAppNamespace.Droid.Renderers
{
    public class GestureContainerRenderer : SKCanvasViewRenderer
    {
        public GestureContainerRenderer(Context context) : base(context)
        {
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            // 先执行SKCanvasView的触摸处理逻辑
            base.OnTouchEvent(e);
            
            // 将事件手动传递给GestureRecognizers
            if (Element is GestureContainer gestureView)
            {
                foreach (var recognizer in gestureView.GestureRecognizers)
                {
                    if (recognizer is IGestureRecognizer androidRecognizer)
                    {
                        androidRecognizer.OnTouch(gestureView, e);
                    }
                }
            }

            return true;
        }
    }
}
  1. 修改GestureContainer中的OnTouch方法,根据平台设置e.Handled:
protected override void OnTouch(SKTouchEventArgs e)
{ 
    switch (e.ActionType)
    {
         case SKTouchAction.Moved:
             // 你的移动逻辑代码
             break;
         case SKTouchAction.Pressed:
             // 你的按下逻辑代码
             break;
    }

    // Android平台设置为true保证Moved事件触发,其他平台保持false让GestureRecognizers正常工作
    e.Handled = Device.RuntimePlatform == Device.Android;
    InvalidateSurface();
}

方案二:完全基于SkiaSharp触摸事件实现手势逻辑

放弃Xamarin自带的GestureRecognizers,直接在OnTouch中处理双击、捏合等手势逻辑,从根源避免冲突:

public abstract class GestureContainer : SKCanvasView, IViewportable
{
    private DateTime _lastTapTime;
    private float _initialPinchDistance;
    private bool _isPinching;

    public GestureContainer()
    {
        // 无需添加Xamarin GestureRecognizers
    }

    private void TapGesture_DoubleTapped(object sender, EventArgs e)
    {
        // 双击逻辑
    }

    public void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
    {
        // 捏合逻辑
    }

    protected override void OnTouch(SKTouchEventArgs e)
    { 
        switch (e.ActionType)
        {
             case SKTouchAction.Pressed:
                 // 处理双击
                 var currentTime = DateTime.Now;
                 if ((currentTime - _lastTapTime).TotalMilliseconds < 300)
                 {
                     TapGesture_DoubleTapped(this, EventArgs.Empty);
                 }
                 _lastTapTime = currentTime;

                 // 处理捏合开始
                 if (e.InTouchPoints.Count >= 2)
                 {
                     var point1 = e.InTouchPoints[0].Location;
                     var point2 = e.InTouchPoints[1].Location;
                     _initialPinchDistance = SKPoint.Distance(point1, point2);
                     _isPinching = true;
                 }
                 break;
             case SKTouchAction.Moved:
                 // 你的移动逻辑

                 // 处理捏合更新
                 if (_isPinching && e.InTouchPoints.Count >= 2)
                 {
                     var currentDistance = SKPoint.Distance(e.InTouchPoints[0].Location, e.InTouchPoints[1].Location);
                     var scaleFactor = currentDistance / _initialPinchDistance;
                     OnPinchUpdated(this, new PinchGestureUpdatedEventArgs(GestureStatus.Running, scaleFactor, e.Location));
                     _initialPinchDistance = currentDistance;
                 }
                 break;
             case SKTouchAction.Released:
                 _isPinching = false;
                 break;
        }

        e.Handled = true; // 保证Android上Moved事件正常触发
        InvalidateSurface();
    }
}

方案三:自定义GestureRecognizer允许同时识别

通过自定义GestureRecognizer,允许它和SKCanvasView的触摸事件同时处理,不过这个方法在Android平台的兼容性不如前两种:

public class CustomDoubleTapGestureRecognizer : TapGestureRecognizer
{
    protected override bool ShouldRecognizeSimultaneously(IGestureRecognizer other)
    {
        return true; // 允许和其他触摸事件同时识别
    }
}

public class CustomPinchGestureRecognizer : PinchGestureRecognizer
{
    protected override bool ShouldRecognizeSimultaneously(IGestureRecognizer other)
    {
        return true;
    }
}

然后在GestureContainer的构造函数中使用这些自定义的GestureRecognizer即可。

内容的提问来源于stack exchange,提问作者Santos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:45:37