一、 原理簡介。
利用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>