如何防止手势捕获子项滚动父级滚动视图

时间:2019-09-09 08:58:18

标签: xamarin xamarin.forms xamarin.ios uiscrollview scrollview

我正在创建一个要嵌入到滚动视图中的自定义控件(自​​定义Skia画布),因为自定义控件(子元素)正在捕获手势输入,这意味着父滚动视图有时会滚动,有时不会在iOS上。

到目前为止,我们已经为滚动视图创建了一个自定义渲染器,可以在“ ScrollEnabled”上启用/禁用一个属性,这在Android上运行良好,并且允许我们在点击并按住时与子元素进行交互在子对象上,但是此解决方案对于iOS来说并不令人满意,因为我们没有从子元素中获得取消触发器来告诉父对象上的ScrollEnabled设置回True(因此允许scrollview再次滚动)。

图表视图

public static readonly BindableProperty AllowStackScrollProperty = BindableProperty.Create(nameof(AllowStackScroll), typeof(bool), typeof(TPChartView), false);

public bool AllowStackScroll  
{
    get { return (bool)GetValue(AllowStackScrollProperty); }
    set { SetValue(AllowStackScrollProperty, value); }
}
{

    _currentTouchAction = e.ActionType;
    if (e.ActionType == SKTouchAction.Cancelled) return;

    ((MasterDetailPage)Application.Current.MainPage).IsGestureEnabled = false;

    if (e.ActionType == SKTouchAction.Released || e.ActionType == SKTouchAction.Exited)
    {
        AllowStackScroll = true;
        this.Chart.OnTouchEnd();
        this.InvalidateSurface();
        e.Handled = true;
        ((MasterDetailPage)Application.Current.MainPage).IsGestureEnabled = true; //Enable the menu gestures again
        return;
    }



    TPVector point = new TPVector(e.Location.X, e.Location.Y);
    this.Chart.OnTouchBegan(point);
    this.InvalidateSurface();
    e.Handled = true;
}

ScrollView渲染器(iOS)

public class TPScrollViewIOSRenderer : ScrollViewRenderer
{
    public new static void Init()
    {
    }

    public bool ScrollDisabled { get; set; } = false;
    private string _currentTouchAction { get; set; }
    public TPScrollViewIOSRenderer()
    {
        if (((TPScrollView)Element) == null) return;
            ((TPScrollView)Element).PropertyChanged += Element_PropertyChanged;
        ScrollEnabled = ((TPScrollView)Element).ScrollingEnabled;

    }


    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);

    }

    public override void TouchesBegan(Foundation.NSSet touches, UIEvent evt)
    {
        if (((TPScrollView)Element) == null) return;

        UITouch touch = touches.AnyObject as UITouch;

        _currentTouchAction = "press";
        LongPress(50, resp => 
        {
            if (resp)
            {

                Device.BeginInvokeOnMainThread(() => 
                {
                ScrollEnabled = false;
                });
            }
            else
            {

                Device.BeginInvokeOnMainThread(() =>
                {
                    ScrollEnabled = true;
                });

            }

        }); 
        base.TouchesBegan(touches, evt);
    }

    public override void TouchesMoved(Foundation.NSSet touches, UIKit.UIEvent evt)
    {
        if (((TPScrollView)Element) == null) return;
        _currentTouchAction = "move";

        base.TouchesMoved(touches, evt);
    }

    public override void TouchesEnded(Foundation.NSSet touches, UIKit.UIEvent evt)
    {
        if (((TPScrollView)Element) == null) return;
        _currentTouchAction = "end";

        Device.BeginInvokeOnMainThread(() =>
        {
            ScrollEnabled = true;
        });


        base.TouchesEnded(touches, evt);
    }

    public override void TouchesCancelled(Foundation.NSSet touches, UIEvent evt)
    {
        if (((TPScrollView)Element) == null) return;
        _currentTouchAction = "canceled";

        Device.BeginInvokeOnMainThread(() =>
        {
            ScrollEnabled = true;
        });

        base.TouchesCancelled(touches, evt);
    }


    public void LongPress(int ExecutionTime, Action<bool> OnComplete)
    {
        var timer = new System.Threading.Timer(
             e =>
             {

                 if (_currentTouchAction == "press" || _currentTouchAction == "move")
                 {
                     OnComplete.Invoke(true);
                     return;
                 }

                 OnComplete.Invoke(false);

             },
             null,
             TimeSpan.FromMilliseconds(ExecutionTime),
             TimeSpan.FromMilliseconds(-1));

    }

    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null) Dispose();

        ScrollEnabled = ((TPScrollView)Element).ScrollingEnabled;
    }

    private void Element_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "ScrollingEnabled");
        { }

    }
}

我们只想要iOS上的行为,即内部元素仅在按住时捕获手势,放开后,父级ScrollView再次优先并允许滚动。

0 个答案:

没有答案