【问题标题】:Xamarin UIScrollView GestureRecognizerShouldBegin reports velocity of 0 when scroll view is movingXamarin UIScrollView GestureRecognizerShouldBegin 在滚动视图移动时报告速度为 0
【发布时间】:2016-01-25 14:47:31
【问题描述】:

我正在使用 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

编辑澄清:

澄清我最终要做什么:我在水平分页视图中有一个垂直滚动视图。我想检查平移的速度,以便如果平移是“水平的”(即 X 速度 > Y 速度),我可以告诉滚动视图不处理该手势。默认行为是,一旦滚动视图处于运动状态,另一个手势仍会滚动,但这使得用户很难水平滚动(跨页面),直到垂直滚动完全稳定为止。

【问题讨论】:

    标签: ios xamarin uiscrollview xamarin.ios uigesturerecognizer


    【解决方案1】:

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

    关键是滚动视图使用的默认平移手势识别器将始终报告 0 速度,如果它已经在运动中(例如,前一个手势的惯性仍然有效)。添加新的UIPanGestureRecognizer 是记录后续手势的“实际”速度的好方法,但到那时已经太晚了,无法影响原始平移手势的GestureRecognizerShouldBegin。所以我所要做的就是将一个ShouldBegin 委托添加到我的新UIPanGestureRecognizer 并使用 that 返回false,以防我希望手势“通过”给父级寻呼机。

            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;
            }
    

    【讨论】:

      【解决方案2】:

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

      就通过 GestureRecognizerShouldBegin 上的 VelocityInView 获取 p/s 而言,在平移运动开始后获得 0,0,但不会停止/重置,这是预期的,至少根据我的经验。 Obj-C/Swift 会返回同样的东西,不要问我为什么,必须让一个真正的 iOS 开发者来问那个原因。

      如果您真的需要在 GestureRecognizerShouldBegin 内从任何其他平移识别器(我在下面的示例中执行此操作)在您的 UIScrollView 子类中分配一个私有 CGPoint,那么在“任何地方”获取速度,您应该是黄金级的。 .

      示例输出:

      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;
              }
          }
      }
      

      【讨论】:

      • 我试过这个,但似乎发生的情况是,您第二次做出手势(移动时),GestureRecognizerShouldBegin 使用默认平移手势识别器(报告 0)调用,然后使用的速度是来自“新”平移手势识别器的 last 报告的速度。换句话说,新的平移手势持有前一个手势的旧值,因此在“常规”平移手势失败(报告 0)时,新的平移手势尚未“开始”并更新其值。我不知道如何让自定义一个触发ShouldBegin 方法...
      • 我刚刚还尝试从滚动视图中删除默认的平移手势识别器,只留下新的平移手势识别器。我看到它进入状态“开始”的消息,但是只有那个手势分配给滚动视图,滚动视图永远不会触发 GestureRecognizerShouldBegin 方法,也不会再移动。我做错了将这个手势“连接”到我认为的视图。
      • 我不认为我在做任何特别的事情,这是整个 UIScrollView 子类,我把它扔到一个视图(AddSubView)上并添加了一个非常大的图像(通过 UIImageView 的 UIImage)为了有东西要平移。我现在通常远离乱七八糟的速度......,当他们的体验改变正常时,用户似乎总是皱眉......您使用 GestureRecognizerShouldBegin 的用例是什么?也许另一种方式来做你需要的(?)
      • 为了澄清我最终想要做的事情:我在水平分页视图中有一个垂直滚动视图。我想检查平移的速度,以便如果平移是“水平的”(即 X 速度 > Y 速度),我可以告诉滚动视图不处理该手势。默认行为是,一旦滚动视图处于运动状态,另一个手势仍会滚动,但这使得用户很难水平滚动(跨页面),直到垂直滚动完全稳定为止。
      • 我完全复制了你的代码,只是它给出了一个“旧”的速度。只保留GestureRecognizerShouldBegin 方法中的日志输出,然后向下再向上滚动。您会注意到初始平移具有负 Y 速度(向下):GestureRecognizerShouldBegin velocity: {X=73.03223, Y=-985.935},然后第二个手势显示“零情况”,它使用来自另一个识别器的陈旧速度:!!!! ShouldBegin velocity not reset !!!!GestureRecognizerShouldBegin velocity: {X=265.2679, Y=-1527.014}(也向下),然后新的手势识别器启动:
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多