在Android系统中,每一次手势交互都会依照以下顺序执行。
1. 接触接触屏一刹那,触发一个MotionEvent事件。
2. 该事件被OnTouchListener监听,在其onTouch()方法里获得该MotionEvent对象。
3. 通过GestureDetector(手势识别器)转发次MotionEvent对象
MotionEvent: 这个类用于封装手势、触摸笔、轨迹球等等的动作事件。其内部封装了两个重要的属性X和Y,这两个属性分别用于记录横轴和纵轴的坐标。
GestureDetector: 识别各种手势,它提供了OnGestureListener和OnDoubleTapListener两个接口,以及一个内部类SimpleOnGestureListener。
手势交互的监听接口,其中提供了多个抽象方法,并根据GestureDetector的手势识别结果调用相对应的方法。
代码说明:
布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/iv" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/a" /> </RelativeLayout>
实现OnGestureListener接口:
package com.example.gesturedetectortest; import android.os.Bundle; import android.util.Log; import android.app.Activity; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; // OnGestureListener: 这是一个手势交互的监听接口, //其中提供了多个抽象方法,并根据GestureDetector的手势识别结果调用相对应的方法。 public class MainActivity extends Activity implements OnGestureListener,OnTouchListener{ public static final String TAG=MainActivity.class.getSimpleName(); private ImageView iv; private GestureDetector detector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); iv=(ImageView)findViewById(R.id.iv); detector=new GestureDetector(this, this); iv.setOnTouchListener(this); } //在onTouchEvent()方法中,我们调用GestureDetector的onTouchEvent()方法, //将捕捉到的MotionEvent交给GestureDetector来分析是否有合适的callback函数来处理用户的手势 // @Override // public boolean onTouchEvent(MotionEvent event) { // // TODO Auto-generated method stub // return this.detector.onTouchEvent(event); // } @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub return this.detector.onTouchEvent(event); } //刚刚手指接触到触摸屏的那一刹那,由1个MotionEvent ACTION_DOWN触发 @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub Log.i(TAG, "onDown y=" + e.getY()); return true; } // 手指按在触摸屏上,它的时间范围在按下起效,在长按之前, //由一个1个MotionEvent ACTION_DOWN触发 //注意和onDown()的区别,强调的是没有松开或者拖动的状态 @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub Log.i(TAG, "onShowPress"); } //手指离开触摸屏的那一刹那 //由一个1个MotionEvent ACTION_UP触发 @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub Log.i(TAG, "onSingleTapUp y=" + e.getY()); return true; } //手指按下且在屏上滑动 //由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // TODO Auto-generated method stub Log.i(TAG, "onScroll:distanceX = " + distanceX + " distanceY = " + distanceY); return true; } //手指长按触屏幕,并且没有松开 //由多个MotionEvent ACTION_DOWN触发 @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub Log.i(TAG, "onLongPress"); } //手指在触摸屏上迅速移动,并松开的动作 //由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 //e1:第1个ACTION_DOWN MotionEvent ,e2:最后一个ACTION_MOVE MotionEven //velocityX:X轴上的移动速度,像素/秒 ,velocityY:Y轴上的移动速度,像素/秒 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub Log.i(TAG, "onFling"); if(e1.getX()-e2.getX()>100&&Math.abs(velocityX)>200){ Log.i(TAG, "onFling 向左滑动"); return true; }else if(e1.getX()-e2.getX()<-100&&Math.abs(velocityX)>200){ Log.i(TAG, "onFling 向右滑动"); return true; }else if(e1.getY()-e2.getY()>10&&Math.abs(velocityY)>50){ Log.i(TAG, "onFling 向上滑动 上位移="+(e1.getY()-e2.getY())); return true; }else if(e1.getY()-e2.getY()<-10&&Math.abs(velocityY)>50){ Log.i(TAG, "onFling 向下滑动 下位移"+(e1.getY()-e2.getY())); return true; } return false; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
onFling方法中可以通过其参数进行一些条件设置,如左右上下滑动的条件。
Activity中的onTouchEvent方法和OnTouchListener中的onTouch方法,都可以实现调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给GestureDetector来分析是否有合适的callback函数来处理用户的手势,两个直接的区别:查看http://www.xuebuyuan.com/1588148.html。
执行不同手势时,logcat显示:
下面这个测试,来自网络,其实和OnGestureListener比较多了几个方法。
package com.example.gesturedetectortest; import android.app.Activity; import android.os.Bundle; import android.os.storage.OnObbStateChangeListener; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; public class SimpleOnGestureActivity extends Activity implements OnTouchListener{ public static final String TAG=SimpleOnGestureActivity.class.getSimpleName(); private GestureDetector detector; private ImageView iv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_gestrue); iv=(ImageView)findViewById(R.id.iv); detector=new GestureDetector(this, new MySimpleGesture()); iv.setOnTouchListener(this); } @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub return this.detector.onTouchEvent(event); } private class MySimpleGesture extends SimpleOnGestureListener{ // 双击的第二下Touch down时触发 public boolean onDoubleTap(MotionEvent e) { Log.i(TAG, "onDoubleTap"); return super.onDoubleTap(e); } // 双击的第二下Touch down和up都会触发,可用e.getAction()区分 public boolean onDoubleTapEvent(MotionEvent e) { Log.i(TAG, "onDoubleTapEvent"); return super.onDoubleTapEvent(e); } // Touch down时触发 public boolean onDown(MotionEvent e) { Log.i(TAG, "onDown"); return super.onDown(e); } // Touch了滑动一点距离后,up时触发 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.i(TAG, "onFling"); return super.onFling(e1, e2, velocityX, velocityY); } // Touch了不移动一直Touch down时触发 public void onLongPress(MotionEvent e) { Log.i(TAG, "onLongPress"); super.onLongPress(e); } // Touch了滑动时触发 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.i(TAG, "onScroll"); return super.onScroll(e1, e2, distanceX, distanceY); } /* * Touch了还没有滑动时触发 * (1)onDown只要Touch Down一定立刻触发 * (2)Touch Down后过一会没有滑动先触发onShowPress再触发onLongPress * So: Touch Down后一直不滑动,onDown -> onShowPress -> onLongPress这个顺序触发。 */ public void onShowPress(MotionEvent e) { Log.i(TAG, "onShowPress"); super.onShowPress(e); } /* * 两个函数都是在Touch Down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touch Up时触发 * 点击一下非常快的(不滑动)Touch Up: onDown->onSingleTapUp->onSingleTapConfirmed * 点击一下稍微慢点的(不滑动)Touch Up: onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed */ public boolean onSingleTapConfirmed(MotionEvent e) { Log.i(TAG, "onSingleTapConfirmed"); return super.onSingleTapConfirmed(e); } public boolean onSingleTapUp(MotionEvent e) { Log.i(TAG, "onSingleTapUp"); return super.onSingleTapUp(e); } } }
一些关于手势的优秀的开源框架:http://jcodecraeer.com/plus/list.php?tid=31&codecategory=16500
示例代码下载