自定义控件之——GestureDetector用户手势检测分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43847987/article/details/102745142

在我们平常的使用当中会只用到很多的手势,DOWN,MOVE,UP,SCROLL,FLING等等,当然在我们之前的理解中使用View的onTouchEvent好像都可以解决,但是在实现的逻辑上也许就会非常的复杂了。所以Android为我们更加方便实现复杂的手势操作提供了GestureDetector这个类。

DestureDetector的接口

DestureDetector对外提供了两个接口(OnGestureDetectorOnDoubleTapListener)和一个外部类(SimpleOnGestureListener)。

GestureDetector.OnGesstureListener接口

首先我们查看该接口内需要实现的方法如下:

public interface OnGestureListener {

        /**
         *用户按下屏幕的时候就会触发
         */
        boolean onDown(MotionEvent e);

        /**
         * 如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPresss就会执行
         */
        void onShowPress(MotionEvent e);

        /**
         *一次轻击屏幕,立刻抬起来,就会有这个触发,当然如果除了Down以外还有其他操作,那就不会再算是Single操作。所以也就不会触发这个事件。
         */
        boolean onSingleTapUp(MotionEvent e);

        /**
         *在屏幕上拖动事件。无论是用手指慢慢拖动View,还是以快速的抛出动作滚动,都会多次触发这个方法
         */
        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);

        /**
         *长按屏幕,超过一定的时间就会触发这个事件
         */
        void onLongPress(MotionEvent e);

        /**
         * 滑屏,用户按下触摸屏,快速移动后松开,由一个MotionEvent.ACTION_DOWN,多个ACTION_MOVE,1个ACTION_UP触发
         *e1:第一个ACTION_DOWN MotionEvent
         *e2:最后一个ACTION_MOVE MotionEvent
         *velocityX:X轴上的移动距离,像素/秒
         *velocityY:Y轴上的移动距离,像素/秒
         */
        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);

各种点击所触发的事件:

  • 点击一下非常快的(不滑动)Touchup:onDown->onSingleTapup->onSingleTapConfirmed
  • 点击一下稍微慢点(不滑动):onDown->onSowPress->onSingleTapup->onSingleTapConfirmed
  • 滑屏时:onDown----->onScroll—>onScroll---->onScroll---->………----->onFling
  • 拖动时:onDown------>onScroll---->onScroll->…------>onFiling

从这个listener中的实现方法我们知道这个接口的作用是监听一些手势,单击、滑动、拖动、长按等等

GestureDetector.OnDoubleTapListener接口

看看这个接口的内部实现:

    	/**
         *可以确认这是一个单击事件而不是一个双击事件的时候回调
         */
        boolean onSingleTapConfirmed(MotionEvent e);
 
        /**
         * 可以确认这是一个双击事件的时候回调
         */
        boolean onDoubleTap(MotionEvent e);

        /**
         *onDoubleTap()回调之后的输入事件(MOVE,UP,DOWN)都会回调这个方法
         *这个方法可以实现一些双击后的控制,让View双击后变得可拖动等
         */
        boolean onDoubleTapEvent(MotionEvent e);

通过查看接口的内部代码我们知道,这个listener主要实现监听点击事件和双击事件

GestureDetector.OnContextClickListener

在这个方法内部只有这样一个方法:

  		/**
         * 外接键盘的鼠标右键,当鼠标右键点击的时候回调
         */
        boolean onContextClick(MotionEvent e)

GestureDetector.SimpleOnGestureListener接口

这个接口其实就是实现上面三个方法的综合,拥有上面三个接口的所有回调方法

使用步骤

  1. 第一步:创建OnGestureListener()监听函数
  2. 创建DestureDetector实例
  3. 在onTouch(View v,MotionEvent event)中进行拦截
  4. 绑定控件

下面就用一个实例来展示如何使用GestureDetector吧

xml文件,再该文件中只设置了一个TextView,而且在java代码中我们设置这个TextView是可以点击和双击的。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:text="Hello World!"
        android:layout_margin="50dp"
        android:id="@+id/tv"
        android:background="#ff00ff"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

java代码,实现了onGestureListener接口和onDoubleTapListener

public class MainActivity extends AppCompatActivity implements View.OnTouchListener {

    private GestureDetector mGestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mGestureDetector=new GestureDetector(new gestureListener());
        mGestureDetector.setOnDoubleTapListener(new doubletapListener());
        TextView tv=findViewById(R.id.tv);
        tv.setOnTouchListener(this);
        tv.setFocusable(true);
        tv.setClickable(true);
        tv.setLongClickable(true);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return mGestureDetector.onTouchEvent(event);
    }

    private class gestureListener implements GestureDetector.OnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            Log.e("gestureListener","onDown");
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {
            Log.e("gestureListener","onShowPress");
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            Log.e("gestureListener","onSingleTapUp");
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            Log.e("gestureListener","onScroll"+(e2.getX()-e1.getX())+"  "+distanceX);
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            Log.e("gestureListener","onLongPress");

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            Log.e("gestureListener","onFling");
            return true;
        }
    }

    private class doubletapListener implements GestureDetector.OnDoubleTapListener{

        /**
         * 单击事件
         * @param e
         * @return
         */
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.e("doubletapListener","onSingleTapConfirmed");
            Toast.makeText(MainActivity.this, "onSingleTapConfirmed", Toast.LENGTH_SHORT).show();
            return true;
        }

        /**
         * @param e 双击事件
         * @return
         */
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            Log.e("doubletapListener","onDoubleTap");
            Toast.makeText(MainActivity.this, "onDoubleTap", Toast.LENGTH_SHORT).show();
            return true;
        }

        /**
         * 双击间隔中发生的动作
         * @param e
         * @return
         */
        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            Log.e("doubletapListener","doubletapListener");
            Toast.makeText(MainActivity.this, "doubletapListener", Toast.LENGTH_SHORT).show();
            return true;
        }
    }
}

代码很简单就只是在每个方法内部打印了一下日志:
单击事件:
在这里插入图片描述
双击事件:
在这里插入图片描述
滑动:
在这里插入图片描述
以上就是我么执行单击,双击,拖动等事件的的结果,当然我们打印日志是为了更好地使用它,在这个方法的内部我们可以执行我们需要用的方法或事件。

GestureDetector.SimpleOnGestureListener类的使用

这个是一个类,使用时只能extends,不能implements,在它的内部重写了onGestureListener和onDoubleTapListener两个接口中的所有函数,只不过这些方法都是空的。使用这个类的时候,我们不需要从写所有的方法,只需要重写我要用到的,所以使用起来会感觉代码更简洁。

各个方法的调用时机:

回调/输入事件 DOWN事件 MOVE事件 UP事件
onDown Y N N
onShowPress Y N N
onLongPress Y N N
onScroll N Y N
onFling N N Y
onSimgleTapUp N N Y
inSingleTapConfirmed N N Y
onDoubleTap Y N N
onDoubleTapEvent Y Y Y

猜你喜欢

转载自blog.csdn.net/weixin_43847987/article/details/102745142