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

UIScrollView在WillEndDragging时向子控件传递事件问题

解决方案:在iOS自定义渲染器中手动触发触摸取消事件

步骤1:创建自定义ScrollView(适配CollectionView同理)

在共享项目中定义自定义滚动视图,方便渲染器定位:

public class CustomScrollView : ScrollView
{
}

步骤2:实现iOS自定义渲染器

创建iOS平台渲染器,监听滚动结束事件并追踪初始触摸控件,手动发送取消事件:

[assembly: ExportRenderer(typeof(CustomScrollView), typeof(CustomScrollViewRenderer))]
namespace YourAppNamespace.iOS.Renderers
{
    public class CustomScrollViewRenderer : ScrollViewRenderer
    {
        private UIView _activeTouchView;

        protected override void OnElementChanged(ElementChangedEventArgs<ScrollView> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.WillEndDragging += OnWillEndDragging;
                Control.TouchesBegan += OnTouchesBegan;
            }
        }

        private void OnTouchesBegan(NSSet touches, UIEvent evt)
        {
            base.TouchesBegan(touches, evt);
            
            var touch = touches.AnyObject as UITouch;
            if (touch == null) return;
            
            var touchLocation = touch.LocationInView(Control);
            _activeTouchView = Control.HitTest(touchLocation, evt);
        }

        private void OnWillEndDragging(object sender, UIScrollViewWillEndDraggingEventArgs e)
        {
            if (_activeTouchView == null) return;
            
            var touches = new NSSet();
            var evt = UIEvent.FromEventHandle(IntPtr.Zero);
            _activeTouchView.TouchesCancelled(touches, evt);
            
            _activeTouchView = null;
        }

        protected override void Dispose(bool disposing)
        {
            if (Control != null)
            {
                Control.WillEndDragging -= OnWillEndDragging;
                Control.TouchesBegan -= OnTouchesBegan;
            }
            base.Dispose(disposing);
        }
    }
}

步骤3:自定义控件适配触摸取消事件

如果你的自定义控件需要重置点击状态,在其iOS渲染器中重写TouchesCancelled方法:

public class CustomButtonRenderer : ButtonRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
    {
        base.OnElementChanged(e);
        if (Control != null)
        {
            Control.TouchesCancelled += OnTouchesCancelled;
        }
    }

    private void OnTouchesCancelled(NSSet touches, UIEvent evt)
    {
        base.TouchesCancelled(touches, evt);
        Control.Highlighted = false;
        // 同步Xamarin Forms控件状态,比如调用自定义重置方法
        ((CustomButton)Element)?.ResetPressedState();
    }

    protected override void Dispose(bool disposing)
    {
        if (Control != null)
        {
            Control.TouchesCancelled -= OnTouchesCancelled;
        }
        base.Dispose(disposing);
    }
}

关键说明

  • 通过HitTest定位触摸起始点对应的子控件,确保取消事件发送给正确目标。
  • 在WillEndDragging中手动触发TouchesCancelled,对齐Android/UWP平台的触摸行为,让控件能重置点击状态。
  • 若使用CollectionView,只需将渲染器基类替换为CollectionViewRenderer,核心逻辑完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 18:50:28