手势识别
可以通过以下两种方式实现:
1. 使用GestureDetector
2. 使用GestureOverlayView(属于线程的控件)
手势交互过程(原理):
1. 触屏一刹那,触发 MotionEvent 事件;
2. 被 OnTouchListener 监听,在 onTouch()中获得 MotionEvent对象;
3. GestureDetector 转发 MotionEvent 对象至 OnGestureListener;
4. OnGestureListener 获取该对象,根据该对象封装的信息做出合适的反馈;
MotionEvent:
1. 用于封装手势、触摸笔、轨迹球等动作事件;
2. 内部封装用于记录横轴和纵轴坐标的属性X和Y。
GestureDetector:
识别各种手势。
OnGestureListener:
1. 手势交互的监听接口,其提供多个抽象方法;
2. 根据 GestureDetector 的手势识别结果,调用相应的方法。
GestureDetector 详解:
触摸屏:按下、移动、抬起等。
监听触摸事件:重载 onTouch 或者设置 setOnTouchListener
GestureDetector 工作原理:
1. 当接收到用户触摸消息时,将消息交给 GestureDetector加工;
2. 通过设置监听器获得 GestureDetector 处理后的手势。
GestureDetector提供两个监听器:
1. OnGestureListener:处理单击类消息
2. OnDoubleTapListener:处理双击类消息
OnGestureListener接口的6个方法:
单击:onDown(MotionEvent e)
抬起:onSingleTapUp(MotionEvent e)
短按:onShowPress(MotionEvent e)
长按:onLongPress(MotionEvent e)
滚动:onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float disanceY)
滑动:onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
(注解:velocity:速率,速度)
OnDoubleTapListener接口的3个方法:
双击:onDoubleTap(MotionEvent e)
双击按下和抬起各触发一次:onDoubleTapEvent(MotionEvent e)
单击确认:onSingleTapConfirmed(MotionEvent e)就是很快地按下并抬起,但不连续点击第二下。
如果分别去实现这两个接口的所有方法,未免太麻烦了,所以这里提供了另一个接口:SimpleOnGestureListener,它已经继承了前面所讲的两个监听器。
- 继承SimpleOnGestureListener
- 重载感兴趣的手势
1 public class MainActivity extends Activity {
2 ImageView imageView;
3 GestureDetector myDetector;
4
5 class myGestureListenner extends SimpleOnGestureListener {
6 @Override
7 // e1表示起始事件,e2表示末尾事件,每个事件都含有坐标属性。通过起止事件的相对位置,可以判断是从左往右滑动还是从右往左滑动。
8 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
9 float velocityY) {
10 // TODO Auto-generated method stub
11 if (e1.getX() - e2.getX() > 50) {
12 Toast.makeText(MainActivity.this, "从右边往左边滑动!", 0).show();
13
14 } else if (e2.getX() - e1.getX() > 50) {
15 Toast.makeText(MainActivity.this, "从左边往右边滑动!", 0).show();
16 }
17 return super.onFling(e1, e2, velocityX, velocityY);
18 }
19
20 }
21
22 @Override
23 protected void onCreate(Bundle savedInstanceState) {
24 super.onCreate(savedInstanceState);
25 setContentView(R.layout.fragment_main);
26 imageView = (ImageView) findViewById(R.id.image);
27 myDetector = new GestureDetector(new myGestureListenner());
28 imageView.setOnTouchListener(new OnTouchListener() {
29
30 @Override
31 public boolean onTouch(View v, MotionEvent event) {
32 // TODO Auto-generated method stub
33 // 捕获触摸屏幕的Event事件
34 myDetector.onTouchEvent(event);
35
36 return true;
37 }
38 });
39 }
40
41 }
使用GestureOverlayView进行手势识别的步骤:
1. 使用Gesture Builder生成手势文件
2. 将文件加入到项目
3. 在项目中创建 GestureOverlayView,将它放置在想要识别手势的控件上,或者把它包裹起来。
只能识别文件中存在的手势,如果不是文件中存在的手势,就无法识别。
---------------
在res文件夹下创建文件夹raw,把手势文件gesture添加到这里。
GestureOverlayView
一种用于手势输入的透明覆盖层,可覆盖在其他控件的上方,也可以包含其他控件。存在3个监听接口:
GestureOverlayView.OnGestureListener // 手势监听器
GestureOverlayView.OnGesturePerformedListener // 手势执行监听器
GestureOverlayView.OnGesturingListener // 手势执行中监听器
------------------
如图使用GestureOverlayView控件去包含ImageView控件。
可识别手势的区域大小不是由ImageView决定,而是由GestureOverlayView决定。
------------------------
补充:
使用Android Studio则更加简单,不用去创建 Simple Project。老师之所以要创建Simple Project,是因为模拟器中没有Gesture Builder这种应用,所以要自己创建。而Android Studio的模拟器是有Gesture Builder的,所以我们可以直接进入模拟器,点击Gesture Builder图标,进行手势的创建。
给gestureOverlayView设置监听器:
gestureOverlayView.addOnGesturePerformedListener(new OnGesturePerformedListener(){})
重写方法onGesturePerformed()。
如图,onGesturePerformed()的示例代码,也就是关于手势识别的代码实现。
ArrayList<Prediction>:预测集
predction.score:相似度,值越大,则越相似,也就是说你必须做出几乎一模一样的手势才能通过识别。相似度的取值范围一般是0.0~10.0,取10.0就已经太夸张了,因为很难做出非常接近的手势。所以,这里的下限只取5.0:
predction.score>=5.0
如果觉得显示的手势的轨迹不好看,可以自定义轨迹的样式。
一些常见的XML属性设置:
Android:eventInterceptionEnabled 定义当手势已经被识别出来时,是否拦截该手势动作
Android:fadeDuration 当用户画完的时候,手势效果淡出的时间
Android:fadeEnabled 用户画完之后,手势是否自动淡出
Android:gestureColor 手势的颜色
Android:gestureStrokeType 笔画的类型
Android:gestureStrokeWidth 笔画的粗细
1 public class MainActivity extends ActionBarActivity {
2 GestureOverlayView gestureOverlayView;
3
4 @Override
5 protected void onCreate(Bundle savedInstanceState) {
6 super.onCreate(savedInstanceState);
7 setContentView(R.layout.fragment_main);
8 gestureOverlayView = (GestureOverlayView) findViewById(R.id.gestureOverlayView1);
9 // 1.找到预设定的手势文件
10 // 2.加载那个手势文件中的所有手势
11 // 3.匹配,识别
12
13 // 从资源中将手势库文件加载进来
14 final GestureLibrary library = GestureLibraries.fromRawResource(
15 MainActivity.this, R.raw.gestures);
16 library.load();
17 gestureOverlayView
18 .addOnGesturePerformedListener(new OnGesturePerformedListener() {
19
20 @Override
21 public void onGesturePerformed(GestureOverlayView overlay,
22 Gesture gesture) {
23 // TODO Auto-generated method stub
24 // 读出手势库中内容 识别手势
25 ArrayList<Prediction> mygesture = library
26 .recognize(gesture);
27 Prediction prediction = mygesture.get(0);
28 if (prediction.score >= 5.0) {
29 if (prediction.name.equals("exit")) {
30 finish();
31 }
32 if (prediction.name.equals("next")) {
33 Toast.makeText(MainActivity.this, "下一首", 0)
34 .show();
35 }
36 if (prediction.name.equals("previouse")) {
37 Toast.makeText(MainActivity.this, "上一首", 0)
38 .show();
39 }
40 } else {
41 Toast.makeText(MainActivity.this, "没有该手势", 0)
42 .show();
43 }
44
45 }
46 });
47
48 }
49
50 }