zoukankan      html  css  js  c++  java
  • Android 手势识别——单击/双击

    为什么需要手势识别?

          手势对于我们的app有很多的地方都在使用,比如右滑关闭界面等。手势控制分为触发动作(Touch Mechanics,用户手指在屏幕上如何动作)和触发行为(Touch Activities,界面上特定动作在特定情境下引发的结果)。这是因为同样的触发动作(如单次触击)在不同情境下可能会带来不同的结果(如轻触,取消,开启/关闭指示),同样单次触发行为(如放大)可能是由多种触发动作(如捏放,双次触击,双次触击拖拽等)实现。

         一般情况下,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。

         Android sdk给我们提供了GestureDetector类,通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的。

    GestureDetector这个类对外提供了两个接口和一个外部类,用于监听不同的手势
    接口: OnGestureListener, OnDoubleTapListener
    内部类: SimpleOnGestureListener

    1、实现 GestureDetector.OnGestureListener

    private class gesturelistener implements GestureDetector.OnGestureListener{
    
        public boolean onDown(MotionEvent e) {
            // TODO Auto-generated method stub  
            return false;
        }
    
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub  
    
        }
    
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub  
            return false;
        }
    
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            // TODO Auto-generated method stub  
            return false;
        }
    
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub  
    
        }
    
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            // TODO Auto-generated method stub  
            return false;
        }
    
    }

    实现该接口时,需要重载六个函数。 下面讲解一下这六个函数的触发条件(具体参看源码中的注释):

    • OnDown(MotionEvent e):用户按下屏幕就会触发;
    • onShowPress(MotionEvent e):如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行。官方的注释如下:
     /**
             * 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
             */
    • onLongPress(MotionEvent e):长按触摸屏,超过一定时长,就会触发这个事件
      触发顺序:
          onDown->onShowPress->onLongPress
    • onSingleTapUp(MotionEvent e):从名子也可以看出,一次单独的轻击抬起操作,也就是轻击一下屏幕,立刻抬起来,才会有这个触发,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以也就不会触发这个事件
          触发顺序:
          点击一下非常快的(不滑动)Touchup:
          onDown->onSingleTapUp->onSingleTapConfirmed
          点击一下稍微慢点的(不滑动)Touchup:
          onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
    • onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) :滑屏,用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发  
      参数解释:(当滑动屏幕的速度较慢时,该方法不会被调用)
          e1:第1个ACTION_DOWN MotionEvent
          e2:最后一个ACTION_MOVE MotionEvent
          velocityX:X轴上的移动速度,像素/秒
          velocityY:Y轴上的移动速度,像素/秒  

    注: 可以通过该函数里的滑动距离和滑动速度,判断是左滑还是右滑

    • onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY):在屏幕上拖动事件。无论是用手拖动view,或者是以抛的动作滚动,都会多次触发,这个方法       在ACTION_MOVE动作发生时就会触发
          滑屏:手指触动屏幕后,稍微滑动后立即松开
          onDown-----》onScroll----》onScroll----》onScroll----》………----->onFling
          拖动(当滑动的速度不是很快的时候,onFling函数最后不会被调用。)
          onDown------》onScroll----》onScroll

     

    2、实现OnDoubleTapListener

    /**
    * The listener that is used to notify when a double-tap or a confirmed
    * single-tap occur.
    */

        OnGestureListener实现了单击相关的手势识别,对于双击相关的手势识别需要单独实现,下面具体介绍里面的几个方法:

     private GestureDetector.OnDoubleTapListener mOnDoubleTapListener = new GestureDetector.OnDoubleTapListener() {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                logger("onSingleTapConfirmed:");
                return false;
            }
    
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                logger("onDoubleTap:");
                return false;
            }
    
            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
                logger("onDoubleTapEvent:"+MotionEvent.actionToString(e.getAction()));
                return false;
            }
        };

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

    onDoubleTap(MotionEvent e):双击事件

    onDoubleTapEvent(MotionEvent e):双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作,包含down、up和move事件;下图是双击一下的Log输出:

    3、实现SimpleOnGestureListener

    /**
         * 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}, {@link OnDoubleTapListener}, and {@link OnContextClickListener}
         * but does nothing and return {@code false} for all applicable methods.
         */
        public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,OnContextClickListener{…..}

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

    4、通过兼容包中工具识别手势

    GestureDetector属于android.view包,android还提供了android.gesture包支持更多的手势操作。官方的介绍中使用了GestureDetectorCompat处理手势识别。 在识别手势的时候尽量使用 兼容包中手势识别。

    public class MainActivity extends Activity implements
            GestureDetector.OnGestureListener,
            GestureDetector.OnDoubleTapListener{
    
        private static final String DEBUG_TAG = "Gestures";
        private GestureDetectorCompat mDetector;
    
        // Called when the activity is first created. 
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // Instantiate the gesture detector with the
            // application context and an implementation of
            // GestureDetector.OnGestureListener
            mDetector = new GestureDetectorCompat(this,this);
            // Set the gesture detector as the double tap
            // listener.
            mDetector.setOnDoubleTapListener(this);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event){
            this.mDetector.onTouchEvent(event);
            // Be sure to call the superclass implementation
            return super.onTouchEvent(event);
        }
    
        @Override
        public boolean onDown(MotionEvent event) {
            Log.d(DEBUG_TAG,"onDown: " + event.toString());
            return true;
        }
    
        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2,
                float velocityX, float velocityY) {
            Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString());
            return true;
        }
    
        @Override
        public void onLongPress(MotionEvent event) {
            Log.d(DEBUG_TAG, "onLongPress: " + event.toString());
        }
    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                float distanceY) {
            Log.d(DEBUG_TAG, "onScroll: " + e1.toString()+e2.toString());
            return true;
        }
    
        @Override
        public void onShowPress(MotionEvent event) {
            Log.d(DEBUG_TAG, "onShowPress: " + event.toString());
        }
    
        @Override
        public boolean onSingleTapUp(MotionEvent event) {
            Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());
            return true;
        }
    
        @Override
        public boolean onDoubleTap(MotionEvent event) {
            Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
            return true;
        }
    
        @Override
        public boolean onDoubleTapEvent(MotionEvent event) {
            Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());
            return true;
        }
    
        @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {
            Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
            return true;
        }
    }
    View Code

    有两个构造方法:一个构造方法入上述手势识别的代码,另一种增加了一个Handler参数,如下:

    image

  • 相关阅读:
    指示函数
    Sql Server中的日期与时间函数
    http://www.jb51.net/softjc/33896.html(vs2010破解)
    什么是VC维?
    smalldatetime和datetime的差别
    基于大规模语料的新词发现算法
    向setInterval , setTimeout调用的函数传递参数
    取指定月份的天数
    SQL 写循环数据
    JavaScript事件一瞥
  • 原文地址:https://www.cnblogs.com/NeilZhang/p/8149186.html
Copyright © 2011-2022 走看看