本文参考:
Android中的手势检测功能主要在GestureDetector这个类当中,所以主要是对GestureDetector这个类的说明。
GestureDetector类对外提供了两个接口和一个外部类,接口:OnGestureListenerOnDoubleTapListener,内部类:SimpleOnGestureListener

二,OnGestureListener接口
手势检测接口,当有down,move,up事件发生时,会回调其中的方法。
OnGestureListener接口重写必须重写6个方法。

public class GestureListenter implements GestureDetector.OnGestureListener {

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return false;
    }
}

方法

含义

OnDown(MotionEvent e)

发生down事件时会立即调用

onShowPress(MotionEvent e)

用户触发down事件,没触发move或yet事件,且down事件发生时间超过瞬间则调用

onLongPress(MotionEvent e)

down事件发生时间超过一定时长,会调用

onSingleTapUp(MotionEvent e)

单独的轻击会调用

onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY)

滑屏松开调用,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发。e1:第1个ACTION_DOWN MotionEvent;e2:最后一个ACTION_MOVE MotionEvent;velocityX:X轴上的移动速度,像素/秒;velocityY:Y轴上的移动速度,像素/秒

onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY)

滑屏调用,且会调用多次

实际操作

调用顺序

轻击

onDown() - onSingleTapup()

短按

onDown() - onShowPress() - onSingleTapUp()

长按

onDown() - onShowPress() - onLongPress()

短按慢划

onDown() - onShowPress() - 多个onScroll() -onFling()

快划

onDown() - 多个onScroll() - onFling()

长按滑动

onDown() - onShowPress() - onLongPress()

总结:当点击时接触屏幕时间超过一定时间会触发onShowPress(),可以作为是否误触的一个判决条件。

public class MainActivity extends AppCompatActivity {

    private GestureDetector mGestureDetector;
    TextView mTextTv;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mGestureDetector = new GestureDetector(new GestureListenter());
        mTextTv = findViewById(R.id.tv_text);
        mTextTv.setFocusable(true);
        mTextTv.setClickable(true);
        mTextTv.setLongClickable(true);
        mTextTv.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return mGestureDetector.onTouchEvent(event);
            }
        });
    }
}

public class GestureListenter implements GestureDetector.OnGestureListener {

    private static final String TAG = "GestureListenter";

    @Override
    public boolean onDown(MotionEvent e) {
        Log.i(TAG, "onDown: ");
        return true;
    }

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

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

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

    @Override
    public void onLongPress(MotionEvent e) {
        Log.i(TAG, "onLongPress: ");
    }

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

需要注意的是onDown()方法应该返回true,否则会导致在慢速滑动况下结束时不会调用onFling()方法,我刚才踩到了。

三,OnDoubleTapListener接口
OnDoubleTapListener是检测屏幕双击的接口。重写时需要重写3个方法

public class DoubleTapListener implements GestureDetector.OnDoubleTapListener {
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        return false;
    }
}

方法

含义

onSingleTapConfirmed(MotionEvent e)

单击确认触发

onDoubleTap(MotionEvent e)

双击时触发

onDoubleTapEvent(MotionEvent e)

双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作,包含down、up和move事件。

public class DoubleTapListener implements GestureDetector.OnDoubleTapListener {

    private static final String TAG = "WillScorpio";

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        Log.i(TAG, "onSingleTapConfirmed: ");
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        Log.i(TAG, "onDoubleTap: ");
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        Log.i(TAG, "onDoubleTapEvent: ");
        return true;
    }
}

为了便于观看log,将ListenerTAG设置为一样的。

mGestureDetector.setOnDoubleTapListener(new DoubleTapListener());

再通过上面的代码设置OnDoubleTapListener

事件

调用过程

轻点

onDown() - onSingleTapUp() - onSingleTapConfirmed()

单击

onDown() - onShowPress() - onSingleTapUp() - onSingleTapConfirmed()

轻击两次

onDown() - onSingleTapUp() - onDoubleTap() - onDoubleTapEvent() - onDown() - onDoubleTapEvent()

单击两次

onDown() - onShowPress()- onSingleTapUp() - onDoubleTap() - onDoubleTapEvent() - onDown() - onDoubleTapEvent()

第一次点击第二次点上滑动

onDown() - onShowPress() - onSingleTapUp() - onDoubleTap() - onDoubleTapEvent() - onDown() - 多个onDoubleTapEvent()

总结:1.在第二下点击时,先触发OnDoubleTap,然后再触发OnDown(第二次点击)。
2.在多个onDoubleTapEvent()之间可能会有onShowPress(),onShowPress()不应该作为重要参数。

四,SimpleOnGestureListener内部类
SimpleOnGestureListenerGestureDetector的内部类,它实现了OnGestureListenerOnDoubleTapListener接口,这样做的好处是如果我们只准备重写其中几个方法,不想重写所有接口方法或准备重写所有方法,便可以选择这个内部类,GestureDetector提供了构造方法。

GestureDetector gestureDetector=new GestureDetector(GestureDetector.OnGestureListener listener);
GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.OnGestureListener listener);
GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener);

android 怎样计算触摸位置 安卓手机触摸测试_android 怎样计算触摸位置


五,识别左右滑动识别左右滑动在onFling()这个函数中,e1是刚开始的MotionEvente2是最后的MotionEvent,正常滑动时没问题,但如果做如下图的滑动,会造成混淆。

android 怎样计算触摸位置 安卓手机触摸测试_android 怎样计算触摸位置_02

public class GestureListenter implements GestureDetector.OnGestureListener {

    private static final String TAG = "WillScorpio";
    final int FLING_MIN_DISTANCE = 100;
    final int FLING_MIN_VELOCITY = 200;


    @Override
    public boolean onDown(MotionEvent e) {
        Log.i(TAG, "onDown: ");
        return true;
    }

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

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

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

    @Override
    public void onLongPress(MotionEvent e) {
        Log.i(TAG, "onLongPress: ");
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE && Math.abs(velocityX) > FLING_MIN_VELOCITY) {
            Log.i(TAG, "onFling: Left");
        }
        if (e2.getX() - e1.getX() > FLING_MIN_DISTANCE && Math.abs(velocityX) > FLING_MIN_VELOCITY) {
            Log.i(TAG, "onFling: Right");
        }
        return true;
    }
}