GestureDetector类中定义了2个接口和一个空实现类,具体看源码:
public class GestureDetector {
/**
* The listener that is used to notify when gestures occur.
* If you want to listen for all the different gestures then implement
* this interface. If you only want to listen for a subset it might
* be easier to extend {@link SimpleOnGestureListener}.
*/
public interface OnGestureListener {
/**
* Notified when a tap occurs with the down {@link MotionEvent}
* that triggered it. This will be triggered immediately for
* every down event. All other events should be preceded by this.
*
* @param e The down motion event.
*/
boolean onDown(MotionEvent e);
/**
* The user has performed a down {@link MotionEvent} and not performed
* a move or up yet. This event is commonly used to provide visual
* feedback to the user to let them know that their action has been
* recognized i.e. highlight an element.
*
* @param e The down motion event
*/
void onShowPress(MotionEvent e);
/**
* Notified when a tap occurs with the up {@link MotionEvent}
* that triggered it.
*
* @param e The up motion event that completed the first tap
* @return true if the event is consumed, else false
*/
boolean onSingleTapUp(MotionEvent e);
/**
* Notified when a scroll occurs with the initial on down {@link MotionEvent} and the
* current move {@link MotionEvent}. The distance in x and y is also supplied for
* convenience.
*
* @param e1 The first down motion event that started the scrolling.
* @param e2 The move motion event that triggered the current onScroll.
* @param distanceX The distance along the X axis that has been scrolled since the last
* call to onScroll. This is NOT the distance between {@code e1}
* and {@code e2}.
* @param distanceY The distance along the Y axis that has been scrolled since the last
* call to onScroll. This is NOT the distance between {@code e1}
* and {@code e2}.
* @return true if the event is consumed, else false
*/
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
/**
* Notified when a long press occurs with the initial on down {@link MotionEvent}
* that trigged it.
*
* @param e The initial on down motion event that started the longpress.
*/
void onLongPress(MotionEvent e);
/**
* Notified of a fling event when it occurs with the initial on down {@link MotionEvent}
* and the matching up {@link MotionEvent}. The calculated velocity is supplied along
* the x and y axis in pixels per second.
*
* @param e1 The first down motion event that started the fling.
* @param e2 The move motion event that triggered the current onFling.
* @param velocityX The velocity of this fling measured in pixels per second
* along the x axis.
* @param velocityY The velocity of this fling measured in pixels per second
* along the y axis.
* @return true if the event is consumed, else false
*/
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}
/**
* The listener that is used to notify when a double-tap or a confirmed
* single-tap occur.
*/
public interface OnDoubleTapListener {
/**
* Notified when a single-tap occurs.
* <p>
* Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this
* will only be called after the detector is confident that the user's
* first tap is not followed by a second tap leading to a double-tap
* gesture.
*
* @param e The down motion event of the single-tap.
* @return true if the event is consumed, else false
*/
boolean onSingleTapConfirmed(MotionEvent e);
/**
* Notified when a double-tap occurs.
*
* @param e The down motion event of the first tap of the double-tap.
* @return true if the event is consumed, else false
*/
boolean onDoubleTap(MotionEvent e);
/**
* Notified when an event within a double-tap gesture occurs, including
* the down, move, and up events.
*
* @param e The motion event that occurred during the double-tap gesture.
* @return true if the event is consumed, else false
*/
boolean onDoubleTapEvent(MotionEvent e);
}
/**
* A convenience class to extend when you only want to listen for a subset
* of all the gestures. This implements all methods in the
* {@link OnGestureListener} and {@link OnDoubleTapListener} but does
* nothing and return {@code false} for all applicable methods.
*/
public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
public void onLongPress(MotionEvent e) {
}
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return false;
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
public void onShowPress(MotionEvent e) {
}
public boolean onDown(MotionEvent e) {
return false;
}
public boolean onDoubleTap(MotionEvent e) {
return false;
}
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
}
通过这个GestureDetector类我们可以识别很多的手势,虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的。
通常要用到GestureDetector类,需要在应用改类的View上或者Activity上传递MotionEvent对象,该对象,可以通过重写Activity的onTouchEvent方法或者通过重写View的setOnTouchListener方法来传递MotionEvent对象.
例如:
/**
* 使用手势识别器
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);//传递屏幕事件
return super.onTouchEvent(event);
}
或者:
/**
* 统一实现了手势滑动返回功能,如果要在OnTouchListener中做其他处理,则按照正常方式设置即可
*/
@Override
public void setOnTouchListener(OnTouchListener l) {
if (null == l) {
// 实现手势功能
l = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (null != gestureDetector) {
//传递触摸事件
return gestureDetector.onTouchEvent(event);
} else {
return false;
}
}
};
}
super.setOnTouchListener(l);
}
然后通过setOnTouchListener(null)即可
例子1:将OnGestureListener封装到工具类中,实现上,下,左,右的滑动监听处理,外部使用只需要传入我们自定义的回调接口,在相应的回调方法中处理业务逻辑即可.
public class GestureListenerHelper {
/**
* 如果需要手势,则调用该方法获取一个OnGestureListener
* @return
*/
public static GestureDetector.OnGestureListener getGestureListener(final Activity activity, final GestureOrientationListener listener){
if (null == activity){
return null;
}
return new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean flag = false;
if (SettingUtils.isOpenArticleGesture(activity)) {
flag = GestureListenerHelper.onFling(activity, e1, e2, velocityX, velocityY, 10*ViewConfiguration.get(activity).getScaledTouchSlop(), listener);
}
return flag;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
};
}
/**
* 手势滑动的处理
* @param activity
* @param e1 手指按下时的第一个位置
* @param e2 手指离开屏幕时的位置
* @param velocityX 水平方向移动速度,单位像素
* @param velocityY 垂直方向移动速度
* @param minTouchSlop 最小触发移动的距离
* @param listener 自定义监听器
* @return
*/
private static boolean onFling(Activity activity, MotionEvent e1, MotionEvent e2, float velocityX, float velocityY, final int minTouchSlop, final GestureOrientationListener listener) {
if (null != activity){
float x1 = e1.getX();
float x2 = e2.getX();
float y1 = e1.getY();
float y2 = e2.getY();
float absX = Math.abs(x1 - x2);
float absY = Math.abs(y1 - y2);
if (absX > absY){ //手势整体方向更倾向水平
if (absX > minTouchSlop){
if (x1 > x2){
listener.onLeft();
}else {
listener.onRight();
}
}
}else { //手势整体方向更倾向垂直
if (absY > minTouchSlop){
if (y1 > y2){
listener.onUp();
}else {
listener.onDown();
}
}
}
}
return false;
}
/**
* 自定义手势事件自处理接口
*/
public interface GestureOrientationListener{
void onUp();
void onDown();
void onLeft();
void onRight();
}
}
例如要对WebView控件设置向右滑动关闭当前Activity的操作,那么只需要自定义一个WebView继承系统的WebView控件.内部维护一个GestureDetector对象,然后重写setOnTouchListener方法和提供一个方法接收外部传递的OnGestureListener对象.代码如下:
package app.test;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebView;
/**
* Created by mChenys on 2015/11/23.
*/
public class MyWebView extends WebView {
private Context mContext;
private GestureDetector.OnGestureListener mGestureListener;//手势监听类
private GestureDetector gestureDetector; // 手势处理类
public MyWebView(Context context) {
this(context,null);
}
public MyWebView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
}
/**
* 对外提供设置手势监听器的方法
*
* @param onGestureListener
*/
public void setGestureListener(GestureDetector.OnGestureListener onGestureListener) {
this.mGestureListener = onGestureListener;
if (null != mGestureListener) {
gestureDetector = new GestureDetector(mContext, mGestureListener);
}
setOnTouchListener(null);
}
/**
* 重写setOnTouchListener方法
* 统一实现了手势滑动返回功能
*/
@Override
public void setOnTouchListener(OnTouchListener l) {
if (null == l) {
// 实现手势功能
l = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (null != gestureDetector) {
//传递触摸事件
return gestureDetector.onTouchEvent(event);
} else {
return false;
}
}
};
}
super.setOnTouchListener(l);
}
}
/**
* Created by mChenys on 2015/11/23.
*/
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyWebView webView = new MyWebView(this);
webView.setGestureListener(GestureListenerHelper.getGestureListener(this, new GestureListenerHelper.GestureOrientationListener() {
@Override
public void onUp() {
}
@Override
public void onDown() {
}
@Override
public void onLeft() {
}
@Override
public void onRight() {
//向右滑动,退出Activity
onBackPressed();
}
}));
setContentView(webView);
webView.loadUrl("http://blog.youkuaiyun.com/mChenys");
}
}
例子2:通过抽取一个抽象的Activity,内部维护GestureDetector对象,处理左右滑动事件,其他Activity只要有左右滑动的需求,只需要继承该抽象的Activity,实现左右滑动的抽象方法即可.
代码:
public abstract class BaseGrideActivity extends Activity {
//手势识别器
protected GestureDetector detector;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//实例化手势识别器
detector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
/**
* 滑动时会回调
* @param e1 :手指按下时的第一个位置
* @param e2 :手指离开屏幕时的位置
* @param velocityX :水平方向移动速度,单位像素
* @param velocityY :垂直方向移动速度
* @return
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//屏蔽斜滑的手势
if (Math.abs(e1.getRawY() - e2.getRawY()) > 100) {
return true;
}
//屏蔽在X方向滑动很慢的情况
if (Math.abs(velocityX) < 200) {
return true;
}
if ((e2.getRawX() - e1.getRawX() > 200)) {
//显示上一个页面:从左到右滑动
LogUtil.d("chenys", "显示上一个页面:从左到右滑动");
gesturePre();
return true;
}
if ((e1.getRawX() - e2.getRawX()) > 200) {
//显示下一个页面:从右到左滑动
Log.d("chenys", "显示下一个页面:从右到左滑动");
gestureNext();
return true;
}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
}
/**
* 使用手势识别器
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);//传递屏幕事件
return super.onTouchEvent(event);
}
/**
* 滑动到下一页
*/
public abstract void gestureNext();
/**
* 滑动到上一页
*/
public abstract void gesturePre();
}