【问题标题】:How to add a gesture detector to a view in Android如何将手势检测器添加到 Android 中的视图
【发布时间】:2017-12-16 17:13:59
【问题描述】:

我一直在努力将手势检测器添加到我项目的子视图中。我是否覆盖父母的onTouchEvent 或孩子的onTouchEvent?我要创建一个OnTouchListener 并在那里添加手势检测器吗? documentation 展示了如何将手势检测器添加到活动本身的示例,但不清楚如何将其添加到视图中。如果子类化视图(例如here),可以使用相同的过程,但我想添加手势而不子类化任何东西。

This 是我能找到的最接近的其他问题,但它特定于ImageView 上的投掷手势,而不是任何View 的一般情况。对于何时返回truefalse,这些答案也存在一些分歧。

为了帮助自己理解它的工作原理,我制作了一个独立的项目。我的答案如下。

【问题讨论】:

    标签: android touch-event gesturedetector


    【解决方案1】:

    此示例展示了如何将手势检测器添加到视图中。布局只是 Activity 中的一个 View。您可以使用相同的方法将手势检测器添加到任何类型的视图中。

    我们将手势检测器添加到绿色的View

    MainActivity.java

    基本思想是在视图中添加一个OnTouchListener。通常我们会在这里获取所有原始触摸数据(如ACTION_DOWNACTION_MOVEACTION_UP 等),但我们不会自己处理,而是将其转发给手势检测器来解释触摸数据。

    我们使用的是SimpleOnGestureListener。这个手势检测器的好处是我们只需要覆盖我们需要的手势。在这里的例子中,我包括了很多。您可以删除不需要的那些。 (不过,您应该始终在 onDown() 中返回 true。返回 true 表示我们正在处理该事件。返回 false 将使系统停止为我们提供更多触摸事件。)

    public class MainActivity extends AppCompatActivity {
    
        private GestureDetector mDetector;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // this is the view we will add the gesture detector to
            View myView = findViewById(R.id.my_view);
    
            // get the gesture detector
            mDetector = new GestureDetector(this, new MyGestureListener());
    
            // Add a touch listener to the view
            // The touch listener passes all its events on to the gesture detector
            myView.setOnTouchListener(touchListener);
        }
    
        // This touch listener passes everything on to the gesture detector.
        // That saves us the trouble of interpreting the raw touch events 
        // ourselves.
        View.OnTouchListener touchListener = new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // pass the events to the gesture detector
                // a return value of true means the detector is handling it
                // a return value of false means the detector didn't 
                // recognize the event
                return mDetector.onTouchEvent(event);
    
            }
        };
    
        // In the SimpleOnGestureListener subclass you should override 
        // onDown and any other gesture that you want to detect.
        class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
    
            @Override
            public boolean onDown(MotionEvent event) {
                Log.d("TAG","onDown: ");
    
                // don't return false here or else none of the other 
                // gestures will work
                return true;
            }
    
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                Log.i("TAG", "onSingleTapConfirmed: ");
                return true;
            }
    
            @Override
            public void onLongPress(MotionEvent e) {
                Log.i("TAG", "onLongPress: ");
            }
    
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Log.i("TAG", "onDoubleTap: ");
                return true;
            }
    
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, 
                                    float distanceX, float distanceY) {
                Log.i("TAG", "onScroll: ");
                return true;
            }
    
            @Override
            public boolean onFling(MotionEvent event1, MotionEvent event2,
                                   float velocityX, float velocityY) {
                Log.d("TAG", "onFling: ");
                return true;
            }
        }
    }
    

    运行此项目是一种快速设置,因此我建议您尝试一下。注意日志事件发生的方式和时间。

    【讨论】:

    • 是否可以检测 onCreate() 上的手势?我无法在 MyGestureListener 类中进行操作
    • 我的问题是关于你的答案,所以很难在新帖子中解释,我只是想问是否可以覆盖 onScroll()/onLongPress()/onSingleTapConfirmed() oncreate() 方法并在那里实现这些方法?
    • @Coder123,您所说的覆盖方法是 SimpleOnGestureListener 的一部分,所以如果您不将该类(或 GestureDetector)子类化,我认为没有办法它。您唯一的其他选择是在 OnTouchListener 中手动处理事件。
    • 这不适用于约束布局或线性布局,甚至是空视图。
    【解决方案2】:

    kotlin 中的简短版本,仅检测视图的双击:

    val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
        override fun onDoubleTap(e: MotionEvent?): Boolean {
            Log.d("myApp", "double tap")
            return true
        }
    })
    myView.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
    

    别忘了让myView 可点击

    【讨论】:

    • 谢谢。一个小的更正:onDown() 需要被覆盖并返回 true 否则它不会工作
    猜你喜欢
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-14
    相关资源
    最近更新 更多