Android 手势

2015-12-17 党洁 更多博文 » 博客 » GitHub »

原文链接 https://jiedang.github.io/2015/12/17/Android%E6%89%8B%E5%8A%BF%E8%AF%A6%E8%A7%A3%E5%92%8C%E4%BD%BF%E7%94%A8.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


手势

什么是手势

其实就是 onTouchEvent 中用,去识别判断出用户当前操作是个啥行为,是双击,长按,滑动,缩放,抛掷这些,然后做相应的操作,业务。

识别手势

  • 如何确定手势操作时间 ?(长按多久,双击间隔多久)
  • 如何确定手势距离 ?(移动长度大于多少算移动,小于多少算点击)
  • 如何确定连续加速度 ?(滑动加减速,抛掷后续补全)

当然系统有在ViewConfiguration 里面有设定这些操作的默认值,但是自身去识别具体那个手势,处理,逻辑太复杂,庞大,划不来。

想明白手势,首先需要有基础的事件分发知识,知道VIEW TREE 对于事件的处理,怎么去持有消耗一个事件,避免使用时候出现,“为啥我这个手势没有被触发啊,没有回调啊?”这些问题。

系统提供方法

系统在API 1就添加了手势类GestureDetector 支持识别手势:

  public interface OnGestureListener {
    boolean onDown(MotionEvent e);

    void onShowPress(MotionEvent e);

    boolean onSingleTapUp(MotionEvent e);

    boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);


    void onLongPress(MotionEvent e);


    boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}

public interface OnDoubleTapListener {

    boolean onSingleTapConfirmed(MotionEvent e);


    boolean onDoubleTap(MotionEvent e);


    boolean onDoubleTapEvent(MotionEvent e);
}

对于如何在ontouchEvent中判断出这些手势可以参考 grepcode中源码,不复杂,繁琐些。主要讲使用,

GestureDetector怎么用(listener方式)

  1. 添加回调listenter"OnGestureListener"或者“OnDoubleTapListener”根据需要监控的手势
  2. 在你自定的view的onToucheEvent调用对应listener类似

    public boolean onTouchEvent( MotionEvent event ) {
       boolean gestureIntercept = mGestureDetector.onTouchEvent(event);
       return gestureIntercept  ||  super.onTouchEvent( event );
    }
    
  3. 根据你要监控手势的层级,在listener各层级手势中返回true(接受事件),比如你要监听双击,那想当然的单击时间就必须接受,以此类推。

  4. tips: 有时候只是想简单的监控一个手势,实现"OnGestureListener"需要填写太多方法,感觉繁琐,系统有提供一个GestureDetector的内部类SimpleOnGestureListener已经实现了对应借口,简单的extends,复写相关方法就好了,代码量少很多。

GestureDetector怎么用(handler方式)

  1. 通过构造器添加handler。
  2. 在handler里面处理message

private static final int SHOW_PRESS = 1;

private static final int LONG_PRESS = 2;

private static final int TAP = 3;

这种方式用的很少,有特殊需求可以参考。

V4对于低版本的适配

可以参考系统V4对于低版本的实现 GestureDetectorCompat,(源码中以compat结尾的都是Android系统自身对于低版本的适配类),使用方式和GestureDetector一样,都是丢入一个"OnGestureListener"和“OnDoubleTapListener”回调。

  • 奇怪的是GestureDetector API 1就添加了,为什么还有一个GestureDetectorCompat做版本适配尼,可能有更好的兼容,后面有发现补充

GestureDetectorCompat中包含两个子类,GestureDetectorCompatImplBaseGestureDetectorCompatImplJellybeanMr2,分别是适配低版本,和API 17以上的版本,前者是处理事件判断出对应手势,后者是使用GestureDetector来实现内部判断。后面开发中如果需要在手势中 做些特别处理,可以复制GestureDetectorCompatImplBase实现做基础,然后修改。

关于加速度 VelocityTracker使用

  1. onTouchEvent中 初始化

        if (mVelocityTracker == null) {
                  mVelocityTracker = VelocityTracker.obtain();
            }
            mVelocityTracker.addMovement(ev);
    
  2. 设置大小范围 可以参考

     mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity();
     mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
    
  3. 在onTouchEvent的ActionUp里面获取加速完后的XY移动量。

        //计算
        mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
        //获取是那根手指和手指ID
        final int upIndex = ev.getActionIndex();
        final int id1 = ev.getPointerId(upIndex);
        //获取加速完后的偏移量XY
        final float x1 = mVelocityTracker.getXVelocity(id1);
        final float y1 = mVelocityTracker.getYVelocity(id1);
    

缩放手势 ScaleGestureDetector

GestureDetector实现完全相同,使用也一样,都有“OnScaleGestureListener”和“SimpleOnScaleGestureListener”,也在V4中有适配类 ScaleGestureDetectorCompat,参照GestureDetector使用学习就好了。