手势Gesture,增加手势
android除了提供了手势检测之外,还允许应用程序把用户手势(多个持续的触摸事件在屏幕上形成特定的形状)添加到指定文件中,以备以后使用
如果程序需要,当用户下次再次画出该手势时,系统将可识别该手势。
android使用GestureLibray来代替手势库,并提供了GestureLibraries工具类来创建手势库,GestureLibraries提供了如下4个静态方法从不同位置加载手势库。
1.static GestureLibray fromFile(String path):从path代表的文件中加载手势;
2.static GestureLibray fromFile(File path):从path代表的文件中加载手势;
3.static GestureLibray fromPrivateFile(Context context,String name):从指定应用程序的数据文件夹中name文件中加载手势库;
4.static GestureLibray fromRawResource(Context context, int resourceId):从resourceId所代表的资源中加载手势库。
一旦程序中获得了GestureLibray对象后,该对象提供如下方法来添加、识别手势:
1.void addGesture(String entryName,Gesture gesture):添加一个名为entryName的手势;
2.Set<String>getGestureEntries():获取该手势库中的所有手势的名称;
3.ArrayList<Gesture>getGestures(String entryName):获取entryName名称对应的所有手势;
4.ArrayList<Prediction>recognize(Gesture gesture):从当前手势库中识别与gesture匹配的全部手势;
5.void removeEntry(String entryName):删除手势库中entryName对应的手势;
6.void removeGesture(String entryName,Gesture gesture):删除手势库中entryName、gesture对应的手势;
7.boolean save():当手势库中听见手势或者删除手势后调用该方法保存手势库。
android提供了GestureLibraries、GestureLibrary来管理手势之外,还提供了一个专门的手势编辑组件——GestureOverlayView,该组件就像一个“绘图组件”,只是用户在组件上绘制的不是图像,而是手势。
为了监听GestureOverlayView组件上的手势,android为GestureOverlayView提供了OnGestureLinstener、OnGesturePerformedListener、OnGesturingListener三个监听器接口,这些监听器所包含的方法分别用于响应手势事件开始、结束、完成、取消等事件,开发者可根据实现需求来选择不同的监听器——一般来说,OnGesturePerformedListener是最常用的监听器,其用于在手势事件完成时提供响应。
注意:
GestureOverlayView不是标准的视图组件,在界面布局中使用该组件时,需要使用完全限定名称。
布局文件==》main.xml <LinearLayout xmlns: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" tools:context=".MainActivity" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="请在以下屏幕上绘制手势" />
<EditText android:id="@+id/edit" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="110" />
<android.gesture.GestureOverlayView
android:id="@+id/gesture" android:layout_width="match_parent" android:layout_height="match_parent" android:gestureStrokeType="multiple" /> <!-- android:gestureStrokeType 用于控制手势是否需要多笔完成,大部分情况, 一个手势只需要一笔完成,此时可将该参数设置为Single;多笔完成则设为multiple --> </LinearLayout> save.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="match_parent" android:layout_height="wrap_content" android:layout_marginRight="8dip" android:text="添加手势" /> <EditText android:id="@+id/gestureName" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> <!-- 定义一个图片框,用于显示手势 --> <ImageView android:id="@+id/show" android:layout_width="128dp" android:layout_height="128dp" android:layout_marginTop="10dp" /> </LinearLayout> 代码实现==》 package com.example.myaddgesture; import android.os.Bundle; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.gesture.Gesture; import android.gesture.GestureLibraries; import android.gesture.GestureLibrary; import android.gesture.GestureOverlayView; import android.gesture.GestureOverlayView.OnGesturePerformedListener; import android.graphics.Bitmap; import android.graphics.Color; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.EditText; import android.widget.ImageView; public class MainActivity extends Activity { EditText edit; GestureOverlayView gestureView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); edit = (EditText) this.findViewById(R.id.gestureName); // 获取手势编辑视图 gestureView = (GestureOverlayView) this.findViewById(R.id.gesture); // 设置手势绘制颜色 gestureView.setGestureColor(Color.RED); // 设置手势绘制的宽度 gestureView.setGestureStrokeWidth(10); // 为手势完成事件绑定事件监听器——手势完成后,触发该事件 gestureView.addOnGesturePerformedListener(new OnGesturePerformedListener() { @Override public void onGesturePerformed(GestureOverlayView overlay, final Gesture gesture) { Log.i("swg", "onGesturePerformed"); // 加载save.xml界面布局视图 View dialog = getLayoutInflater().inflate(R.layout.save, null); ImageView image = (ImageView) dialog.findViewById(R.id.show); final EditText gestureName = (EditText) dialog.findViewById(R.id.gestureName); // 根据Gesture包含的手势创建一个位图 Bitmap bitmap = gesture.toBitmap(128, 128, 10, 0xFFFF0000); image.setImageBitmap(bitmap); // 使用对话框显示dialog组件 new AlertDialog.Builder(MainActivity.this).setView(dialog) .setPositiveButton("保存", new OnClickListener() { @SuppressLint("SdCardPath") @Override public void onClick(DialogInterface dialog, int which) { Log.i("swg", "setPositiveButton-->onClick"); // 获取指定文件对应的手势库 GestureLibrary lib = GestureLibraries .fromFile("/sdcard/mygestures"); lib.addGesture(gestureName.getText().toString(), gesture); // 保存手势 lib.save(); } }).setNegativeButton("取消", null).show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
注意:需要多笔操作才可以弹出对话框。
运行效果如下:
识别用户手势
GestureLibray提供了额recognize(Gesture gesture)方法识别用户手势,该方法将会返回该手势库中所有与gesture参数匹配的手势——两个手势的图形越相似、相似度越高。
recognize(Gesture ges)方法返回值为ArrayList<Prediction>,其中Prediction封装了手势的匹配信息,Prediction对象的name属性代表了匹配的手势名,score属性代表了手势的相似度。
下面的程序将会利用以上添加手势库程序所创建的手势库来识别手势,如下所示:
布局文件==》 <LinearLayout xmlns: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" tools:context=".MainActivity" > <android.gesture.GestureOverlayView android:id="@+id/gesture" android:layout_width="match_parent" android:layout_height="match_parent" android:gestureStrokeType="multiple" /> <!-- android:gestureStrokeType 用于控制手势是否需要多笔完成,大部分情况, 一个手势只需要一笔完成,此时可将该参数设置为Single;多笔完成则设为multiple --> </LinearLayout> 代码实现==》 package com.example.myrecognizegesture; import java.util.ArrayList; import android.os.Bundle; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.gesture.Gesture; import android.gesture.GestureLibraries; import android.gesture.GestureLibrary; import android.gesture.GestureOverlayView; import android.gesture.GestureOverlayView.OnGesturePerformedListener; import android.gesture.Prediction; import android.graphics.Color; import android.view.Menu; import android.widget.ArrayAdapter; import android.widget.Toast; public class MainActivity extends Activity { GestureOverlayView gestureView; GestureLibrary gestureLib; @SuppressLint({ "SdCardPath", "ShowToast" }) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); gestureView = (GestureOverlayView) this.findViewById(R.id.gesture); // 设置手势绘制颜色 gestureView.setGestureColor(Color.RED); // 设置手势绘制的宽度 gestureView.setGestureStrokeWidth(10); gestureLib = GestureLibraries.fromFile("/sdcard/mygestures"); if (gestureLib.load()) Toast.makeText(MainActivity.this, "手势文件装载成功", 5000).show(); else Toast.makeText(MainActivity.this, "手势文件装载失败", 5000).show(); gestureView.addOnGesturePerformedListener(new OnGesturePerformedListener() { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { // 识别用户刚刚绘制的手势 ArrayList<Prediction> predictions = gestureLib.recognize(gesture); ArrayList<String> result = new ArrayList<String>(); // 遍历所有找到的Prediction对象 for (Prediction pred : predictions) { // 输出相似度大于2.0的手势 if (pred.score > 2) result.add("与手势[" + pred.name + "]相似度为:" + pred.score); if (result.size() > 0) { ArrayAdapter adapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_dropdown_item_1line, result.toArray()); new AlertDialog.Builder(MainActivity.this).setAdapter(adapter, null) .setPositiveButton("保存", null).show(); } else Toast.makeText(MainActivity.this, "无法找到匹配的手势", 5000).show(); } } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
运行效果如下:(和实际连接手机运行存在一定差异,虚拟机部分内容显示不全)