2013年5月9日
47_手势识别
--------------------
第一步:建立手势库
使用SDK自带例子GestureBuilder建立手势库(位置:android-sdk-windows\samples\android-8\GestureBuilder)。使用GestureBuilder之前,你需要恢复其到开发环境,然后进行编绎并部署到手机上。此时,就可以使用GestureBuilder建立手势库,生成的手势库文件在SCDard上,默认文件名称为:gestures
第二步:在应用中加载手势库文件,然后开发手势识别代码。
把手势库文件gestures文件拷贝到项目的res/raw目录下。然后在布局文件中添加用于手势绘制的View:
<android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="fill_parent“ android:layout_height="0dip"
android:layout_weight="1.0"
/>
大多数情况下,手势都是通过一笔完成。然而有一些特别的需求就需要通过多个笔画来实现,这时可以使用gestureStrokeType属性进行设置:Multiple:1
手势识别代码见ppt下方
public class MainActivity extends Activity {
private GestureOverlayView gestureOverlayView;
private GestureLibrary mLibrary;
private boolean state;
private EditText addressText;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
addressText = (EditText)this.findViewById(R.id.address);
gestureOverlayView = (GestureOverlayView)this.findViewById(R.id.gestures);
//当用户完成一次Gesture绘制后,系统将自动调用Listener对象的onGesturePerformed()方法
gestureOverlayView.addOnGesturePerformedListener(new GestureListener());
mLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures);
state = mLibrary.load();//加载手势库
}
private final class GestureListener implements GestureOverlayView.OnGesturePerformedListener{
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
if(state){
List<Prediction> predictions = mLibrary.recognize(gesture);//从手势库中查询匹配的内容,匹配的结果可能包括多个相似的结果,匹配度高的结果放在最前面
if(!predictions.isEmpty()){
Prediction prediction = predictions.get(0);
//prediction的score属性代表了与手势的相似程度
//prediction的name代表手势对应的字母
if(prediction.score > 1){
addressText.setText(prediction.name);
}
}
}
}
}
}
---------------------------------------
2.相关理解:手势识别其实就是图形识别,当用户画出图形后,由程序识别然后按照识别的结果进行执行。
----------------------------------------------------------------------------------------------------
3.导入一个android项目到eclipse工作workspace中的方法:
a.在已经workspace已经存在的android项目中拷贝.classpath,.project,project.properties(这里应该是default.properties文件)到
需要导入的项目中
b.然后直接导入项目到eclipse中就可以了
---------------------------------------------------------
4.a、这里要实现的功能是,当用户画出一个对勾后,关闭该应用。
b、当用户画一个L后,就给李德伟打电话
------------------------------------------------------
5.首先要建立手势库,手势识别的时候会从手势库中查找,如果找到就执行相应的业务功能
----------------------------------------------------------------
6.WARNING: Application does not specify an API level requirement!
[2009-12-27 16:51:33 - Tank] WARNING: Application does not specify an API level requirement!
[2009-12-27 16:51:33 - Tank] Device API version is 3 (Android 1.5)
网上一查是由于没有指定users sdk的缘故,修改AndroidManifest.xml文件.
加入:
<uses-sdk android:minSdkVersion="3"></uses-sdk>
加在<manifest> </manifest> 之间.
------------------------------------------------------
7.2013/5/10
----------------
8.[2013-05-10 22:54:48 - GestureBuilder] Re-installation failed due to different application signatures.
[2013-05-10 22:54:48 - GestureBuilder] You must perform a full uninstall of the application. WARNING: This will remove the application data!
[2013-05-10 22:54:48 - GestureBuilder] Please execute 'adb uninstall com.android.gesture.builder' in a shell.
[2013-05-10 22:54:48 - GestureBuilder] Launch canceled!
这时先运行android模拟机,进入命令行,当然你要定位adb.exe的目录,我是放在E:\android\android-sdk-windows\platform-tools 下
E:\android\android-sdk-windows\platform-tools> adb uninstall com.android.gesture.builder.
重新运行就可以了
--------------------------------------------------
9.这里建立手势库的时候,用的是android自带的一个例子:
这个例子可以在这里找到:
G:\李鹏视频\andoid程序学习及开发\3G手机Android应用开发\3G手机Android应用开发开发资料\开发资料\android-sdk_r06-windows\android-sdk-windows\samples\android-8
就是这个项目:GestureBuilder
---------------------------------------
10.如果出现问题按照上面的方法进行解决
运行该例子程序后:点击Add gesture进行手势添加,也就是添加用户自己画的图片
添加的时候,只要在空白区域画出手势,在Name中输入手势名称就,然后点击Done就
可以添加一个手势了
-------------------------------
11.当添加完手势后,可以查看在sdcard根目录下,有gestures这个文件,这个就是手势库文件
也是一个数据库文件,这时候就可以在这个手势库的基础上进行手势的查找识别了。
---------------------------------------------------------------------------------------
11-1:做的时候首先将上一步生成的手势库文件gestures复制到:/gesture/res/raw/gestures这个路径下,当查不到的时候需要关闭应用
11-2:关闭应用的方法:
当应用不再使用时,通常需要关闭应用,可以使用以下两种方法关闭android应用:
第一种方法:首先获取当前进程的id,然后杀死该进程。 (建议使用)
android.os.Process.killProcess(android.os.Process.myPid())
第二种方法:终止当前正在运行的Java虚拟机,导致程序终止
System.exit(0);
第三种方法:强制关闭与该包有关联的一切执行
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
manager.restartPackage(getPackageName());
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
----------------------------------------------------------------------------------------
12.下面是手势识别实例的所有源码:
屏幕布局:
--------------
整个屏幕都是供用户绘制手势
在屏幕右下角有个识别按钮
---------------------------------
a.新建android项目:gesture
b./gesture/src/com/credream/gesture/GestureActivity.java
package com.credream.gesture;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGestureListener;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.Prediction;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class GestureActivity extends Activity {
private static final String TAG = "GestureActivity";
private GestureLibrary library;
private Gesture mgesture;
private GestureOverlayView overlayView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//fromRawResource从raw这个手势库文件中得到手势对象
library = GestureLibraries.fromRawResource(this, R.raw.gestures);
//加载手势对象
library.load();
//获取overlayView,也就是用户识别手势的画板。
overlayView = (GestureOverlayView) this.findViewById(R.id.gestures);
//只针对单笔手势:overlayView.addOnGesturePerformedListener(new GesturePerformedListener());
//当用户绘制完手势之后,就会触发一个事件
//overlayView.addOnGesturePerformedListener(new GesturePerformedListener());
//注意这里GesturePerformedListener这个方法只是针对单笔手势的,用户画多笔的时候会没有响应
overlayView.addOnGestureListener(new GestureListener());
//addOnGestureListener,这个方法,既可以实现单笔手势,也可以实现多笔手势
}
// ②.在这个方法中识别手势
public void find(View v){
recognize(mgesture);
//②.1 识别完之后,清除。
overlayView.clear(true);
}
//②.下面这个方法可以识别单笔,也可以识别多笔。
private final class GestureListener implements OnGestureListener{
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
Log.i(TAG, "onGestureStarted()");
//可以打印到控制台,得到这三个方法的调用顺序。
//-----------------------------------------
/*这三个方法的调用顺序是,当用户画第一笔的时候,调用onGestureStarted方法
* 当用户在画第一笔的过程中不断调用onGesture这个方法
* 当用户画完第一笔的时候调用onGestureEnded这个方法
* 当用户开始画第二笔的时候调用onGestureStarted这个方法,一次循环。。
* */
//-------------------------------------------
}
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
Log.i(TAG, "onGesture()");
}
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
Log.i(TAG, "onGestureEnded()");
//因为这个方法是最后调用的,所以在这个方法里得到用户最后画完的手势
mgesture = overlay.getGesture();
//取得用户最后画完的手势
}
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
Log.i(TAG, "onGestureCancelled()");
}
}
//①.以下方法只识别单笔绘图。
//当用户绘制完手势之后,就会触发一个事件,就会调用这个方法,把用户绘制完的手势传进来
private final class GesturePerformedListener implements OnGesturePerformedListener{
//overlay这个参数其实就是取得用户绘制所用的那个画板,这里是overlayView
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
//在这个方法中就来识别用户画出的手势,也就是把用户绘制的手势在手势库中查找,查找到就是
//代表可以识别。
//这时候把导出的手势库文件gesture,添加到
///gesture/res/raw这个路径中,注意这里raw是新建的文件夹
//然后查看R文件就可以看到下面这些:
//public static final int gestures=0x7f040000;
//识别手势, recognize(gesture)这个方法会在手势库中查找,如果找到匹配项
//会以集合的形式返回
//ArrayList<Prediction> predictions=library.recognize(gesture);
//这个集合中的元素排序原则是最匹配的在最上边,其次是不怎么匹配的。
//这个方法会把所有匹配的记录查询出来,并且把最匹配的在最上边
recognize(gesture);
}
}
private void recognize(Gesture gesture) {
//这个集合中的元素排序原则是最匹配的在最上边,其次是不怎么匹配的。
//这个方法会把所有匹配的记录查询出来,并且把最匹配的在最上边
ArrayList<Prediction> predictions = library.recognize(gesture);
if(!predictions.isEmpty()){//当结果集合不是空的时候,就说明有匹配
//得到最匹配的那个,也就是第一条记录
Prediction prediction = predictions.get(0);
//prediction.score>0-10这个是匹配值,范围:prediction.score>0-10
//这个值为10的时候,代表手势库中的图和用户绘制的图有10%的匹配度
if(prediction.score >= 6){
//这里要求匹配度要在60%以上
//如果名称为李德伟lidewei
if("lidewei".equals(prediction.name)){
//调用打电话意图,
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:1350505050"));
//通过意图调用打电话的activity,这里需要有拨号权限
startActivity(intent);
}else if("close".equals(prediction.name)){
finish();//关闭Activity,也就是关闭窗口
//当activity关闭的时候,其实应用还存在,这里需要关闭应用
//当activity关闭的时候,会调用onDestroy方法,在这个方法里
//可以直接杀掉进程
}
}else{
//匹配度不够6的时候,提示匹配度太低
Toast.makeText(getApplicationContext(), R.string.low, 1).show();
}
}else{
//没有匹配的记录
Toast.makeText(getApplicationContext(), R.string.notfind, 1).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//这里直接杀掉进程:首先取得当前进程的id,然后调用killProcess杀掉进程
android.os.Process.killProcess(android.os.Process.myPid());//关闭应用
}
}
-----------------------------------------------------------
c./gesture/res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, MainActivity!</string>
<string name="app_name">手势识别</string>
<string name="notfind">不匹配</string>
<string name="low">匹配度太低</string>
<string name="recognize">识别</string>
</resources>
--------------------------------------------------
d./gesture/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.credream.gesture"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".GestureActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<!-- 由于识别成功后会给李德伟拨打电话,所以这里需要这个权限 -->
<uses-permission android:name="android.permission.CALL_PHONE"/>
</manifest>
-----------------------------------------------------
e./gesture/res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<!-- 这个控件可以供用户在他上面绘制手势 -->
<android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gestureStrokeType="multiple"
/>
<!-- ①.1 android:layout_height="0dp",设置用户绘制手势界面的高度
①.2 android:layout_weight="1",设置定义测量的优先级别,0的优先级最高,0>1>2...
按钮的话,android:layout_weight="1"这个默认值是0
①.3 系统首先测量按钮的高度,因为按钮的优先级高。
④.4 只要这样设置就可以实现用窗口的高度,减去按钮的高度,剩余的,就是用户绘制手势的高度
-->
<!-- android:gestureStrokeType="multiple"注意加上这一句就可以进行多笔画识别
以前只可以写一笔,现在可以写好几笔画。
-->
<!-- ①. android:layout_weight="0"这里要求让这个按钮显示在屏幕的最下方
这里采取的方法是,用窗口的高度,减去按钮的高度,剩余的,就是用户绘制手势的高度 -->
<Button
android:layout_weight="0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/recognize"
android:onClick="find"
/>
</LinearLayout>
------------------------------------------------------------------------------------
13.这个功能可以做成,用户输入密码。
手势识别,可以用于软件的快捷方式。比如用户想打开某个应用画个o就可以。
使用手势识别可以实现解锁功能。
----------------------------------------------------------------------------