一.手势事件的监听方式
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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<android.gesture.GestureOverlayView
android:id="@+id/gesture"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</android.gesture.GestureOverlayView>
</LinearLayout>
对话框show_gesture.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:text="@string/set_gesture_name"/>
<EditText
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<ImageView
android:id="@+id/show"
android:layout_gravity="center"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_marginTop="10dp"/>
</LinearLayout>