当滚动视图移动时,Xamarin UIScrollView GestureRecognizerShouldBegin 报告速度为 0
Xamarin UIScrollView GestureRecognizerShouldBegin reports velocity of 0 when scroll view is moving
我正在使用 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-it-is-already-moving#latest
编辑澄清:
阐明我最终想做的事情:我在水平分页视图中有一个垂直滚动视图。我想检查平移的速度,以便在平移为 "horizontal"(即 X 速度 > Y 速度)时告诉滚动视图不处理该手势。默认行为是这样的,一旦滚动视图在运动,另一个手势仍然滚动,但这使得用户很难水平滚动(跨页面),直到垂直滚动完全稳定。
Is this a bug or is this the expected behavior?
就通过 GestureRecognizerShouldBegin 上的 VelocityInView 获取 p/s 而言,在平移运动开始后获取 0,0,但不是 stopped/reset,是预期,至少以我的经验。 Obj-C/Swift 将要 return 同样的事情,不要问我为什么,必须得到一个实际的 iOS 开发人员来询问那个原因。
抓住速度 'anywhere' 否则你应该是金色的,如果你真的需要在 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 子class:
注意:这使用 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
是记录后续手势的 "actual" 速度的好方法,但到那时影响原始平移手势的 GestureRecognizerShouldBegin
为时已晚。所以我所要做的就是向我的新 UIPanGestureRecognizer
添加一个 ShouldBegin
委托,并在这种情况下使用 that 到 return false
我想要 "fall through" 到父寻呼机的手势。
public MyScroll() : base()
{
UIPanGestureRecognizer panGesture = new UIPanGestureRecognizer();
panGesture.ShouldBegin = delegate(UIGestureRecognizer recognizer)
{
CGPoint v = panGesture.VelocityInView(this);
if (v.X != 0 || v.Y != 0)
{
if (Math.Abs(v.X) > Math.Abs(v.Y))
{
return false;
}
}
return true;
};
this.AddGestureRecognizer(panGesture);
}
这样,我只让默认的滚动视图平移手势识别器完成它的工作,而我的新 UIPanGestureRecognizer
识别用户何时做出新的水平手势,并传递该手势,以便寻呼机可以分页。这使得父分页器和垂直页面滚动视图的组合可以很好地协同工作(想象一下具有垂直滚动页面并能够翻阅页面,即使垂直页面处于运动状态)。注意,您还需要实现以下方法以允许两个手势识别器同时操作:
[Export("gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:")]
public bool ShouldRecognizeSimultaneously(UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer)
{
return true;
}
我正在使用 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-it-is-already-moving#latest
编辑澄清:
阐明我最终想做的事情:我在水平分页视图中有一个垂直滚动视图。我想检查平移的速度,以便在平移为 "horizontal"(即 X 速度 > Y 速度)时告诉滚动视图不处理该手势。默认行为是这样的,一旦滚动视图在运动,另一个手势仍然滚动,但这使得用户很难水平滚动(跨页面),直到垂直滚动完全稳定。
Is this a bug or is this the expected behavior?
就通过 GestureRecognizerShouldBegin 上的 VelocityInView 获取 p/s 而言,在平移运动开始后获取 0,0,但不是 stopped/reset,是预期,至少以我的经验。 Obj-C/Swift 将要 return 同样的事情,不要问我为什么,必须得到一个实际的 iOS 开发人员来询问那个原因。
抓住速度 'anywhere' 否则你应该是金色的,如果你真的需要在 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 子class:
注意:这使用 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
是记录后续手势的 "actual" 速度的好方法,但到那时影响原始平移手势的 GestureRecognizerShouldBegin
为时已晚。所以我所要做的就是向我的新 UIPanGestureRecognizer
添加一个 ShouldBegin
委托,并在这种情况下使用 that 到 return false
我想要 "fall through" 到父寻呼机的手势。
public MyScroll() : base()
{
UIPanGestureRecognizer panGesture = new UIPanGestureRecognizer();
panGesture.ShouldBegin = delegate(UIGestureRecognizer recognizer)
{
CGPoint v = panGesture.VelocityInView(this);
if (v.X != 0 || v.Y != 0)
{
if (Math.Abs(v.X) > Math.Abs(v.Y))
{
return false;
}
}
return true;
};
this.AddGestureRecognizer(panGesture);
}
这样,我只让默认的滚动视图平移手势识别器完成它的工作,而我的新 UIPanGestureRecognizer
识别用户何时做出新的水平手势,并传递该手势,以便寻呼机可以分页。这使得父分页器和垂直页面滚动视图的组合可以很好地协同工作(想象一下具有垂直滚动页面并能够翻阅页面,即使垂直页面处于运动状态)。注意,您还需要实现以下方法以允许两个手势识别器同时操作:
[Export("gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:")]
public bool ShouldRecognizeSimultaneously(UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer)
{
return true;
}