Android手势检测简介
本文参考:启舰博客
一,简介
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; }}
方法 | 含义 |
---|---|
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
,将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; }}
更多相关文章
- Android中工作线程与主线程同步方式
- Android(安卓)多媒体
- android中调用系统功能 来显示本地相册图片 拍照 视频 音频功能
- Android事件分发和View绘制流程分析(三)
- Android(安卓)OnTouchListener OnGestureListener
- Android反射机制实例
- Android的webView应用与js互调app混合开发用例
- Android(安卓)获取当前日期 时间很方便 直接调用Calendar类即可
- Android调用相机和相册详解