android之GestureDetector

今天来详细说一下android中常常使用的GestureDetector。先来看看google对GestureDetector的介绍:

/**
 * Detects various gestures and events using the supplied {@link MotionEvent}s.
 * The {@link OnGestureListener} callback will notify users when a particular
 * motion event has occurred. This class should only be used with {@link MotionEvent}s
 * reported via touch (don‘t use for trackball events).
 *
 * To use this class:
 * <ul>
 *  <li>Create an instance of the {@code GestureDetector} for your {@link View}
 *  <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call
 *          {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback
 *          will be executed when the events occur.
 * </ul>
 */
上面主要说了GestureDetector的作用和使用方法,这里我先做一下大意的翻译:GestureDetector可以通过view的onTouchEvent带回的MotionEvent来判断出特殊的手势,当检测到有特殊的手势发生时,就会回调对应的特殊方法来告知用户。

从上述可以知道,对于GestureDetector的使用主要有两个地方需要我们自己来做:

(1)在需要检测手势的view或者activity等 ,需要在其onTouchEvent(MotionEvent event)方法里面实时将event信息传递给你的GestureDetector对象,比如下来这样:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        return this.detector.onTouchEvent(event);
    }
(2)上面说,当有特殊的手势时候会调用特殊的回调方法,所以这里还需要我们去写对于特殊手势的回调函数。GestureDetector里面定义了不同的接口函数来对应不同的手势。所以我们只需要实现GestureDetector里面的手势接口方法即可。

GestureDetector的手势接口分两种:OnGestureListener主要处理单点触摸、OnDoubleTapListener主要是处理两点触摸。一般情况,你希望用到那一种就实现一种的接口就可以了。然后把实现手势接口的对象传递给你的GestureDetector就可以了。

在GestureDetector.java有其对GestureDetector的定义,从中可以看到定义的一个变量    private final OnGestureListener mListener; 其中mListener就是指向我们自己实现手势接口的对象。我们来看看GestureDetector的一个最终的构造函数:

    public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
        if (handler != null) {
            mHandler = new GestureHandler(handler);
        } else {
            mHandler = new GestureHandler();
        }
        mListener = listener;
        if (listener instanceof OnDoubleTapListener) {
            setOnDoubleTapListener((OnDoubleTapListener) listener);
        }
        init(context);
    }


下面我们来一个实例(一个手电筒APP中用到的GestureDetector):

public class LightActivity extends Activity implements OnTouchListener, OnGestureListener {

    private static String MY_PKG_NAME = "com.android.camera";

    private LinearLayout mlayout;

    private GestureDetector detector; // 申明一个GestureDetector 

...
...
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_light);

        CloseCamera();
        mlayout = (LinearLayout) findViewById(R.id.mlayou);
        detector = new GestureDetector(this); // 实例化一个对象,这里传递的是LightActivity对象,因为LightActivity实现了OnGestureListener 接口



        Resources resources = this.getResources();
...
...
}
...
...
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        return this.detector.onTouchEvent(event); //  这里实时将MotionEvent 传递给我们的detector


    }
...
...
// 下面你的几个方法是实现接口OnGestureListener

    @Override
    public boolean onDown(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        // TODO Auto-generated method stub
        // ????????????
        /*
         * if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE && Math.abs(velocityX)
         * > FLING_MIN_VELOCITY) { if (IsOpenFlash) { // Fling left
         * mVibrator.vibrate(off, -1); closeFlashLight();
         * mlayout.setBackgroundDrawable(mdrawable_off); } } else if (e2.getX()
         * - e1.getX() > FLING_MIN_DISTANCE && Math.abs(velocityX) >
         * FLING_MIN_VELOCITY) { if (!IsOpenFlash) { // Fling right
         * mVibrator.vibrate(on, -1); openFlashLight();
         * mlayout.setBackgroundDrawable(mdrawable_on); } }
         */
        return false;
    }
    @Override
    public void onLongPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        // TODO Auto-generated method stub
        // 锟斤拷锟斤拷
        if ((e1.getY() > MAX_UP && e2.getY() < MAX_DOWN)
                && (e1.getX() > MAX_LEFT && e2.getX() < MAX_RIGHT)) {
            if (e1.getY() - e2.getY() > FLING_MIN_DISTANCE
                    && Math.abs(distanceY) > FLING_MIN_VELOCITY) {
                if (!IsOpenFlash) {
                    // Fling up
                    mVibrator.vibrate(on, -1);
                    openFlashLight();
                    mlayout.setBackgroundDrawable(mdrawable_on);
                }
            } else if (e2.getY() - e1.getY() > FLING_MIN_DISTANCE
                    && Math.abs(distanceY) > FLING_MIN_VELOCITY) {
                if (IsOpenFlash) {
                    // Fling down
                    mVibrator.vibrate(off, -1);
                    closeFlashLight();
                    mlayout.setBackgroundDrawable(mdrawable_off);
                }
            }
        }
        return false;
    }
    @Override
    public void onShowPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }
...
...
}
最后我们来介绍一下GestureDetector的手势接口方法:

(1)OnGestureListener

boolean onDown(MotionEvent e);  // 点击时候一触摸到屏就会发生

void onShowPress(MotionEvent e); // 在点击触摸到屏时候、并且move or up都还没有发生时候 就会发生。其实就是在onDown之后,原则上第一个会发生的手势。

boolean onSingleTapUp(MotionEvent e); // 当单个点击触摸屏UP(离开)的时候发生的手势,这里为什么是SingleTap呢? 就是要区别多点触摸,所以这里其实是指只有一个手指触摸屏时候,up(离开屏)的时候发生的手势。

void onLongPress(MotionEvent e);// 长按手势

boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);// 是指触摸屏的时候,在屏上面滑动的时候发生的手势,其实上是在MotionEvent.ACTION_MOVE的时候才会发生的手势。

boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY); // 这个和onScroll不一样,这个主要是用于识别用户在move的时候,突然UP的时候才会发生的手势。velocityX 和velocityY是指速率(这里是一个second移动的距离);MotionEvent e1当前这个手势发生的down motion event ;MotionEvent e2 发生这个手势的move motion event。onFling主要用于判断用户的意图,

对于onFling和onScroll我们来举例说明: onScroll一般用于识别用户对图片的放大、缩小意图;onFling常用于识别用户看电子 书的时候翻页的意图。

(2)OnDoubleTapListener:

boolean onSingleTapConfirmed(MotionEvent e); //  确认只是一次点击的时候发生的手势,这里其实是第一次点击后,一段时间内没有再收到一个一个点击,则发生该手势。这里的一段时间其实就是一点确认是否是双击的时间:ViewConfiguration.getDoubleTapTimeout()。在ViewConfiguration.java里面有其定义时间长度:

    /**
     * Defines the duration in milliseconds between the first tap‘s up event and
     * the second tap‘s down event for an interaction to be considered a
     * double-tap.
     */
    private static final int DOUBLE_TAP_TIMEOUT = 300;

boolean onDoubleTap(MotionEvent e);// 双击的时候发生的手势。参数:MotionEvent e 是指第一次点击的事件。

boolean onDoubleTapEvent(MotionEvent e);// // 双击发生的过程中发生的手势。


其实GestureDetector的处理核心代码是public boolean onTouchEvent(MotionEvent ev),这个方法做了所有对手势的检测和区分。如还是不太理解各个手势是如何发生的话可以去看看这个方法。



android之GestureDetector,布布扣,bubuko.com

android之GestureDetector

上一篇:android monkey 命令详解


下一篇:iOS从入门到精通之 :协议(protocol)