• Android手势识别01基本手势的处理
  • 一简介
  • 二按下显示按下单击滚动长按快掷手势
  • 1 activity_base_testxml
  • 2 BaseTestActivityjava
  • 3 图示
  • 4 方法分析和说明
  • 三双击手势
  • 1 使用 GestureDetectorOnDoubleTapListener
  • 2 使用 GestureDetectorSimpleOnGestureListener
  • 3 图示
  • 四GestureDetectorSimpleOnGestureListener
  • 五缩放手势
  • 1 ScaleGestureActivityjava
  • 2 图示
  • 六拖拽
  • 1 自己处理按下移动的动作重写onTouchEvent事件
  • 2 使用手势
  • 3 图示
  • 七源码

Android手势识别01——基本手势的处理

一、简介

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

手势手势 Android 1.6 中加入的。手势还有支持库,尽量使用支持库。

基本手势的使用步骤一般如下:

  1. 创建手势的监听类(可以继承自GestureDetector.OnGestureListener,或者继承自GestureDetector.SimpleOnGestureListener)
  2. 创建手势的探测器,如mGestureDetector = new GestureDetectorCompat(this,mOnGestureListener);
  3. 重写Activity或者View的onTouchEvent的方法,在其中调用探测器的onTouchEvent方法如

@Override public boolean onTouchEvent(MotionEvent event) { mGestureDetector.onTouchEvent(event); return super.onTouchEvent(event); }

二、按下、显示按下、单击、滚动、长按、快掷手势

按下、显示按下、单击、滚动、长按、快掷这些手势我们可以可使用 GestureDetector.OnGestureListener或者GestureDetector.SimpleOnGestureListener来进行监听,请看下面的例子

2.1 activity_base_test.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/base_tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

2.2 BaseTestActivity.java

/**
 * <b>Project:</b> gesturedemo<br>
 * <b>Create Date:</b> 2017/4/25<br>
 * <b>Author:</b> qiwenming<br>
 * <b>Description:</b>
 *  基本手势测试
 * <br>
 */
public class BaseTestActivity extends BaseActivity {

    private static final String TAG = "BaseTestActivity";
    private GestureDetectorCompat mGestureDetector;
    private TextView mBaseTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base_test);
        mBaseTv = (TextView)findViewById(R.id.base_tv);
        mGestureDetector = new GestureDetectorCompat(this,mOnGestureListener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

   private GestureDetector.OnGestureListener mOnGestureListener = new GestureDetector.OnGestureListener() {
       @Override
       public boolean onDown(MotionEvent mCurrentDownEvent) {
           logger("onDown: ");
           Log.i(TAG, "onDown: ");
           return true;
       }

       @Override
       public void onShowPress(MotionEvent mCurrentDownEvent) {
           logger("onShowPress: ");
           Log.i(TAG, "onShowPress: ");
       }

       @Override
       public boolean onSingleTapUp(MotionEvent mCurrentDownEvent) {
           logger("onSingleTapUp: ");
           Log.i(TAG, "onSingleTapUp: ");
           return false;
       }

       @Override
       public boolean onScroll(MotionEvent mCurrentDownEvent, MotionEvent motionEvent1, float velocityX, float velocityY) {
           logger("onScroll: "+velocityX+"     ,     "+velocityY);
           Log.i(TAG, "onScroll: "+velocityX+"     ,     "+velocityY);
           return false;
       }

       @Override
       public void onLongPress(MotionEvent mCurrentDownEvent) {
           logger("onLongPress: ");
           Log.i(TAG, "onLongPress: ");
       }

       @Override
       public boolean onFling(MotionEvent mCurrentDownEvent, MotionEvent motionEvent1, float velocityX, float velocityY) {
           Log.i(TAG, "onFling: "+velocityX+"----"+velocityY);
           logger("onFling: "+velocityX+"     ,     "+velocityY);
           //右滑关闭acitivity
           if(velocityX > 10 && velocityX > Math.abs(velocityY)) {
               finish();
           }
           return true;
       }
   };

    private void logger(String msg){
        String log = mBaseTv.getText()+"\n"+msg;
        if(log.split(":").length>30){
            log = msg;
        }
        mBaseTv.setText(log);
    }
}

2.3 图示

android frament手势滑动 安卓手势_android frament手势滑动


2.4 方法分析和说明

事件

说明

onDown

只要按下,这个方法就会执行,也就是说我们的手势中,这个方法一定会执行。

onShowPress

已经按下,但是没有移动或者抬起。此事件通常用于提供视觉反馈给用户,让他们知道他们的行动已经认可即突出元素。

onSingleTapUp

敲击手势的事件

onScroll

滚动。 velocityX说明:左→右 => 负值,右→左 => 正值;velocityY说明:上→下 => 负值,下→上 => 正值

onLongPress

长按

onFling

快掷。


三、双击手势

双击手势我们使用的监听是GestureDetector.OnDoubleTapListener或者GestureDetector.SimpleOnGestureListener,想多来说我们使用GestureDetector.SimpleOnGestureListener方便一点。

3.1 使用 GestureDetector.OnDoubleTapListener

BaseTestActivity.java

/**
 * <b>Project:</b> gesturedemo<br>
 * <b>Create Date:</b> 2017/4/26<br>
 * <b>Author:</b> qiwenming<br>
 * <b>Description:</b>
 * 双击手势
 * <br>
 */
public class DoubleTapActivity extends BaseTestActivity {

    private TextView mTv;
    private GestureDetectorCompat mGestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_double_tap);
        mTv = (TextView)findViewById(R.id.doubletap_tv);
        mGestureDetector = new GestureDetectorCompat(this,mOnGestureListener);
        mGestureDetector.setOnDoubleTapListener(mOnDoubleTapListener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    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;
        }
    };

    private GestureDetector.OnGestureListener mOnGestureListener = new GestureDetector.OnGestureListener() {
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public void onShowPress(MotionEvent e) {

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    };

    private void logger(String msg){
        String log = mTv.getText()+"\n"+msg;
        if(log.split(":").length>30){
            log = msg;
        }
        mTv.setText(log);
    }
}

3.2 使用 GestureDetector.SimpleOnGestureListener

我们看到,如果我们使用的是GestureDetector.OnGestureListener,我们需要添加两个监听。而我们使用GestureDetector.SimpleOnGestureListener,就会简单好多。

/**
 * <b>Project:</b> gesturedemo<br>
 * <b>Create Date:</b> 2017/4/26<br>
 * <b>Author:</b> qiwenming<br>
 * <b>Description:</b>
 * 双击手势
 * <br>
 */
public class DoubleTapActivity extends BaseTestActivity {

    private TextView mTv;
    private GestureDetectorCompat mGestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_double_tap);
        mTv = (TextView)findViewById(R.id.doubletap_tv);
        mGestureDetector = new GestureDetectorCompat(this,mDoubleSimpGestureListener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    private GestureDetector.SimpleOnGestureListener mDoubleSimpGestureListener = new GestureDetector.SimpleOnGestureListener(){
        @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;
        }
    };

    private void logger(String msg){
        String log = mTv.getText()+"\n"+msg;
        if(log.split(":").length>30){
            log = msg;
        }
        mTv.setText(log);
    }
}

3.3 图示

android frament手势滑动 安卓手势_按下显示按下_02


四、GestureDetector.SimpleOnGestureListener

上面我们总是说使用 GestureDetector.SimpleOnGestureListener更为方便一点,我们可以看看这个类

public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
            OnContextClickListener {

        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;
        }

        public boolean onContextClick(MotionEvent e) {
            return false;
        }
    }

通过上面我们可以看到这个类实现了:GestureDetector.OnGestureListener,GestureDetector.OnDoubleTapListener,GestureDetector.OnContextClickListener,这三个接口,也就是说如果我们是使用到上的上面的手势那么我们可以使用GestureDetector.SimpleOnGestureListener


五、缩放手势

缩放手势,我们使用的是ScaleGestureDetector和ScaleGestureDetector.OnScaleGestureListener

其中ScaleGestureDetector中的getScaleFactor()是用来获取缩放比例的,这个比例是相对于上一次的缩放比例

5.1 ScaleGestureActivity.java

/**
 * <b>Project:</b> YuantaiApplication<br>
 * <b>Create Date:</b> 2017/4/26<br>
 * <b>Author:</b> qiwenming<br>
 * <b>Description:</b> <br>
 *     缩放手势
 */
public class ScaleGestureActivity extends BaseActivity {

    private View mView;
    private ScaleGestureDetector mScaleGestureDetector;
    private static final String TAG = "ScaleGestureActivity";
    private float mScaleFactor = 1.0f;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scale_gesture);
        mView = findViewById(R.id.scale_view);
        mScaleGestureDetector = new ScaleGestureDetector(this,mScaleGestureListener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mScaleGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    private ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener = new ScaleGestureDetector.OnScaleGestureListener() {
        @Override
        public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
            mScaleFactor  *= scaleGestureDetector.getScaleFactor();
            mView.setScaleX(mScaleFactor);
            mView.setScaleY(mScaleFactor);
            Log.i(TAG, "onScale: "+ scaleGestureDetector.getScaleFactor()+"----"+mScaleFactor);
            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {

        }
    };
}

5.2 图示

android frament手势滑动 安卓手势_按下显示按下_03


六、拖拽

拖拽我们使用的其实就是手势中的滚动。

6.1 自己处理按下移动的动作,重写onTouchEvent事件

DragTestActivity.java

/**
 * <b>Project:</b> YuantaiApplication<br>
 * <b>Create Date:</b> 2017/4/26<br>
 * <b>Author:</b> qiwenming<br>
 * <b>Description:</b>
 * 拖拽
 * <br>
 */
public class DragTestActivity extends BaseActivity {

    private View mView;
    private GestureDetectorCompat mGestureDetectorCompat;
    private static final String TAG = "DragTestActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drag_test);
        mView = findViewById(R.id.drag_view);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        onMyDrag(event);
        return super.onTouchEvent(event);
    }


    private float mLastX = 0;
    private float mLastY = 0;
    private float mOffsetX = 0;
    private float mOffsetY = 0;
    public void onMyDrag(MotionEvent event){
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                mLastX = event.getX();
                mLastY = event.getY();
                Log.i(TAG, "onMyDrag:ACTION_DOWN  "+event.getX()+"  ,  "+event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                mOffsetX += event.getX()-mLastX;
                mOffsetY += event.getY()-mLastY;
                mLastX = event.getX();
                mLastY = event.getY();
                mView.setTranslationX( mOffsetX );
                mView.setTranslationY( mOffsetY );
                break;
        }
    }
}

6.2 使用手势

DragTestActivity.java

/**
 * <b>Project:</b> YuantaiApplication<br>
 * <b>Create Date:</b> 2017/4/26<br>
 * <b>Author:</b> qiwenming<br>
 * <b>Description:</b>
 * 拖拽
 * <br>
 */
public class DragTestActivity extends BaseActivity {

    private View mView;
    private GestureDetectorCompat mGestureDetectorCompat;
    private static final String TAG = "DragTestActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drag_test);
        mView = findViewById(R.id.drag_view);
        mGestureDetectorCompat = new GestureDetectorCompat(this,mSimpleOnGestureListener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetectorCompat.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    private float mOffsetScX = 0;
    private float mOffsetScY = 0;
    private GestureDetector.SimpleOnGestureListener mSimpleOnGestureListener = new GestureDetector.SimpleOnGestureListener(){
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            mOffsetScX +=  -distanceX;
            mOffsetScY +=  -distanceY;
            mView.setTranslationX( mOffsetScX );
            mView.setTranslationY( mOffsetScY );
            return true;
        }
    };
}

6.3 图示

android frament手势滑动 安卓手势_手势识别_04


七、源码

源码下载: https://github.com/qiwenming/GestureDemo/tree/master/app/src/main/java/com/qwm/gesturedemo/basetest