今天起介紹下和手勢和多點觸摸相關的知識。。。。。。
先上個一道菜,手勢的識別。。。。。
java.lang.Object ↳android.view.View ↳android.view.ViewGroup ↳android.widget.FrameLayout ↳android.gesture.GestureOverlayView
介紹下GestureOverlayView,這個透明的view就是讓你在上面畫手勢用的,可疊在其他View上面。
和這個類相關的還有三個介面,分別是
GestureOverlayView.OnGestureListener;
GestureOverlayView.OnGesturePerformedListener(作用:根據在GestureOverlayView上畫的手勢來識別是否匹配手勢庫裡的手勢);
GestureOverlayView.OnGesturingListener.
GestureOverlayView的xml的屬性介紹:
android:gestureStrokeType
設定手勢的筆畫數,它有兩個值,GESTURE_STROKE_TYPE_MULTIPLE(多筆),GESTURE_STROKE_TYPE_SINGLE(一筆)
public final class GestureLibraries
static GestureLibrary fromFile(File path) static GestureLibrary fromFile(String path) static GestureLibrary fromPrivateFile(Context context, String name) static GestureLibrary fromRawResource(Context context, int resourceId)
想從SD卡或者raw的資源中直接載入手勢;
下面介紹下手勢的識別功能,先上代碼:
GestureIdentifyDemoActivity.xml
package com.potato;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.Prediction;import android.os.Bundle;import android.widget.Toast;public class GestureIdentifyDemoActivity extends Activity {// 手勢庫GestureLibrary mGestureLib;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);// 手勢畫板GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gesture_overlay_view_test);// 手勢識別的監聽器gestures.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {// 注1@Overridepublic void onGesturePerformed(GestureOverlayView overlay,Gesture gesture) {//從手勢庫中查詢匹配的內容,匹配的結果可能包括多個相似的結果,匹配度高的結果放在最前面 ArrayList<Prediction> predictions = mGestureLib.recognize(gesture);// 注3if (predictions.size() > 0) {Prediction prediction = (Prediction) predictions.get(0);// 匹配的手勢if (prediction.score > 1.0) {Toast.makeText(GestureIdentifyDemoActivity.this,prediction.name, Toast.LENGTH_SHORT).show();}}}});// 從raw中載入已經有的手勢庫mGestureLib = GestureLibraries.fromRawResource(this, R.raw.gestures);// 注2if (!mGestureLib.load()) {finish();}}}
注1:
gestures.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener()
手勢識別的監聽器。。。。
注2:
mGestureLib = GestureLibraries.fromRawResource(this, R.raw.gestures);
從res/raw/載入gestures手勢這個檔案
注3:
ArrayList<Prediction> predictions = mGestureLib.recognize(gesture);
從手勢庫中識別出和在GestureOverlayView所畫的手勢;
mian.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" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="輸入手勢:" /> <!-- 注意 android.gesture.要加,否則報錯,估計是找不到包--> <android.gesture.GestureOverlayView android:id="@+id/gesture_overlay_view_test" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1.0" android:gestureStrokeType="multiple" /></LinearLayout>
這裡要注意:android.gesture.GestureOverlayView這裡的不能用GestureOverlayView
下面介紹如何向手勢庫中增加自訂的手勢:
上代碼:
GestureBuilderDemoActivity.java
package com.potato;import java.io.File;import java.util.Collections;import java.util.Comparator;import java.util.HashMap;import java.util.Map;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.content.res.Resources;import android.gesture.Gesture;import android.gesture.GestureLibraries;import android.gesture.GestureLibrary;import android.graphics.Bitmap;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.os.Environment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;public class GestureBuilderDemoActivity extends Activity {private static final int STATUS_SUCCESS = 0;private static final int STATUS_CANCELLED = 1;private static final int STATUS_NO_STORAGE = 2;private static final int STATUS_NOT_LOADED = 3;private static final int REQUEST_NEW_GESTURE = 1;// 存放手勢的檔案private final File mStoreFile = new File(Environment.getExternalStorageDirectory(), "gestures");private GesturesAdapter mAdapter;private static GestureLibrary mGestureLib;private TextView mTvEmpty;Button mBtnAddGesture;Button mBtnIdentify;Resources mRes;ListView mListViewGesture;// 寬度、高度private int mThumbnailSize;// 密度private int mThumbnailInset;// 顏色private int mPathColor;static GestureLibrary getStore() {return mGestureLib;}/** * 手勢排序 */private final Comparator<NamedGesture> mSorter = new Comparator<NamedGesture>() {public int compare(NamedGesture object1, NamedGesture object2) {return object1.name.compareTo(object2.name);}};/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mRes = getResources();mBtnAddGesture = (Button) findViewById(R.id.addButton);mBtnIdentify = (Button) findViewById(R.id.reloadButton);mPathColor = mRes.getColor(R.color.gesture_color);mThumbnailInset = (int) mRes.getDimension(R.dimen.gesture_thumbnail_inset);mThumbnailSize = (int) mRes.getDimension(R.dimen.gesture_thumbnail_size);mListViewGesture = (ListView) findViewById(android.R.id.list);mAdapter = new GesturesAdapter(this);mListViewGesture.setAdapter(mAdapter);if (mGestureLib == null) {mGestureLib = GestureLibraries.fromFile(mStoreFile);// 注1}mTvEmpty = (TextView) findViewById(android.R.id.empty);loadGestures();if (mListViewGesture.getAdapter().isEmpty()) {mListViewGesture.setEmptyView(mTvEmpty);mBtnAddGesture.setEnabled(false);} else {mBtnAddGesture.setEnabled(true);}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {switch (requestCode) {case REQUEST_NEW_GESTURE:loadGestures();break;}}}/** * 識別手勢 */@SuppressWarnings({ "UnusedDeclaration" })public void identifyGestures(View v) {Intent intent = new Intent(this, GestureIdentifyDemoActivity.class);startActivity(intent);}/** * 建立手勢 * @param v */@SuppressWarnings({ "UnusedDeclaration" })public void addGesture(View v) {Intent intent = new Intent(this, CreateGestureActivity.class);startActivityForResult(intent, REQUEST_NEW_GESTURE);}/** * 載入手勢 * @return */private int loadGestures() {if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {return STATUS_NO_STORAGE;}final GestureLibrary gestureLib = mGestureLib;mAdapter.clear();if (gestureLib.load()) {// 注2for (String name : gestureLib.getGestureEntries()) {for (Gesture gesture : gestureLib.getGestures(name)) {final Bitmap bitmap = gesture.toBitmap(mThumbnailSize,// 注3mThumbnailSize, mThumbnailInset, mPathColor);final NamedGesture namedGesture = new NamedGesture();namedGesture.gesture = gesture;namedGesture.name = name;mAdapter.addBitmap(namedGesture.gesture.getID(), bitmap);mAdapter.add(namedGesture);}}mAdapter.sort(mSorter);// 注4mAdapter.notifyDataSetChanged();return STATUS_SUCCESS;}return STATUS_NOT_LOADED;}static class NamedGesture {String name;Gesture gesture;}private class GesturesAdapter extends ArrayAdapter<NamedGesture> {private final LayoutInflater mInflater;private final Map<Long, Drawable> mThumbnails = Collections.synchronizedMap(new HashMap<Long, Drawable>());public GesturesAdapter(Context context) {super(context, 0);mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);}void addBitmap(Long id, Bitmap bitmap) {mThumbnails.put(id, new BitmapDrawable(bitmap));}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = mInflater.inflate(R.layout.list_item_gesture,parent, false);}final NamedGesture gesture = getItem(position);final TextView label = (TextView) convertView;label.setTag(gesture);label.setText(gesture.name);label.setCompoundDrawablesWithIntrinsicBounds(mThumbnails.get(gesture.gesture.getID()), null, null, null);return convertView;}};}
注1
mGestureLib = GestureLibraries.fromFile(mStoreFile);
從SD卡中載入已有的手勢;
注2
gestureLib.load()
從手勢庫載入手勢
注3
final Bitmap bitmap = gesture.toBitmap(mThumbnailSize,// 注3mThumbnailSize, mThumbnailInset, mPathColor);
把手勢轉換成bitmap
注4
排序
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:background="#009966" android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1.0" /> <LinearLayout style="@android:style/ButtonBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/addButton" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:enabled="false" android:onClick="addGesture" android:text="button_add" /> <Button android:id="@+id/reloadButton" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="identifyGestures" android:text="button_identify" /> </LinearLayout></LinearLayout>
建立手勢
CreateGestureActivity.java
package com.potato;import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.view.View;import android.view.MotionEvent;import android.gesture.GestureOverlayView;import android.gesture.Gesture;import android.gesture.GestureLibrary;import android.widget.TextView;import android.widget.Toast;import java.io.File;public class CreateGestureActivity extends Activity {private static final float LENGTH_THRESHOLD = 120.0f;private Gesture mGesture;private View mDoneButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.create_gesture);mDoneButton = findViewById(R.id.done);GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay);overlay.addOnGestureListener(new GesturesProcessor());}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);if (mGesture != null) {outState.putParcelable("gesture", mGesture);}}@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);mGesture = savedInstanceState.getParcelable("gesture");if (mGesture != null) {final GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay);overlay.post(new Runnable() {public void run() {overlay.setGesture(mGesture);}});mDoneButton.setEnabled(true);}}/** * 增加手勢的按鈕 * @param v */public void addGesture(View v) {if (mGesture != null) {final TextView input = (TextView) findViewById(R.id.gesture_name);final CharSequence name = input.getText();if (name.length() == 0) {input.setError("輸入gesture的名字!");return;}// 把手勢增加到手勢庫final GestureLibrary store = GestureBuilderDemoActivity.getStore();// 注1store.addGesture(name.toString(), mGesture);store.save();setResult(RESULT_OK);final String path = new File(Environment.getExternalStorageDirectory(), "gestures").getAbsolutePath();Toast.makeText(this, "儲存成功" + path, Toast.LENGTH_LONG).show();} else {setResult(RESULT_CANCELED);}finish();}/** * 取消手勢 * @param v */public void cancelGesture(View v) {setResult(RESULT_CANCELED);finish();}/** * 手勢監聽著 * @author Administrator * */private class GesturesProcessor implementsGestureOverlayView.OnGestureListener {public void onGestureStarted(GestureOverlayView overlay,MotionEvent event) {mDoneButton.setEnabled(false);mGesture = null;}public void onGesture(GestureOverlayView overlay, MotionEvent event) {}public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {// 擷取在GestureOverlayView手勢mGesture = overlay.getGesture();// 注2if (mGesture.getLength() < LENGTH_THRESHOLD) {overlay.clear(false);}mDoneButton.setEnabled(true);}public void onGestureCancelled(GestureOverlayView overlay,MotionEvent event) {}}}
注1
final GestureLibrary store = GestureBuilderDemoActivity.getStore();// 注1store.addGesture(name.toString(), mGesture);store.save();
手勢增加到手勢庫
注2
擷取在GestureOverlayView手勢
create_gesture.xml\
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="6dip" android:text="prompt_gesture_name" android:textAppearance="?android:attr/textAppearanceMedium" /> <EditText android:id="@+id/gesture_name" android:layout_width="0dip" android:layout_weight="1.0" android:layout_height="wrap_content" android:maxLength="40" android:singleLine="true" /> </LinearLayout> <android.gesture.GestureOverlayView android:id="@+id/gestures_overlay" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1.0" android:gestureStrokeType="multiple" /> <LinearLayout style="@android:style/ButtonBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/done" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:enabled="false" android:onClick="addGesture" android:text="button_done" /> <Button android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="cancelGesture" android:text="button_discard" /> </LinearLayout> </LinearLayout>
注意,不要忘記,寫入手勢時,一定要增加許可權,寫入sd卡
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
有問題,請留言或者發郵件
ligexiao@gmail.com
原始碼:http://download.csdn.net/detail/alex0203/3868687