我正在创建一个要嵌入到滚动视图中的自定义控件(自定义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再次优先并允许滚动。