一、 原理简介。
利用Android 中的 GestureOverlayView 可以记录用户对屏幕的滑动手势 。每一个手势都是一个Gesture对象,而且一定时间内,可以将多个手势作为一个Gesture对象。 GestureLibrary 可以将这些Gesture以键值对的形式进行存储。这样,设备就可以通过用户的手势获取其对应的键,并通过键来进行进一步的操作。
二、 使用方法。
(一) 创建和写入
1、在布局文件中添加android.gesture.GestureOverlayView。只需要给它一个id,然后简单的设置其宽高即可。这个组件的作用是记录用户输入的手势。
2、在Activity的onCreate()方法中获取该组件,并添加手势监听 onGestureListenner()。手势监听必须实现四个方法 :
(1)onGestureStarted(GestureOverlayView overlay, MotionEvent event);
(2)onGestureEnded(GestureOverlayViewoverlay, MotionEvent event) ;
(3)onGestureCancelled(GestureOverlayViewoverlay, MotionEvent event);
(4) onGesture(GestureOverlayViewoverlay, MotionEvent event)
涉及到获取手势的方法主要是方法(1)和方法(2)。onGestureStarted方法是在手势输入刚开始的时候触发, onGestureEnded在手势结束的时候触发。一个手势是从手指触摸到屏幕开始的,一直到手指离开屏幕时该手势才算结束。
GestureOverlayView有一个setGestureStrokeType方法,通过该方法传入不同的参数,可以设置输入手势的笔画,
GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE:可以输入多个手势组成一个手势对象。
GestureOverlayView.GESTURE_STROKE_TYPE_SINGLE :一个手势对象只能有一个手势。
3、创建一个GestureLibrary。 GestureLibrary重载一个静态方法 : fromFile( 形参),这个方法的形参可以是一个String 类型的路径, 也可以是File类型的文件 ,返回结果是一个手势库 GestureLibrart的对象。手势库对象提供了对手势对象的写入和读取方法。
向手势库写入手势,使用addGesture(Stringname,Gesture gesture)
读取手势库手势,使用getGesture(String name)
另外,读取手势库前,必须调用一次手势库的save()方法,否则无法读取。
(二) 手势匹配
getGesture(String name)可以精确的找到一个手势,看起来非常不错。可是我们必须考虑实际开发中的具体情况:加入我们要开发一个输入法应用,用户想要通过输入面板输入一个“赵”字,这个时候就不能使用getGesture(String name)了。因为这明显是在寻找某个手势,而我们的应用一般是要通过手势找到某个文字。这样一种情况下,可以使用GestureLibrary提供的recognize(Gesture gesture)方法。该方法返回值并不是String类型,而是一个Prediction泛型的List对象。该List对象包含了所有和用户手势相匹配的对象。而且Prediction对象还有一个score属性,用于标示该对象与用户输入手势的匹配程度。值越大匹配程序越高。于是在实际开发时,按照score值将所有Prediction.name排列出来,让用户自己来选择自己刚才输入的手势所希望得到的结果就成为最合理的逻辑了。
如果感觉不直观,可以使用手势库的getGestureEntries()获取到所有手势的key,然后遍历出来所有手势库的gesture,使用gesture的toBitmap方法把手势搞成图片,在surfaceview上画出来。余不多述… …
下面上三张图:黑色区域输入手势保存到手势库,白色区域输入手势会将手势库匹配结果显示在最上面的textview上
代码:GestureActivity.java
package com.example.gesturedemo;
import java.io.File;
import java.util.ArrayList;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGestureListener;
import android.gesture.Prediction;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.TextView;
public class GestureActivity extends Activity {
private String tag = "GestureActivity";
private EditText et_name;
private GestureOverlayView gov_save;
private TextView tv_prediction;
private int flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;
private int mask = flags;
private GestureLibrary gLib;
private GestureOverlayView gov_read;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().setFlags(flags, mask);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_gesture);
initView();
initFile();
}
private void initFile() {
String path = new File(Environment.getExternalStorageDirectory(),
"gestures").getAbsolutePath();
File file = new File(path);
gLib = GestureLibraries.fromFile(file);
}
private void initView() {
et_name = (EditText) findViewById(R.id.et_name);
gov_save = (GestureOverlayView) findViewById(R.id.gov_save);
gov_save.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);
tv_prediction = (TextView) findViewById(R.id.tv_prediction);
gov_save.addOnGestureListener(new OnGestureListener() {
private String name;
@Override
public void onGestureStarted(GestureOverlayView overlay,
MotionEvent event) {
name = et_name.getText() + "";
if (TextUtils.isEmpty(name)) {
tv_prediction.setText("请给手势输入一个名字");
}
}
@Override
public void onGestureEnded(GestureOverlayView overlay,
MotionEvent event) {
Gesture gesture = gov_save.getGesture();
gLib.addGesture(name, gesture);
if (gLib.save()) {
tv_prediction.setText("手势 " + name + " 保存成功!");
et_name.setText("");
gov_save.clear(true);
}
}
@Override
public void onGestureCancelled(GestureOverlayView overlay,
MotionEvent event) {
}
@Override
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
}
});
gov_read = (GestureOverlayView) findViewById(R.id.gov_read);
gov_read.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);
gov_read.addOnGestureListener(new OnGestureListener() {
@Override
public void onGestureStarted(GestureOverlayView overlay,
MotionEvent event) {
Log.i(tag, "开始匹配手势");
}
@Override
public void onGestureEnded(GestureOverlayView overlay,
MotionEvent event) {
Gesture gesture = gov_read.getGesture();
if (gLib.load()) {
ArrayList<Prediction> list = gLib.recognize(gesture);
if (list.size() > 0) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
Prediction prediction = list.get(i);
if (prediction.score >= 1) {
sb.append(" || " + prediction.name
+ " 的匹配程度是 " + prediction.score
+ " || ");
}
}
tv_prediction.setText(sb);
gov_read.clear(true);
}
}
}
@Override
public void onGestureCancelled(GestureOverlayView overlay,
MotionEvent event) {
}
@Override
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
}
});
}
}
activity_gesture.xml布局文件
<LinearLayoutxmlns: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:orientation="vertical">
<TextView
android:id="@+id/tv_prediction"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:paddingLeft="10dp"
android:text="手势结果匹配区"/>
<EditText
android:id="@+id/et_name"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:background="@drawable/edit_background"
android:hint="请在此处输入手势要匹配的内容"
android:inputType="textNoSuggestions"
android:paddingLeft="10dp"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.gesture.GestureOverlayView
android:id="@+id/gov_save"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#000000">
</android.gesture.GestureOverlayView>
<android.gesture.GestureOverlayView
android:id="@+id/gov_read"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1">
</android.gesture.GestureOverlayView>
</LinearLayout>
</LinearLayout>