您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
79_android下的手势识别-手势识别库的录入
发布时间:2021-03-20 22:14:13编辑:雪饮阅读()
本来呢,这次准备介绍下手势识别,但是呢这个手势库也就是gesturesBuilder的apk程序以前老的sdk中是有的,但是现在android studio目前我用的这个sdk的api是28版本中是没有的。所以这次呢先来介绍下如何实现gesturesBuilder软件的功能。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.creategesture">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="手势绘制"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.CreateGesture">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:label="手势库"
android:name=".MainActivity2" >
</activity>
</application>
</manifest>
那么接下来就是辅布局文件了,在该布局文件中将以listview的形式呈现手势库中的所有手势activity_main2.xml如:
最后还有一个布局文件,这个布局文件仅仅只是为了实现手势保存时候填写下当前手势名称,关于手势名称这样,可以通过接口看出同一个手势名称可能会有多个手势存在,不过本人在这里没有验证过。那么该布局文件如save_gesture.xml:
逻辑实现
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="请在下方绘制手势:"
android:textSize="36sp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="bottom"
>
<!--
android:gestureStrokeType="multiple"
设置手势类型支持多笔划,默认手势类型是一笔划不能停
其实这里有个争议,在多笔划被识别时候有时候自己明明手绘出多笔划图案,但是却没有被识别
关于这个问题,有说是笔划与笔划之间的停顿时间没有把握好,并且这个停顿时间是可以通过类型如下方式设置的
android:fadeDuration="2000"
且不说这种设置是否正确,我是没有见过有人通过这个提高识别率。
那么另外一种说法就直接是指向了识别率本身,具体处理方法也不是单纯的修改下停顿时间(判定时间)这种方式
关于这两个说法到底孰正孰非,这里暂不做讨论
-->
<android.gesture.GestureOverlayView
android:id="@+id/govGesture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gestureStrokeType="multiple"/>
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="查看手势列表"
android:onClick="getGestureList"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/gestureList"
>
</ListView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15dp">
<TextView
android:id="@+id/tvTip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请输入手势名称:"
android:textSize="26sp"/>
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_toRightOf="@+id/tvTip"/>
<ImageView
android:id="@+id/ivGesture"
android:layout_width="80dp"
android:layout_height="60dp"
android:layout_below="@id/tvTip"/>
</RelativeLayout>
那么主程序MainActivity的实现如MainActivity.java:
package com.example.creategesture;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
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.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
private GestureOverlayView govGesture;
private Gesture mGesture;
private EditText editText;
private ImageView imageView;
private ListView mListView;
private List<GestureData> gestureDatas;
//手势库必须定义为本activity的全局,否则在下面存储和读取时候用的不是同一个实例对象,则比如存储了,但却获取不到库里面的手势列表
private GestureLibrary library= GestureLibraries.fromFile("sdcard/mygestures");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
govGesture = (GestureOverlayView) findViewById(R.id.govGesture);
//当手势被识别成功时的颜色
govGesture.setGestureColor(Color.RED);
//手势完成后触发该事件(当你画的手势被成功识别后才会触发下面这些事件)
govGesture.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
mGesture=gesture;
View dialog=getLayoutInflater().inflate(R.layout.save_gesture,null);
imageView=dialog.findViewById(R.id.ivGesture);
editText=dialog.findViewById(R.id.etName);
//根据手势创建位图
Bitmap bitmap=mGesture.toBitmap(128,128,10,0xff0000ff);
imageView.setImageBitmap(bitmap);
new AlertDialog.Builder(MainActivity.this).setView(dialog)
.setNegativeButton("取消",null)
.setPositiveButton("保存", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//获取对应的手势库并将本次手势存储
library.addGesture(editText.getText().toString(),mGesture);
boolean isSave=library.save();
if (isSave) Toast.makeText(MainActivity.this,"保存成功",Toast.LENGTH_SHORT).show();
else Toast.makeText(MainActivity.this,"保存失败",Toast.LENGTH_SHORT).show();
}
}).show();
}
});
}
public void getGestureList(View view) {
Set<String> entries = library.getGestureEntries();
System.out.println("手势库大小:"+entries.size());
gestureDatas = new ArrayList<GestureData>();
int serialNumber=0;
for (String key : entries) {
System.out.println(key);
ArrayList<Gesture> gestures= library.getGestures(key);
for(Gesture gesture:gestures){
Bitmap bitmap=gesture.toBitmap(128,128,10,0xff0000ff);
GestureData gestureData = new GestureData();
gestureData.setBitmap(BitMapTool.getBytes(bitmap));
gestureData.setBitmapKey(key);
gestureData.setSerialNumber(serialNumber);
gestureDatas.add(gestureData);
}
}
Intent intent = new Intent();
//待打开activity所在包名;待打开activity类名(包含包名的全路径)
intent.setClassName("com.example.creategesture", "com.example.creategesture.MainActivity2");
intent.putExtra("key", (Serializable) gestureDatas);
startActivity(intent);
}
}接下来就是我们逻辑中对bitmap依赖的一个工具类,因为我们activity之间进行传递一个List类型数据,但是通过意图一般只能传递简单的字符串参数,像是一个list这样的复合型数据就需要序列化传递,但是序列化就需要被序列化的实体类中每个属性类型都实现了序列化接口,一般基本数据类型都实现了,但是像是我们手势数据bitmap类型则不可以,所以要将bitmap类型转换为基本数据类型,最后取出来再重新转回去,所以就出现了我们的这个bitmap与基本数据类型互相转换的工具类如BitMapTool.java:
package com.example.creategesture;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.ByteArrayOutputStream;
public class BitMapTool {
public static byte[] getBytes(Bitmap bitmap){
//实例化字节数组输出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, baos);//压缩位图
return baos.toByteArray();//创建分配字节数组
}
public static Bitmap getBitmap(byte[] data){
return BitmapFactory.decodeByteArray(data, 0, data.length);//从字节数组解码位图
}
}那么最后就是这个读取手势库中手势列表的逻辑实现如MainActivity2.java:
package com.example.creategesture;
import android.content.Intent;
import android.gesture.Gesture;
import android.gesture.GestureOverlayView;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;
public class MainActivity2 extends AppCompatActivity {
private GestureOverlayView govGesture;
private Gesture mGesture;
private EditText editText;
private ImageView imageView;
private ListView mListView;
private List<GestureData> gestureDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Intent intent = getIntent();
gestureDatas = (List<GestureData>) intent.getSerializableExtra("key");
for(GestureData gesture:gestureDatas){
System.out.println("key:"+gesture.getBitmapKey()+" serialNumber:"+gesture.getSerialNumber());
}
mListView = (ListView) this.findViewById(R.id.gestureList);
mListView.setAdapter(new MyAdatper());
}
public class MyAdatper extends BaseAdapter {
public int getCount() {
return gestureDatas.size();
}
public Object getItem(int position) {
return gestureDatas.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = new TextView(MainActivity2.this);
ImageView imageView = new ImageView(MainActivity2.this);
GestureData person = gestureDatas.get(position);
Bitmap bmp =BitMapTool.getBitmap(person.getBitmap()) ;
imageView.setImageBitmap(bmp);
return (View)imageView;
}
}
}那么最后要说的就是上面我们一直说的这个逻辑实体类bitmap中转的实体类如GestureData.java:
package com.example.creategesture;
import java.io.Serializable;
public class GestureData implements Serializable{
byte[] bitmap;
Integer serialNumber;
String bitmapKey;
public byte[] getBitmap() {
return this.bitmap;
}
public void setBitmap(byte[] bitmap){
this.bitmap=bitmap;
}
public Integer getSerialNumber() {
return this.serialNumber;
}
public void setSerialNumber(Integer serialNumber) {
this.serialNumber = serialNumber;
}
public String getBitmapKey() {
return this.bitmapKey;
}
public void setBitmapKey(String bitmapKey) {
this.bitmapKey = bitmapKey;
}
}那么最后将这些都完成后部署到设备中并勾选了对应权限后如
这里我画了两个手势都读取到了
关键字词:android,手势,库