GestureDetector手势检测器的使用

本文详细介绍GestureDetector类的使用方法,包括其内部接口OnGestureListener和OnDoubleTapListener的定义及功能,展示了如何实现屏幕滑动监听,提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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)即可


那么如何使用GestureDetector类实现屏幕的上,下,左,右的滑动监听呢? 

例子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();
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值