一、使用GestureDetector进行手势识别
手势交互过程(原理):
1、触屏一刹那,触发MotionEvent事件2、被OnTouchListener监听,在onTouch()中获得MotionEvent对象
3、GestureDetector转发MotionEvent对象至OnGestureListener
4、OnGestureListener获得该对象,根据该对象封装的信息做出和适当的反馈
MotionEvent
1、用于封装手势、触摸笔、轨迹球等动作事件2、内部封装用于记录横轴和纵轴坐标的属性X和Y
GestureDetector
识别各种手势
触摸屏:按下、移动、抬起等
重载onTouch或者设置OnTouchListenerOnTouchListener工作原理:
当接收到用户触摸消息时,将消息交给GestureDetector加工通过设置监听器获得GestureDetector处理后的手势
OnTouchListener提供两个监听器:
OnGestureListener:处理单击类消息OnDoubleTapListener:处理双击类消息
OnGestureListener:
1、手势交互的监听接口,其提供多个抽象方法2、根据GestureDetector的手势识别结果调用相对应的方法
OnGestureListener接口:
单击:onDown(MotionEvent e)
抬起:onSingleTapUp(MotionEvent e)
短按:onShowPress(MotionEvent e)
长按:onLongPress(MotionEvent e)
滚动:onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
滑动:onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
OnDoubleTapListener接口:
双击:onDoubleTap(MotionEvent e)
双击按下和抬起各触发一次:onDoubleTapEvent(MotionEvent e)
单击确认:onSingleTapConfirmed(MotionEvent e),即很快的按下并抬起,但并不连续点击第二下
对于上面的两种接口,我们可以直接继承SimpleOnGestureListener,然后重载感兴趣的手势。
使用实例:
1、布局文件
<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/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/guide_image1" />
</RelativeLayout>
2、实现手势识别
package com.cx.gesturedetectordemo;
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ImageView image;
private GestureDetector myGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
//实例化GestureDetector
myGestureDetector = new GestureDetector(this, new myOnGestureListener());
//增加监听事件
image.setOnTouchListener(new OnTouchListener() {
@Override//可以捕获触摸屏幕发生的Event事件
public boolean onTouch(View v, MotionEvent event) {
//使用GestureDetector转发MotionEvent对象给OnGestureListener
myGestureDetector.onTouchEvent(event);
return true;
}
});
}
class myOnGestureListener extends SimpleOnGestureListener{
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
if(e1.getX()-e2.getX()>50){
Toast.makeText(MainActivity.this, "向左滑动", Toast.LENGTH_SHORT).show();
}else if(e2.getX()-e1.getX()>50){
Toast.makeText(MainActivity.this, "向右滑动", Toast.LENGTH_SHORT).show();
}
return super.onFling(e1, e2, velocityX, velocityY);
}
}
}
3、多个手指滑动识别。例如手机的UI界面,两个手指向内滑动→可操作界面,三个手指向内滑动→界面窗口视图。该内容为后来添加内容,下面源码中不包含该部分代码。
a.修改上面的ImageView的点击方法
image.setOnTouchListener(new OnTouchListener() {
@Override//可以捕获触摸屏幕发生的Event事件
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = 1;
break;
case MotionEvent.ACTION_UP:
mode = 0;
break;
case MotionEvent.ACTION_POINTER_UP:
mode -= 1;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);//两点按下时的距离
mode += 1;
break;
case MotionEvent.ACTION_MOVE:
if (mode == 2) {
float newDist = spacing(event);
//+-100是为了增加滑动幅度
if (newDist > oldDist+100) {
Toast.makeText(MainActivity.this, "两指分!", Toast.LENGTH_SHORT).show();
//清零是为了防止多次执行
mode = 0;
}else if (newDist < oldDist-100) {
Toast.makeText(MainActivity.this, "两指聚!", Toast.LENGTH_SHORT).show();
mode = 0;
}
}else if (mode == 3) {
float newDist = spacing(event);
if (newDist > oldDist+100) {
Toast.makeText(MainActivity.this, "三指分!", Toast.LENGTH_SHORT).show();
mode = 0;
}else if (newDist < oldDist-100) {
Toast.makeText(MainActivity.this, "三指聚!", Toast.LENGTH_SHORT).show();
mode = 0;
}
}
break;
}
return true;
}
});
b.增加计算移动距离的方法
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
二、使用GestureOverlayView进行手势识别
GestureOverlayView是一种用于手势输入的透明覆盖层,可覆盖在其他控件的上方,也可包含其他控件。存在3个监听器接口:
实现步骤:
1、使用Gestures Builder生成手势文件2、加入项目
3、GestureOverlayView
拓展:笔画颜色、多笔画识别等、
监听器
GestureOverlayView.OnGestureListener 手势监听器GestureOverlayView.OnGesturePerformedListener 手势执行监听器
GestureOverlayView.OnGesturingListener 手势执行中监听器
常见XML属性:
android:eventsInterceptionEnabled 定义当手势已经被识别出来时,是否拦截该手势动作android:fadeDuration 当用户画完手势效果淡出的时间(ms)
android:fadeEnabled 用户画完之后手势是否自动淡出
android:gestureColor 手势的颜色
android:gestureStrokeType 笔画的类型
android:gestureStrokeWidth 笔画的粗细
使用实例:
1、生成手势文件
我们可以直接使用官方Demo来进行手势文件的生成,Demo位置:E:\eclipse\adt-bundle-windows-x86-20130219\sdk\samples\android-10\GestureBuilder
a.Demo导入:
需要new一个已经存在的项目,步骤如下
b.运行导入的项目,在应用中添加手势并生成手势文件。(生成的手势文件一般在SD卡的根目录)
c.将生成的手势文件放在新建工程的res/raw文件夹下
2、布局文件,添加GestureOverlayView控件
<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" >
<android.gesture.GestureOverlayView
android:id="@+id/gestureOverlayView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/guide_image1" />
</android.gesture.GestureOverlayView>
</RelativeLayout>
2、实现手势识别
package com.cx.gestureoverlayviewdemo;
import java.util.ArrayList;
import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.Prediction;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
private GestureOverlayView gestureOverlayView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gestureOverlayView = (GestureOverlayView) findViewById(R.id.gestureOverlayView1);
//从资源中将手势库文件加载进来
final GestureLibrary library = GestureLibraries.fromRawResource(this, R.raw.gestures);
library.load();
//增加手势执行监听器
gestureOverlayView.addOnGesturePerformedListener(new OnGesturePerformedListener() {
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
//读出手势库中的内容 识别手势
ArrayList<Prediction> myGesture = library.recognize(gesture);
Prediction prediction = myGesture.get(0);
//判断相似度0.0~10.0
if(prediction.score > 5.0){
//通过名字判断手势
if(prediction.name.equals("yes")){
Toast.makeText(MainActivity.this, "正确!", Toast.LENGTH_SHORT).show();
}else if(prediction.name.equals("no")){
Toast.makeText(MainActivity.this, "错误!", Toast.LENGTH_SHORT).show();
}else if(prediction.name.equals("next")){
Toast.makeText(MainActivity.this, "下一步!", Toast.LENGTH_SHORT).show();
}else if(prediction.name.equals("back")){
Toast.makeText(MainActivity.this, "上一步!", Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(MainActivity.this, "无法识别!", Toast.LENGTH_SHORT).show();
}
}
});
}
}
源码下载