一.手势事件的监听方式
1.使用 onTouchEvent事件监听器或者使用 setOnTouchEventListener监听触摸事件
2.事件类型的判断
event.getAction()或者event.getActionMask(),注意,前者包含后者,后者判断起来比较精确
3.事件的生命周期 Action_DOWN(按下) ---> Action_MOVE(移动) --->Action_UP/Action_CANCELED(抬起手指或者滑出屏幕)
在一些事件,如Click,LongClick等事件按照该周期的时间长度和 移动位置来决定的
4.事件传递的3个阶段
第一阶段是 分发/拦截阶段 ondispatchEvent和onInteceptorEvent(一般在此阶段处理事件,可能导致事件无法传递)
第二阶段是 向下传递阶段 onTouchEvent
学过javascript的读者可能会发现,这种事件的传递和js的十分类似,不过少了一个阶段就是 目标View处理阶段,按照javascript的划分,
第一个阶段 捕获阶段(无论如何处理,事件总会传递到目标控件)
第二个阶段 目标控件事件处理阶段
第三个阶段 冒泡阶段(这个阶段处理事件的比较多,可终止冒泡)
很显然,android的事件传递阶段似乎很不友好,因为此阶段捕获导致很多处理冲突,甚至目标控件无法得到事件,比如ViewGroup拦截事件之后,将直接把事件交给自己的onTouchEvent进行处理,造成子View上的事件处理程序一直无法执行,很多时候由于这种事件分发问题导致的错误非常多,因此对于这种问题的处理要务必格外小心,如果遇到这种冲突,一般的做法是 2个联系密切的 View控件分别绑定事件,并调用getParent().requestDisallowInterceptTouchEvent(true),但这种方法也是由局限性的,希望有更好想法的读者指正一下。
5.多点触摸事件的处理,对于多点触摸,可以使用
event.getPointersCount()或者触摸点的数量,然后通过 event.getX(index) ,event.getY(index)获得触摸点的坐标
public class MultiTouchActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_multi_touch); } public boolean onTouchEvent(MotionEvent event) { // ֻ2个手指 if(event.getPointerCount() == 2) { if(event.getAction() == MotionEvent.ACTION_MOVE) { int historySize = event.getHistorySize(); if(historySize == 0) return true; //第1个手指的Y坐标 float currentY1 = event.getY(0); //第1个手指的历史纵坐标 float historyY1 = event.getHistoricalY(0, historySize - 1); //第二个手指的的Y坐标 float currentY2 = event.getY(1); //第2个手指的历史纵坐标 float historyY2 = event.getHistoricalY(1,historySize - 1); float distance = Math.abs(currentY1 - currentY2); float historyDistance = Math.abs(historyY1 - historyY2); if(distance > historyDistance) { Log.d("status", "放大"); } else if(distance < historyDistance) { Log.d("status", "缩小"); } else { Log.d("status", "平行移动"); } } } return true; }}
二.使用手势库
public class DrawGestureTest extends Activity implements OnGesturePerformedListener { private GestureOverlayView mDrawGestureView; private static GestureLibrary sStore; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mDrawGestureView = (GestureOverlayView)findViewById(R.id.gesture); //设置手势可多笔画绘制,默认情况为单笔画绘制 mDrawGestureView.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE); //设置手势的颜色(蓝色) mDrawGestureView.setGestureColor(gestureColor(R.color.gestureColor)); //设置还没未能形成手势绘制是的颜色(红色) mDrawGestureView.setUncertainGestureColor(gestureColor(R.color.ungestureColor)); //设置手势的粗细 mDrawGestureView.setGestureStrokeWidth(4); /*手势绘制完成后淡出屏幕的时间间隔,即绘制完手指离开屏幕后相隔多长时间手势从屏幕上消失; * 可以理解为手势绘制完成手指离开屏幕后到调用onGesturePerformed的时间间隔 * 默认值为420毫秒,这里设置为0.5秒 */ mDrawGestureView.setFadeOffset(500); //绑定监听器 mDrawGestureView.addOnGesturePerformedListener(this); //创建保存手势的手势库 createStore(); } private void createStore() { File mStoreFile = null; /*判断mStoreFile是为空。 * 判断手机是否插入SD卡,并且应用程序是否具有访问SD卡的权限 */ if (mStoreFile == null && Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { mStoreFile = new File(Environment.getExternalStorageDirectory(), "mygesture"); } if (sStore == null) { /* 另外三种创建保存手势文件的方式如下: //保存手势的文件在手机SD卡中 sStore = GestureLibraries.fromFile(Environment.getExternalStorageDirectory().getAbsolutePath() + "mygesture"); sStore = GestureLibraries.fromPrivateFile(this, Environment.getExternalStorageDirectory().getAbsolutePath + "mygesture"); //保存手势的文件在应用程序的res/raw文件下 sStore = GestureLibraries.fromRawResource(this, R.raw.gestures); */ sStore = GestureLibraries.fromFile(mStoreFile); } testLoad(); } //测试保存手势的文件是否创建成功 private void testLoad() { if (sStore.load()) { showMessage("手势文件装载成功"); } else { showMessage("手势文件装载失败"); } } public static GestureLibrary getStore() { return sStore; } //手势绘制完成时调用 @Override public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { // TODO Auto-generated method stub creatDialog(gesture); } private void creatDialog(final Gesture gesture) { View dialogView = getLayoutInflater().inflate(R.layout.show_gesture, null); //imageView用于显示绘制的手势 ImageView imageView = (ImageView) dialogView.findViewById(R.id.show); //获取用户保存手势的名字 EditText editText = (EditText)dialogView.findViewById(R.id.name); final String name = editText.getText().toString(); // 调用Gesture的toBitmap方法形成对应手势的位图 final Bitmap bitmap = gesture.toBitmap(128, 128, 10, gestureColor(R.color.showColor)); imageView.setImageBitmap(bitmap); Builder dialogBuider = new AlertDialog.Builder(DrawGestureTest.this); dialogBuider.setView(dialogView); //绑定对话框的确认按钮监听事件 dialogBuider.setPositiveButton( "保存", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 添加手势 sStore.addGesture(name, gesture); // 保存添加的手势 sStore.save(); } }); //绑定对话框的取消按钮监听事件 dialogBuider.setNegativeButton("取消", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }); //显示对话框 dialogBuider.show(); } private int gestureColor(int resId) { return getResources().getColor(resId); } private void showMessage(String s) { Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); //移除绑定的监听器 mDrawGestureView.removeOnGesturePerformedListener(this); } }
main.xml
对话框show_gesture.xml