【问题标题】:The meaning of returning false from OnGestureListener.onDown()OnGestureListener.onDown()返回false的意义
【发布时间】:2021-08-20 17:25:39
【问题描述】:

根据android training,如果你扩展GestureDetector.SimpleOnGestureListener,并从onDown(...)返回false,那么GestureDetector.SimpleOnGestureListener的其他方法将永远不会被调用:

无论您是否使用 GestureDetector.OnGestureListener,最好实现一个返回 true 的 onDown() 方法。这是因为所有手势都以 onDown() 消息开头。如果你从 onDown() 返回 false,就像 GestureDetector.SimpleOnGestureListener 默认做的那样,系统假定你想忽略手势的其余部分,并且 GestureDetector.OnGestureListener 的其他方法永远不会被调用。这有可能在您的应用程序中导致意外问题。唯一应该从 onDown() 返回 false 的情况是,如果你真的想忽略整个手势。

但是,在我的简单测试中,onScroll(...) 被调用。

public void onCreate(Bundle savedInstanceState) {
    mDetector = new GestureDetectorCompat(this, MyGestureListener);
}


public boolean onTouchEvent(MotionEvent event) { 
    mDetector.onTouchEvent(event);
    return true;
}


class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
    private boolean scrollEvent;

    @Override
    public boolean onDown (MotionEvent event) {
        Log.v("GESTURE", "onDown ");
        return false;
    }

    @Override
    public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.v("GESTURE", "onScroll");
        return true;
    }

另一个类似的问题是下一个定义,同样来自同一个 android 培训页面:

单个 on 方法的返回值为 true 表示您已经处理了触摸事件。 false 返回值通过视图堆栈向下传递事件,直到成功处理触摸。

这与之前的报价有何不同?

【问题讨论】:

    标签: android android-gesture android-touch-event


    【解决方案1】:

    您应该从 onDown() 返回 false 的唯一情况是您真的想忽略整个手势。

    这几乎说明了一切。

    重点是onDown(...) 方法接收MotionEvent 作为参数,您可以选择在onDown(...) 方法中分析MotionEvent,如果它不是您想要处理的东西,则返回false.

    MotionEvent 包含许多详细信息,包括手势开始的位置(例如) - 如果它在您要处理的区域之外,则返回 false,否则返回 true

    如果您从onDown(...) 返回true,则将调用其他方法。这些方法中的每一个都可以选择分析和处理传递给它们的各种参数。如果您在任何这些方法中处理事件并且不想要任何进一步的操作,则从这些方法返回 true,否则将调用其他方法(可能在超类中,具体取决于您的代码实现)。

    手势很复杂,涉及上下动作以及任何方向的运动。允许选择拒绝手势(通过在onDown(...) 中返回false)使事情变得更加通用。

    编辑:在某些情况下,您可能会在屏幕上有多个视图。传递给onDown(...)MotionEvent 将包含有关手势开始位置的信息。如果您不希望屏幕的某些区域对手势做出反应,则在检查手势的开始位置后返回 false

    【讨论】:

    • 我仍然不明白为什么我从onDown(...) 返回false 并且onScroll(...) 被调用。谢谢你的好答案。
    • @user1869297 :请参阅我答案末尾的编辑。通过检查MotionEvent,您可以判断手势是否在您希望发生的屏幕区域中发生。如果不是,则通过返回 false 来忽略该手势。
    【解决方案2】:

    实际上,我不知道它是否正确,但这个定义在这种情况下会正确

    例如,您为TextView 处理onTouch(TextView 默认为not clickable

    class MainActivity : AppCompatActivity() {
        private lateinit var detector: GestureDetectorCompat
    
        public override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            detector = GestureDetectorCompat(this, MyGestureListener())
    
    
            findViewById<View>(R.id.textview).setOnTouchListener { v, event ->
                // 
                // Don't always return true here (like OP post)
                // 
                detector.onTouchEvent(event) // Kotlin code, equivalent to "return detector.onTouchEvent(event)" in Java
            }
        }
    
        inner class MyGestureListener : GestureDetector.SimpleOnGestureListener() {
    
            override fun onDown(event: MotionEvent): Boolean {
                Log.d(DEBUG_TAG, "onDown: " + event.toString())
                return false
            }
    
            override fun onFling(event1: MotionEvent, event2: MotionEvent,
                             velocityX: Float, velocityY: Float): Boolean {
                Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString())
                return true
            }
    
            override fun onSingleTapUp(event: MotionEvent?): Boolean {
                Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString())
                return true
            }
        }
    }
    

    在这种情况下:
    如果您的 onDown 函数返回 FALSE,则在 onFlingonSingleTapUp NEVER 上调用

    如果您的 onDown 函数返回 TRUE,则在 onFlingonSingleTapUp 上调用 CAN

    注意

    如果视图为not clickable,则此定义将更正。
    如果视图是clickable,则ALL 事件将CALLED onDown return falseonDown return true

    希望对您有所帮助,如果我错了,请纠正我 DEMO

    【讨论】:

      【解决方案3】:

      我不确定我是对还是错,但以下是用户应该从 onDown() 返回 false 的点

      1. 当用户不想对屏幕上的手势做出反应时。
      2. 当用户想要实现或使用触摸事件的 onLongPress() 方法时。

      对于第 1 点,@Squonk 和 @Phan Van Linh 都提供了解释,所以我只解释第 2 点。

      第二点:当用户想要实现 onLongPress() 方法时。

      public MySurfaceView(Context context, IAttributeSet attrs):base(context, attrs)
      {
          this.context=context;
          SetWillNotDraw(false);
          gestureDetector = new GestureDetector(context, new GestureListener());
      
      }
      
       public override bool OnTouchEvent(MotionEvent e)
      {
          Log.Debug(Tag, "Inside" + System.Reflection.MethodBase.GetCurrentMethod().Name + "Method");
          return gestureDetector.OnTouchEvent(e); 
      }
      
      private class GestureListener : GestureDetector.SimpleOnGestureListener
      {
          public override bool OnDown(MotionEvent e)
          {
              Log.Debug("Tag", "Inside Gesture OnDown Event");
              // don't return false here or else none of the other 
              // gestures will work
              return true;
      
          }
      
          public override bool OnSingleTapConfirmed(MotionEvent e)
          {
              Log.Debug("Tag", "Inside Gesture OnSingleTapConfirmed Event");
      
              return true;
          }
      
          public override bool OnDoubleTap(MotionEvent e)
          {
              Log.Debug("Tag", "Inside Gesture OnDoubleTap Event");
              return true;
          }
      
          public override void OnLongPress(MotionEvent e)
          {
              Log.Debug("Tag", "Inside Long Press Event");
          }
      
      
      
      
      }
      

      如果你在 OnDown 方法中返回 True,则 GestureListener 类的所有方法都将被调用,除了 onLongPress()

      如果你在 OnDown 方法中返回 false,那么只有 onLongPress 方法会被调用。

      如果我的观察有误,请告诉我。

      【讨论】:

        猜你喜欢
        • 2018-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-27
        • 1970-01-01
        • 1970-01-01
        • 2019-05-04
        相关资源
        最近更新 更多