在我们平常的使用当中会只用到很多的手势,DOWN,MOVE,UP,SCROLL,FLING等等,当然在我们之前的理解中使用View的onTouchEvent好像都可以解决,但是在实现的逻辑上也许就会非常的复杂了。所以Android为我们更加方便实现复杂的手势操作提供了GestureDetector这个类。
DestureDetector对外提供了两个接口(OnGestureDetector、OnDoubleTapListener)和一个外部类(SimpleOnGestureListener)。
首先我们查看该接口内需要实现的方法如下:
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);
各种点击所触发的事件:
从这个listener中的实现方法我们知道这个接口的作用是监听一些手势,单击、滑动、拖动、长按等等
看看这个接口的内部实现:
/**
*可以确认这是一个单击事件而不是一个双击事件的时候回调
*/
boolean onSingleTapConfirmed(MotionEvent e);
/**
* 可以确认这是一个双击事件的时候回调
*/
boolean onDoubleTap(MotionEvent e);
/**
*onDoubleTap()回调之后的输入事件(MOVE,UP,DOWN)都会回调这个方法
*这个方法可以实现一些双击后的控制,让View双击后变得可拖动等
*/
boolean onDoubleTapEvent(MotionEvent e);
通过查看接口的内部代码我们知道,这个listener主要实现监听点击事件和双击事件
在这个方法内部只有这样一个方法:
/**
* 外接键盘的鼠标右键,当鼠标右键点击的时候回调
*/
boolean onContextClick(MotionEvent e)
这个接口其实就是实现上面三个方法的综合,拥有上面三个接口的所有回调方法
下面就用一个实例来展示如何使用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;
}
}
}
代码很简单就只是在每个方法内部打印了一下日志:
单击事件:
双击事件:
滑动:
以上就是我么执行单击,双击,拖动等事件的的结果,当然我们打印日志是为了更好地使用它,在这个方法的内部我们可以执行我们需要用的方法或事件。
这个是一个类,使用时只能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 |