欢迎莅临 SUN WU GANG 的园子!!!

世上无难事,只畏有心人。有心之人,即立志之坚午也,志坚则不畏事之不成。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  470 随笔 :: 0 文章 :: 22 评论 :: 30万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

手势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不是标准的视图组件,在界面布局中使用该组件时,需要使用完全限定名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
布局文件==》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: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;
    }
 
}

     <android.gesture.GestureOverlayView

注意:需要多笔操作才可以弹出对话框。

运行效果如下:

 

识别用户手势

GestureLibray提供了额recognize(Gesture gesture)方法识别用户手势,该方法将会返回该手势库中所有与gesture参数匹配的手势——两个手势的图形越相似、相似度越高。

recognize(Gesture ges)方法返回值为ArrayList<Prediction>,其中Prediction封装了手势的匹配信息,Prediction对象的name属性代表了匹配的手势名,score属性代表了手势的相似度。

下面的程序将会利用以上添加手势库程序所创建的手势库来识别手势,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
布局文件==》
<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;
    }
 
}

运行效果如下:(和实际连接手机运行存在一定差异,虚拟机部分内容显示不全)

 

posted on   sunwugang  阅读(1415)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示