Xamarin UIScrollView GestureRecognizerShouldBegin在滚动视图移动时报告速度为0

我使用Xamarin来开发一个iOS应用程序,我想子类UIScrollView为了处理在滚动视图基于其速度的平移手势。 所以,我重写了GestureRecognizerShouldBegin并检查了平移手势的VelocityInView 。 这适用于第一个手势,但在滚动视图运动(减速)时触发的后续平移手势总是报告(0,0)的速度:

 public class MyScroll : UIScrollView { public override bool GestureRecognizerShouldBegin(UIGestureRecognizer gestureRecognizer) { UIPanGestureRecognizer panGesture = gestureRecognizer as UIPanGestureRecognizer; if (panGesture != null) { CGPoint velocity = panGesture.VelocityInView(this); Console.WriteLine("Pan gesture velocity: " + velocity); } return true; } } 

在滚动处于运动状态的同时平移一次,然后再一次输出:

 Pan gesture velocity: {X=37.92359, Y=-872.2426} Pan gesture velocity: {X=0, Y=0} 

这是一个错误还是这是预期的行为?

编辑:跨Xamarin的论坛上发布: https : //forums.xamarin.com/discussion/54478/uiscrollview-pan-gesture-velocity-reporting-0-if-is-already-moving#latest

编辑澄清:

澄清我最终要做的事情:在水平分页视图内有一个垂直滚动视图。 我想检查锅的速度,以便我可以告诉滚动视图,如果锅是“水平”(即,X速度> Y速度),不处理该手势。 默认行为是这样的:一旦滚动视图处于运动中,另一个手势仍然滚动,但是这使得用户难以水平滚动(横跨页面)直到垂直滚动已经完全解决。

这是一个错误还是这是预期的行为?

在通过GestureRecognizerShouldBegin上的VelocityInView获取p / s方面,在pan运动开始后得到0,0, 但是没有停止/重置 ,至less在我的经验中是预期的。 Obj-C / Swift将会返回同样的东西,不要问我为什么,必须得到一个真正的iOS开发者来问这个问题。

如果你真的需要在GestureRecognizerShouldBegin从任何其他的泛识别器(我在下面的例子中这样做)在你的UIScrollView子类中分配一个私人的CGPoint,那么你应该是金GestureRecognizerShouldBegin

示例输出:

 2015-10-26 12:07:06.676 iOSVelocity[68486:2309184] Touch-enabed Pan gesture velocity: {X=-608.4813, Y=0} 2015-10-26 12:07:06.703 iOSVelocity[68486:2309184] Touch-enabed Pan gesture velocity: {X=-1213.629, Y=0} 2015-10-26 12:07:06.726 iOSVelocity[68486:2309184] Touch-enabed Pan gesture velocity: {X=-935.5507, Y=0} 2015-10-26 12:07:06.771 iOSVelocity[68486:2309184] Touch-enabed Pan gesture velocity: {X=-1191.385, Y=-8.564461} 2015-10-26 12:07:06.772 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=-1191.385, Y=-8.564461} 2015-10-26 12:07:06.772 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=-1191.385, Y=-8.564461} 2015-10-26 12:07:08.882 iOSVelocity[68486:2309184] !!!! ShouldBegin velocity not reset !!!! 2015-10-26 12:07:08.885 iOSVelocity[68486:2309184] GestureRecognizerShouldBegin velocity: {X=-1191.385, Y=-8.564461} 2015-10-26 12:07:08.887 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=-1191.385, Y=-8.564461} 2015-10-26 12:07:08.889 iOSVelocity[68486:2309184] gestureRecognizer velocity: {X=0, Y=0} 2015-10-26 12:07:08.890 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=0, Y=0} 2015-10-26 12:07:08.891 iOSVelocity[68486:2309184] gestureRecognizer velocity: {X=0, Y=0} 2015-10-26 12:07:08.937 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=0, Y=0} 2015-10-26 12:07:08.938 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=0, Y=0} 2015-10-26 12:07:08.939 iOSVelocity[68486:2309184] gestureRecognizer velocity: {X=-336.9197, Y=0} 2015-10-26 12:07:08.940 iOSVelocity[68486:2309184] Touch-enabled Pan gesture velocity: {X=-336.9197, Y=0} 2015-10-26 12:07:08.954 iOSVelocity[68486:2309184] Touch-enabled Pan gesture velocity: {X=-650.7258, Y=0} 2015-10-26 12:07:08.961 iOSVelocity[68486:2309184] Touch-enabled Pan gesture velocity: {X=-650.7258, Y=0} 2015-10-26 12:07:08.993 iOSVelocity[68486:2309184] Touch-enabled Pan gesture velocity: {X=-914.0547, Y=0} 2015-10-26 12:07:09.027 iOSVelocity[68486:2309184] Touch-enabled Pan gesture velocity: {X=-734.1516, Y=0} 2015-10-26 12:07:09.032 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=-734.1516, Y=0} 2015-10-26 12:07:09.033 iOSVelocity[68486:2309184] otherGestureRecognizer velocity: {X=-734.1516, Y=0} 2015-10-26 12:07:09.060 iOSVelocity[68486:2309184] Touch-enabled Pan gesture velocity: {X=-1086.368, Y=0} 

示例UIScrollView子类:

注意:这使用shouldRecognizeSimultaneouslyWithGestureRecognizer为了允许自动平移在用户举起他们的触摸之后继续

注2:不知道我是否抓住了所有的手势状态排列,所以根据需要进行调整

 using System; using UIKit; using CoreGraphics; using CoreFoundation; using CoreData; using Foundation; using CoreMotion; namespace iOSVelocity { public class MyScroll : UIScrollView { UIPanGestureRecognizer panGesture; CGPoint velocity; public MyScroll (CGRect cGRect) : base (cGRect) { panGesture = new UIPanGestureRecognizer (() => { if ((panGesture.State == UIGestureRecognizerState.Began || panGesture.State == UIGestureRecognizerState.Changed) && (panGesture.NumberOfTouches == 1)) { velocity = panGesture.VelocityInView (this); Console.WriteLine ("Touch-enabled Pan gesture velocity: " + velocity); } else if (panGesture.State == UIGestureRecognizerState.Ended) { // Gesture ended, but auto-panning could still be going... } }); AddGestureRecognizer (panGesture); } [Export ("gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:")] public bool ShouldRecognizeSimultaneously (UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer) { if (gestureRecognizer is UIPanGestureRecognizer) { var panRecognizer = (UIPanGestureRecognizer)gestureRecognizer; velocity = panRecognizer.VelocityInView (this); Console.WriteLine ("gestureRecognizer velocity: " + velocity); } else if (otherGestureRecognizer is UIPanGestureRecognizer) { var panRecognizer2 = (UIPanGestureRecognizer)otherGestureRecognizer; CGPoint beginvelocity = panRecognizer2.VelocityInView(this); if (beginvelocity.X != 0 && beginvelocity.Y != 0) velocity = panRecognizer2.VelocityInView (this); Console.WriteLine ("otherGestureRecognizer velocity: " + velocity); } else { // What should we do here? } return true; } public override bool GestureRecognizerShouldBegin (UIGestureRecognizer gestureRecognizer) { UIPanGestureRecognizer panGesture = gestureRecognizer as UIPanGestureRecognizer; if (panGesture != null) { CGPoint beginvelocity = panGesture.VelocityInView(this); if (beginvelocity.X == 0 && beginvelocity.Y == 0) { Console.WriteLine ("!!!! ShouldBegin velocity not reset !!!!"); } else { velocity = beginvelocity; } Console.WriteLine ("GestureRecognizerShouldBegin velocity: " + velocity); } return true; } } } 

我终于弄明白了。 感谢@RobertN的帮助:)

关键在于,如果滚动视图已经在运动(例如,来自先前手势的惯性仍然有效),那么由滚动视图使用的默认的平移手势识别器将总是报告0速度。 添加新的UIPanGestureRecognizer是logging后续手势的“实际”速度的好方法,但到那时,影响原始平移手势的GestureRecognizerShouldBegin时间已经太晚了。 所以我所要做的就是将ShouldBegin委托添加到新的UIPanGestureRecognizer并在我希望手势“传递”给父寻呼机的情况下使用来返回false

  public MyScroll() : base() { UIPanGestureRecognizer panGesture = new UIPanGestureRecognizer(); panGesture.ShouldBegin = delegate(UIGestureRecognizer recognizer) { CGPoint v = panGesture.VelocityInView(this); if (vX != 0 || vY != 0) { if (Math.Abs(vX) > Math.Abs(vY)) { return false; } } return true; }; this.AddGestureRecognizer(panGesture); } 

这样,我只是让默认的滚动视图平移手势识别器做它的事情,而我的新的UIPanGestureRecognizer识别用户何时正在做一个新的水平手势,并通过这一点,使寻呼机可以寻呼。 这使得父页面浏览器和垂直页面滚动视图的组合很好地结合在一起(想象垂直滚动页面并且能够翻页,即使垂直页面在运动中)。 请注意,您还需要实现以下方法以允许两个手势识别器同时操作:

  [Export("gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:")] public bool ShouldRecognizeSimultaneously(UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer) { return true; }