- GestureDetector为手势识别类,用来监听回调用户对视图的操作。
这次我们就分别模拟一些用户的手势事件,来看看这个类是怎么回调的吧
废话不多说,直接看代码。
public class MainActivity extends AppCompatActivity {
private Button mButton;
private GestureDetector mGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.button);
mGestureDetector = new GestureDetector(this, new MyOnGestureListener());
mButton = (Button) findViewById(R.id.btn_textgesture);
mButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(getClass().getName(), "onTouch-----" +
getActionName(event.getAction()));
mGestureDetector.onTouchEvent(event);
// 一定要返回true,不然获取不到完整的事件
return true;
}
});
}
private String getActionName(int action) {
String name = "";
switch (action) {
case MotionEvent.ACTION_DOWN: {
name = "ACTION_DOWN";
break;
}
case MotionEvent.ACTION_MOVE: {
name = "ACTION_MOVE";
break;
}
case MotionEvent.ACTION_UP: {
name = "ACTION_UP";
break;
}
default:
break;
}
return name;
}
class MyOnGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.i(getClass().getName(), "onSingleTapUp-----" +
getActionName(e.getAct ion()));
return false;
}
@Override
public void onLongPress(MotionEvent e) {
Log.i(getClass().getName(), "onLongPress-----" +
getActionName(e.getAction()));
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {
Log.i(getClass().getName(),"onScroll-----" +
getActionName(e2.getAction()) + ",(" + e1.getX() + "," +
e1.getY() + ") ,("+ e2.getX() + "," + e2.getY() + ")");
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.i(getClass().getName(),"onFling-----" +
getActionName(e2.getAction()) + ",(" + e1.getX() + "," + e1.getY()
+ ") ,("+ e2.getX() + "," + e2.getY() + ")");
return false;
}
@Override
public void onShowPress(MotionEvent e) {
Log.i(getClass().getName(), "onShowPress-----" +
getActionName(e.getAction()));
}
@Override
public boolean onDown(MotionEvent e) {
Log.i(getClass().getName(), "onDown-----" +
getActionName(e.getAction()));
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i(getClass().getName(), "onDoubleTap-----" +
getActionName(e.getAction()));
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
Log.i(getClass().getName(), "onDoubleTapEvent-----" +
getActionName(e.getAction()));
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i(getClass().getName(), "onSingleTapConfirmed-----" + getActionName(e.getAction()));
return false;
}
}
}
视图的样子就是一个空布局里面有一个button,准备工作都做好了。
- 我们来模拟一下单次点击事件:
这里由于笔者点击时抖动了一下,所以多调用了一次<code>onTouch</code>这并不影响我们观察,根据Log的顺序分析,首先调用了<code>onTouch</code>Motion是Down,之后马上调用<code>onDown</code>,Motion同上,这时我们应该把抬起来了,所以调用了<code>onTouch</code>而Motion是Up,最后调用<code>onSingleTapUp</code>是一次单击事件,而最后那个<code>onSingleTapComfirmed</code>方法是用来判断这就是一次点击,一旦调用这个方法,后面就不会出现两次点击(双击)这样的事件
,这里笔者有个问题:为什么调用<code>onSingleTapComfirmed</code>的Motion是Down而不是Up?
如果哪位大神指导这个问题,麻烦在评论区指点下,谢啦。
-
之后我们模拟一下双击的事件:
这里依旧出现了Move的Motion...还是不影响观察,继第一次点击之后观察,<code>onTouch</code>依旧调用这里就不再说了,注意下<code>onDoubleTap</code>他在我们按下去的时候就已经调用了,之后的方法<code>onDoubleTapEvent</code>就可以用来监听从双击第二次Down到第二次Up的所有事件。而且,如果调用了<code>onDoubleTap</code>,那之后就不能再调用<code>onSingleTapUp</code>和<code>onSingleTapComfirmed</code>了。
接下来是长按效果的模拟:
前面的都是一样的,从<code>onShowPress</code>开始,这个是一个按下不滑动时的调用,如果按的时间再长一点就会调用<code>onLongPress</code>这就是长按的实现。值得一提的是,如果长按执行了,直到用户Up,其他的事件都不会触发,如图就是笔者长按后移动后的Log。
- 再来是移动的模拟:
这里根据打印的Log可以发现,调用了<code>onScroll</code>,这个方法获取的坐标指的不是滑动的距离,而是距离上一次滑动的坐标。这里说的一次滑动指的是一整个事件。最后的<code>onFling</code>这个字面意思是“抛”,就是滑动后没有停下就离开屏幕,如果不想调用这个方法,在滑动之后要停一下,亲测有效。
- 最后一点值得注意的是,这些方法除了<code>onLongPress</code>没有返回值,其他的方法都有返回值通过<code>onTouchEvent</code>返回至<code>onTouch</code>。
理解这个类的事件回调顺序后,相信以后对用户的交互事件处理有点帮助。