本文参考:
Android中的手势检测功能主要在GestureDetector
这个类当中,所以主要是对GestureDetector
这个类的说明。GestureDetector
类对外提供了两个接口和一个外部类,接口:OnGestureListener
,OnDoubleTapListener
,内部类: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;
}
}
方法 | 含义 |
| 发生down事件时会立即调用 |
| 用户触发down事件,没触发move或yet事件,且down事件发生时间超过瞬间则调用 |
| down事件发生时间超过一定时长,会调用 |
| 单独的轻击会调用 |
| 滑屏松开调用,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发。e1:第1个ACTION_DOWN MotionEvent;e2:最后一个ACTION_MOVE MotionEvent;velocityX:X轴上的移动速度,像素/秒;velocityY:Y轴上的移动速度,像素/秒 |
| 滑屏调用,且会调用多次 |
实际操作 | 调用顺序 |
轻击 | 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;
}
}
方法 | 含义 |
| 单击确认触发 |
| 双击时触发 |
| 双击间隔中发生的动作。指触发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
,将Listener
的TAG
设置为一样的。
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
内部类SimpleOnGestureListener
时GestureDetector
的内部类,它实现了OnGestureListener
和OnDoubleTapListener
接口,这样做的好处是如果我们只准备重写其中几个方法,不想重写所有接口方法或准备重写所有方法,便可以选择这个内部类,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);
五,识别左右滑动识别左右滑动在onFling()
这个函数中,e1
是刚开始的MotionEvent
,e2
是最后的MotionEvent
,正常滑动时没问题,但如果做如下图的滑动,会造成混淆。
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;
}
}