前一篇文章我们介绍了GestureDetector类,这个主要用来处理触摸点击、双击、滑动操作,对于一个具体的手势是无能为力的,今天我们介绍的这个类可以自定义一个手势用来代表一个具体的操作,比如我们画个对勾让当前页面跳到另一个页面,而画个圈关闭当前页面。
GestureOverlayView作为一个Vie存在,自然是可以在布局文件中定义的,不过该类不是标准的控件类,所以需要全限定类名来引用,那么作为一个控件我们自然的使用方式是在XML布局文件中定义,并且设置一些属性,然后在代码中使用findviewbyid找到这个控件进行使用,这个类的使用也是一样。我们通过这个类可以定义一个具体的手势保存到文件中,并且可以画一个手势用来和文件中保存的所有手势做对比,如果有比对相似的就可以认为是该手势识别成功了,下面我们来具体的使用这个类。
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.gesture.GestureOverlayView
android:gestureColor="#f00"
android:id="@+id/gestureView"
android:gestureStrokeType="multiple"
android:gestureStrokeWidth="10"
android:uncertainGestureColor="#0f0"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
代码:
public class MainActivity extends AppCompatActivity {
private GestureOverlayView overlayView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
overlayView= (GestureOverlayView) findViewById(R.id.gestureView);
}
}
运行效果:
我们看到已经可以绘制我们的手势了,可是现在并没有任何效果,下面我们将演示如何保存一个手势,手势对应的事件就是toast一个提示框,如果下次需要识别的时候只需要画个这个就可以toast提示框。在演示这个效果前,我们来看另外一个类:GestureLibraries,这个类的作用就是用来保存手势和识别手势,手势的保存方式是以文件的形式保存,一个文件可以对应多个手势,区别手势以保存的时候的名字。
我们第一步是要给手势做一个监听操作,在画完手势的时候我们dialog一个框出来让用户选择是否保存这个手势,如果选择保存就用GestureLibraries来把保存这个手势,保存的名字就用“toast”,在原来的代码中添加:
file = new File(Environment.getExternalStorageDirectory(), "gesture");
//保存手势和识别手势的对象
gestureLibrary = GestureLibraries.fromFile(file);
//手势确认的时候调用
overlayView.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
@Override
public void onGesturePerformed(GestureOverlayView overlay, final Gesture gesture) {
if (gesture.getLength() > LENGTH) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("是否保存");
builder.setMessage("保存?");
builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.e(TAG, "onGesturePerformed");
gestureLibrary.addGesture("Toast", gesture);
if (gestureLibrary.save())
Toast.makeText(MainActivity.this, "保存手势成功!",Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "用户取消", Toast.LENGTH_SHORT).show();
}
});
builder.show();
} else {
Log.e(TAG, "长度需超过20个像素!");
}
}
});
}
//跳转到手势识别activity
public void recogniz(View view) {
startActivity(new Intent(this, RecognizActivity.class));
}
布局文件中添加:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="recogniz"
android:text="点击识别保存的手势" />
在布局文件中添加了一个按钮,点击按钮跳到RecognizeActivity类里面,这个类现在不存在,我们新建一个,然后里面的
代码如下:
public class RecognizActivity extends AppCompatActivity {
private GestureOverlayView overlayView;
private File file;
private GestureLibrary gestureLibrary;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recogniz);
overlayView = (GestureOverlayView) findViewById(R.id.gestureView1);
file = new File(Environment.getExternalStorageDirectory(), "gesture");
//保存手势和识别手势的对象
gestureLibrary = GestureLibraries.fromFile(file);
//一定要调用这个
gestureLibrary.load();
//手势确认的时候调用
overlayView.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
@Override
public void onGesturePerformed(GestureOverlayView overlay, final Gesture gesture) {
ArrayList<Prediction> predictions = gestureLibrary.recognize(gesture);
Log.e("识别出:",predictions.size()+"");
for (int i = 0; i < predictions.size(); i++) {
Log.e(predictions.get(i).name, predictions.get(i).score + "");
if (predictions.get(i).score>2)
Toast.makeText(RecognizActivity.this,"识别成功!匹配度:"+predictions.get(i).score,Toast.LENGTH_SHORT).show();
}
}
});
}
}
布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imgv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:src="@drawable/background" />
<android.gesture.GestureOverlayView
android:id="@+id/gestureView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gestureColor="#f00"
android:gestureStrokeType="multiple"
android:gestureStrokeWidth="10"
android:uncertainGestureColor="#0f0" />
</RelativeLayout>
因为GestureOverlayView是继承与FrameLayout的,是一种帧布局,我们让他浮在一个ImageView上面。在GestureLibraries调用recognize识别手势的时候,返回一个
Prediction,这个类有两个属性,一个是name,一个是score,name是识别出来的手势保存的时候的名字,score是匹配度,一般认识大于2的话就可以认为识别成功了,最高是10,OK,改完之后我们来运行效果:
扫描关注我的微信公众号:
总结:
要绘制一个手势,我们可以使用GestureOverlayView,这是一个控件,我们可以直接在布局文件中定义,它是帧布局的子类,可以直接覆盖在别的View上面,在activity中find这个控件,然后给一个监听,在绘制完成的时候自动调用监听,监听里面可以得到保存的手势,我们可以使用GestureLibraries来保存手势,GestureLibraries是把手势保存到一个文件中,一个文件中可以保存多个手势,区别不同的手势是通过文件名字的,GestureLibraries也可以用来识别手势,通过函数recognize来识别,该函数返回的是一个集合,里面的泛型是Prediction,Prediction有两个变量一个是name保存匹配的手势的名字,个是score保存的是匹配的相识度,如果score的值超过2我们就可以认识匹配成功了。OK,最后附上demo:demo下载