Android GestureDetector★★★

本文详细介绍了Android中的GestureDetector类,包括其内部定义的OnGestureListener、OnDoubleTapListener和OnContextClickListener接口,以及SimpleOnGestureListener类。通过GestureDetector可以方便地监听和处理用户的触摸手势,如单击、滑动、长按、双击等。文章还讲解了如何使用GestureDetector,以及在多点触摸上下文中如何处理手势。
摘要由CSDN通过智能技术生成

1.GestureDetecor

用户触摸屏幕时会产生许多手势,一般通过重写View类的onTouch()方法可以处理一些触摸事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦,需要自己根据用户触摸的轨迹去判断是什么手势。

因此,Android sdk提供了GestureDetector类来监听手势发生,通过它的onTouchEvent(event)方法完成不同手势的识别。识别出手势后,不同的手势要怎么处理,再由开发者自己来实现。

GestureDetector类内部定义了三个接口和一个类,重写这些方法,就能实现传入触摸事件之后做出相应的回调:

①OnGestureListener接口

监听一些手势,如单击、滑动、长按等操作。

②OnDoubleTapListener接口

监听双击和单击事件。

③OnContextClickListener接口

当鼠标/触摸板,右键点击时候的回调。

④SimpleOnGestureListener 类

实现了上面三个接口的类,拥有上面三个的所有回调方法。

这些回调方法的返回值都是boolean类型,和View的事件传递机制一样,返回true表示消耗了事件,flase表示没有消耗。

其中,SimpleOnGestureListener是一个静态内部类,它实现了OnGestureListener、OnDoubleTapListener、OnContextClickListener三个接口。SimpleOnGestureListener类内重写了接口中的所有方法,但都是空实现,返回的布尔值都是false。这个类的主要作用就是方便继承这个类有选择的复写回调方法,而不是实现接口去重写所有的方法。

 

下面具体说说这几个接口:

①GesturetDetector.OnGestureListener 接口

public interface OnGestureListener {

    boolean onDown(MotionEvent e); // 由1个down触发,每按一下屏幕立即触发

    void onShowPress(MotionEvent e); //按下屏幕并且没有移动或松开,由1个down触发。注意和onDown()的区别,强调的是没有松开或者拖动的状态,而onDown()没有任何限制。主要是提供给用户一个可视化的反馈,告诉用户按下操作已经被捕捉到了。如果按下的速度很快只会调用onDown(),按下的速度稍慢一点会先调用onDown()再调用onShowPress()

  boolean onSingleTapUp(MotionEvent e); //一次单纯的轻击抬手动作时触发,由一个up触发。如果除了Down以外还有其他操作,比如触发了长按,这时候手抬起时,这个方法不执行

    boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX,float distanceY); // 屏幕拖动事件。手指按下并在屏幕上滑动时触发。这个事件由1个down,多个move触发。手指在屏幕上滑动时,会不断触发该方法。如果按下的时间过长,调用了onLongPress,再拖动屏幕不会触发onScroll。e1:开始拖动的第一次按下down操作,也就是第一个ACTION_DOWN;e2:触发当前onScroll方法的ACTION_MOVE,即当前滑动位置点;distanceX:当前x坐标与最后一次触发scroll方法的x坐标的差值,不是e1点到e2点的x轴距离;diastancY:当前y坐标与最后一次触发scroll方法的y坐标的差值,不是e1点到e2点的y轴距离

    void onLongPress(MotionEvent e); //长按。在down操作之后,过一个特定的时间触发 

    boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY); //按下屏幕,在屏幕上快速滑动后松开,由一个down、多个move、一个up触发。当滑动较慢时,只会触发onScroll,而不会触发onFling。e1:开始快速滑动的第一次按下down操作,也就是第一个ACTION_DOWN,即拖动事件的起点;e2:触发当前onFling方法的move操作,也就是最后一个ACTION_MOVE,即onFling()调用时手指的位置;velocityX:X轴上的移动速度,像素/秒;velocityY:Y轴上的移动速度,像素/秒

}

快按屏幕抬起:onDown —> onSingleTapUp —> onSingleTapConfirmed

慢按屏幕抬起:onDown –> onShowPress —> onSingleTapUp —> onSingleTapConfirmed

按下屏幕等待一段时间:onDown –> onShowPress –> onLongPress

拖动屏幕:onDown –> onShowPress –> onScroll(多个) –> onFling

快速滑动:onDown–>onScroll(多个)–>onFling

注意:当拖动速率velocityX或velocityY超过ViewConfiguration.getMinimumFlingVelocity()最小拖动速率时,才会调用onFling(),也就是说如果只拖动一点,或者慢慢的拖动,是不会触发该方法的。

②GesttureDetector.OnDoubleTapListener 接口

public interface OnDoubleTapListener {

    boolean onSingleTapConfirmed(MotionEvent e); //单击事件。用来判定该次点击是单纯的SingleTap而不是DoubleTap。如果连续点击两次就是DoubleTap手势,如果只点击一次,系统等待一段时间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap,然后触发SingleTapConfirmed事件。触发顺序是:OnDown->OnSingleTapUp->OnSingleTapConfirmed。关于onSingleTapConfirmed和onSingleTapUp的区别:onSingleTapUp只要手抬起就会执行,而对于onSingleTapConfirmed来说,如果双击的话,则onSingleTapConfirmed不会执行。

    boolean onDoubleTap(MotionEvent e); //双击事件。在第二次点击的down时触发。参数表示双击发生时,第一次按下时的down事件

   boolean onDoubleTapEvent( MotionEvent e); //双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作,包含down、up和move事件

}

下图是双击一下的Log输出:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_20,color_FFFFFF,t_70,g_se,x_16

从图中可以看出,在第二下点击时,先触发OnDoubleTap,然后再触发OnDown(第二次点击)。在触发OnDoubleTap以后,就开始触发onDoubleTapEvent了,onDoubleTapEvent后面的数字代表了当前的事件,0指ACTION_DOWN,1指ACTION_UP,2 指ACTION_MOVE。

双击顺序:onDown –> onSingleTapUp –> onDoubleTap –> onDoubleTapEvent –> onDown–> onDoubleTapEvent

③GesttureDetector.OnContextClickListener接口

public interface On context click Listener {

    boolean onContextClick(MotionEvent e);

}

④GestureDetector.SimpleOnGestureListener类

它与前面三个不同,这是一个类,并且实现了前三个接口,在它基础上新建类的话,要用extends派生而不是用implements继承。OnGestureListener和OnDoubleTapListener接口里的函数都是必须重写的,即使用不到也要重写一个空函数,但SimpleOnGestureListener类的实例或派生类中可以根据情况,用到哪个函数就重写哪个函数,因为SimpleOnGestureListener类本身已经实现了这两个接口的所有函数,只是里面全是空的而已。

 

2.GestureDetector使用方法

①第一步:根据需求创建onGestureListener、onDoubleTapListener或simpleOnGestureListener这三个类中的一个对象。比如只需要监听单击的话,那只需要得到实现了onGestureListener接口的对象;如果是双击,就只需要得到实现了onDoubleTapListener接口的对象;如果两种情况都需要考虑,就可以用SimpleOnGestureListener对象或者一个实现了上面两个接口的对象。

②第二步:创建一个GestureDetector对象,参数传入第一步的对象。

GestureDetector的构造函数如下:

public GestureDetector(Context context, OnGestureListener listener) {

    this(context, listener, null);

}

public GestureDetector(Context context, OnGestureListener listener, Handler handler) {

}

public GestureDetector(Context context, OnGestureListener listener, Handler handler,

        boolean unused) {

    this(context, listener, handler);

}

mGestureDetector = new GestureDetector( mContext, new MyGestureListener());

③第三步: 给view设置OnTouchListener监听,重写onTouch()方法,在return语句中写上mGestureDetector.onTouchEvent(event),将控制权交给GestureDector。

④第四步:绑定控件,给view设置setClickable(true)、setFocusable(true)、setLongClickable(true)。这一步非常重要,不然出不来效果。

注意:GestureDetector的构造方法中,有的构造函数需要多传递一个Handler作为参数,这个Handler主要是为了给GestureDetector提供一个Looper。带有handler参数,表示要在与该handler相关联的线程上,监听手势并处理延时事件。

通常情况下不需要这个Handler,因为它会在内部自动创建一个Handler用于处理数据。如果在主线程中创建GestureDetector,那么它内部创建的Handler会自动获得主线程的Looper;但是如果在一个没有创建Looper的子线程中创建 GestureDetector ,则需要传递一个带有Looper的Handler给它,否则就会因为无法获取到Looper导致创建失败。

下面是两种在子线程中创建GestureDetector的方法:

// 方式一:在主线程创建Handler

final Handler handler = new Handler();

new Thread(new Runnable() {

    @Override

    public void run() {

        final GestureDetector detector = new GestureDetector(this, new               GestureDetector.SimpleOnGestureListener() , handler);

        // ......

    }

}).start();

// 方式二:在子线程创建Handler,并指定Looper

new Thread(new Runnable() {

    @Override

    public void run() {

        final Handler handler = new Handler(Looper.getMainLooper());

        final GestureDetector detector = new GestureDetector(this, new               GestureDetector.SimpleOnGestureListener() , handler);

        // ......

    }

}).start();

使用其它创建Handler的方式也可以,重点是传递的Handler一定要有Looper。强调一下:重点是Handler中的Looper。假如子线程准备了Looper,则可以直接使用第 1 种构造函数进行创建:

new Thread(new Runnable() {

    @Override public void run() {

        Looper.prepare(); // <- 重点在这里

        final GestureDetector detector = new GestureDetector(this, new              GestureDetector.SimpleOnGestureListener());

        // ... 省略其它代码 ...

    }

}).start();

 

GestureDetector使用 完整代码:

public class MyActivity extends Activity implements View.OnTouchListener, GestureDetector.OnGestureListener,GestureDetector.OnDoubleTapListener{

    private GestureDetector mGestureDetector;

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        mGestureDetector = new GestureDetect

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值