所谓手势,其实是指用户手指或触摸笔在触摸屏上的连续触碰的行为,比如在屏幕上从左向右划出的一个动作,就是手势;再比如在屏幕上画出一个圆圈也是手势。手势这种连续的触碰会形成某个方向上的移动趋势,也会形成一个不规则的几何图形。Android对两种手势行为都是提供了支持。
- 对于第一种手势行为,Android提供了手势检测,并为手势检测提供了相应的监听器;
- 对于第二种手势行为,Android允许开发者添加手势,并提供了相应的API识别用户手势。

添加手势

Android除了提供手势检测之外,还允许应用程序把用户手势(多个持续的触摸事件在屏幕上形成特定的形状)添加到指定文件中,已备以后使用——如果程序需要,当用户下次再次画出该手势时,系统将可识别该手势。
下面的应用程序在界面布局中使用了GestureOverlayView。

  • 布局文件layout/activity_main.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:gravity="center_horizontal"    android:orientation="vertical">    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="请在下面屏幕上绘制手势" />        <android.gesture.GestureOverlayView        android:id="@+id/gesture"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:gestureStrokeType="multiple" />LinearLayout>

由于GestureOverlayView并不是标准的视图组件,因此在界面布局中使用该组件时需要使用全限类名。
上面的程序使用GestureOverlayView组件时指定了一个android:gestureStrokeType参数,该参数控制手势是否需要多一笔完成。大部分时候,一个手势只要一笔就可以完成,此时可将该参数设为single。如果该手势需要多笔来完成,则将该参数设为multiple。
接下来程序将会为GestureOverlayView添加一个OnGesturePerformedListener监听器,当手势事件完成时,该监听器会打开一个对话框,让用户选择保存该手势。

  • MainActivity.java逻辑代码:
package com.fukaimei.addgesture;import android.content.DialogInterface;import android.gesture.Gesture;import android.gesture.GestureLibraries;import android.gesture.GestureLibrary;import android.gesture.GestureOverlayView;import android.graphics.Bitmap;import android.graphics.Color;import android.support.v7.app.AlertDialog;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.ImageView;public class MainActivity extends AppCompatActivity {    EditText editText;    GestureOverlayView gestureView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // 获取文本编辑框        editText = (EditText) findViewById(R.id.gesture_name);        // 获取手势编辑视图        gestureView = (GestureOverlayView) findViewById(R.id.gesture);        // 设置手势的绘制颜色        gestureView.setGestureColor(Color.RED);        // 设置手势的绘制宽度        gestureView.setGestureStrokeWidth(4);        // 为gesture的手势完成事件监听器        gestureView.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {  //①            @Override            public void onGesturePerformed(GestureOverlayView overlay, final Gesture gesture) {                // 加载sava.xml界面布局代表的视图                View saveDialog = getLayoutInflater().inflate(R.layout.save, null);                // 获取saveDialog里的show组件                ImageView imageView = (ImageView) saveDialog.findViewById(R.id.show);                // 获取saveDialog里的gesture_name组件                final EditText gestureName = (EditText) saveDialog.findViewById(R.id.gesture_name);                // 根据Gesture包含的手势创建一个位图                Bitmap bitmap = gesture.toBitmap(128, 128, 10, 0xffff0000);                imageView.setImageBitmap(bitmap);                // 使用对话框显示saveDialog组件                new AlertDialog.Builder(MainActivity.this).setView(saveDialog).setPositiveButton("保存",                        new DialogInterface.OnClickListener() {                            @Override                            public void onClick(DialogInterface dialog, int which) {                                // 获取指定文件对应的手势库                                GestureLibrary gestureLib = GestureLibraries.fromFile("/mnt/sdcard/mygestures");  //②                                // 添加手势                                gestureLib.addGesture(gestureName.getText().toString(), gesture);  //②                                // 保存手势库                                gestureLib.save();  //②                            }                        }).setNegativeButton("取消", null).show();            }        });    }}

上面程序中标为序号①的代码为GestureOverlayView绑定OnGesturePerformedListener监听器,该监听器用于在手势完成时提供响应——它的响应就是打开一个对话框。该对话框的界面布局代码如下。

  • layout/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="wrap_content"            android:layout_height="wrap_content"            android:layout_marginRight="8dip"            android:text="请填手势名" />                <EditText            android:id="@+id/gesture_name"            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>

AddGesture程序中的标为②序号的代码是在对话框中完成的,这段代码用于从SD卡的指定文件中加载手势库,并添加用户刚刚输入的手势。

注意:上面的程序需要将手势库保存在SD卡上,因此还需要在清单文件AndroidManifest.xml里面添加程序的读写SD卡的权限。

  • 在清单文件AndroidManifest.xml里添加的权限代码如下:
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

识别用户手势

前面已经提到,GestureLibrary提供了recognize(Gesture ges)方法来识别手势,该方法将会返回该手势库中所有与ges匹配的手势——两个手势的图形越相似,相似度越高。
recognize(Gesture ges)方法的返回值为ArrayList< Predicttion>,其中Prediction封装了手势的匹配信息,Prediction对象的name属性代表了匹配的手势名,score属性代表了手势的相似度。
下面的程序将会利用前一个程序所创建的手势库来识别手势。该程序的界面很简单,只是在界面中定义了一个GestureOverlayView组件,允许用户在该组件上输入手势。程序为该组件绑定了OnGesturePerformedListener监听器,该监听器检测到用户手势完成时,就会调用手势库来识别用户输入的手势。


  • layout/activity_main.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">        <android.gesture.GestureOverlayView        android:id="@+id/gesture"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:gestureStrokeType="multiple" />LinearLayout>
  • layout/result.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">    <ListView        android:id="@+id/show"        android:layout_width="match_parent"        android:layout_height="match_parent" />LinearLayout>
  • MainActivity.java逻辑代码:
package com.fukaimei.recognisegesture;import android.gesture.Gesture;import android.gesture.GestureLibraries;import android.gesture.GestureLibrary;import android.gesture.GestureOverlayView;import android.gesture.Prediction;import android.support.v7.app.AlertDialog;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.widget.ArrayAdapter;import android.widget.Toast;import java.util.ArrayList;public class MainActivity extends AppCompatActivity {    // 定义手势编辑组件    GestureOverlayView gestureView;    // 记录手机上已有的手势库    GestureLibrary gestureLibrary;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // 读取上一个程序所创建的手势库        gestureLibrary = GestureLibraries.fromFile("/mnt/sdcard/mygestures");        if (gestureLibrary.load()) {            Toast.makeText(this, "手势文件装载成功", Toast.LENGTH_SHORT).show();        } else {            Toast.makeText(this, "手势文件装载失败", Toast.LENGTH_SHORT).show();        }        // 获取手势编辑组件        gestureView = (GestureOverlayView) findViewById(R.id.gesture);        // 为手势编辑组价绑定事件监听器        gestureView.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {            @Override            public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {                // 识别用户刚刚所绘制的手势                ArrayList predictions = gestureLibrary.recognize(gesture);  //①                ArrayList result = new ArrayList();                // 遍历所有找到的Prediction对象                for (Prediction pred : predictions) {                    // 只有相似度大于2.0的手势才会被输出                    if (pred.score > 2.0) {                        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());                    // 使用一个带List的对话框来显示所有匹配的手势                    new AlertDialog.Builder(MainActivity.this).setAdapter(adapter, null)                            .setPositiveButton("确定", null).show();                } else {                    Toast.makeText(MainActivity.this, "无法找到能匹配的手势", Toast.LENGTH_SHORT).show();                }            }        });    }}   

注意:上面的程序同样需要将手势库保存在SD卡上,因此还需要在清单文件AndroidManifest.xml里面添加程序的读写SD卡的权限。

  • 在清单文件AndroidManifest.xml里添加的权限代码如下:
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

上面的MainActivity.java程序中的标序号为①的代码就负责调用前一个程序的手势库来识别用户刚输入的手势,用户只要在屏幕上绘制一个大致与之前相似的手势,即可提示的结果。

更多相关文章

  1. Android(安卓)“再按一次返回键退出程序”
  2. Android(安卓)修改应用程序字体
  3. 初识Android的界面UI
  4. Android移动view动画问题 关于view的位置移动了,但view里面绑定的
  5. Android(安卓)手势检测---GestureDetector
  6. 资深程序员多年代码实践总结:《和Android源代码一起工作》 | Andr
  7. flex兼容 iOS和Android样式兼容 【微信小程序】
  8. android studio :利用安卓真机USB调试安卓程序
  9. 适用于Android的最佳免费待办事项列表应用程序以及如何使自己成

随机推荐

  1. windows管理linux机器
  2. Linux内核中实现生产者与消费者(避免无效
  3. Linux下搭建ftp服务
  4. linux 下使用 vim+cscope+ctags+taglist+
  5. linux下socket实现TCP通信的简单程序接口
  6. 嵌入式linux 字节对齐 导致输出Alignment
  7. 0K6410学习之linux移植nand flash
  8. linux的常用命令
  9. linux安装PHP环境
  10. Linux 安装MongoDB 2.6.5