Android手势识别GestureOverlayView手势消除和多笔画识别问题
最近做的一个项目,要求将手势(Gesture)由用户自定义储存,然后再根据用户划出的手势分别启动相应的功能。在网上查找了一些资料,发现可以使用Android 1.6开始支持的手势识别功能,至于完成笔画绘制的部分可以直接使用GestureOverlayView来完成。在Android的模拟器了预装了一个叫GesturesBuilder的程序(最近的4.4还有,源码:http://download.youkuaiyun.com/detail/xiaowan0404/7852261)。通过对这个软件的源码学习以及网上的资料,完成的还算顺利,不过却遇到了两个问题,也就是标题中所说的自动消除和多笔画识别不准确。不过要解决这两个问题却有点麻烦,我直接说结论吧,Android的源码就是这样的,它并没有提供相应的API来给我们使用,所以我觉得这里Android只是给我们提供了一个“半成品”,尽管以我的水平来说,要写出这么一个半成品还是远远不足。
http://blog.youkuaiyun.com/stevenhu_223/article/category/1515741
这里已经把Android手势识别源码说明的很详细了,一些API我就不列出来,Android的官方文档和网上就有很多资料了。我就说一些值得注意之处。
http://download.youkuaiyun.com/detail/xiaowan0404/8039051
这是手势识别相关源代码。
GestureStore
GestureStore里面的两个方法:setOrientationStyle(int style)和void setSequenceType(int type)。我们可以看一下源码:
public static final int SEQUENCE_INVARIANT = 1;
// when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed
public static final int SEQUENCE_SENSITIVE = 2;
// ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures
public static final int ORIENTATION_INVARIANT = 1;
// at most 2 directions can be recognized
public static final int ORIENTATION_SENSITIVE = 2;
// at most 4 directions can be recognized
static final int ORIENTATION_SENSITIVE_4 = 4;
// at most 8 directions can be recognized
static final int ORIENTATION_SENSITIVE_8 = 8;
这里注意,只有ORIENTATION_INVARIANT和ORIENTATION_SENSITIVE是public的,但是我们在外面调用时也是可以直接set 4和8的。
public void setOrientationStyle(int style) {
mOrientationStyle = style;
}
public void setSequenceType(int type) {
mSequenceType = type;
}
这两个方法对于提高识别精度个人认为还是很重要的,不然有时候我们画一条斜率是45度的直线,它直接给把横线的情况识别出来了。
GestureOverlayView
setGestureVisible(boolean visible):手势是否可见。
setFadeEnabled(boolean fadeEnabled):这个方法不是设置手势是否自动清除的,只是手势消散动画的开关。
setFadeOffset(long fadeOffset):手势多少毫秒后消除,或调用onGesturePerformed(手势识别Listener方法)的时间间隔(如果调用)。
所以自动消除的问题来了,如果想让手势识别进行后不会自动消散的话,Android并没有给出API。
private void clear(boolean animated, boolean fireActionPerformed, boolean immediate) {
setPaintAlpha(255);
removeCallbacks(mFadingOut);
mResetGesture = false;
mFadingOut.fireActionPerformed = fireActionPerformed;
mFadingOut.resetMultipleStrokes = false;
if (animated && mCurrentGesture != null) {
mFadingAlpha = 1.0f;
mIsFadingOut = true;
mFadingHasStarted = false;
mFadingStart = AnimationUtils.currentAnimationTimeMillis() + mFadeOffset;
postDelayed(mFadingOut, mFadeOffset);
} else {
mFadingAlpha = 1.0f;
mIsFadingOut = false;
mFadingHasStarted = false;
if (immediate) {
mCurrentGesture = null;
mPath.rewind();
invalidate();
} else if (fireActionPerformed) {
postDelayed(mFadingOut, mFadeOffset);
} else if (mGestureStrokeType == GESTURE_STROKE_TYPE_MULTIPLE) {
mFadingOut.resetMultipleStrokes = true;
postDelayed(mFadingOut, mFadeOffset);
} else {
mCurrentGesture = null;
mPath.rewind();
invalidate();
}
}
}
再看一下mFadingOut相关的代码,可以看到,无论怎么样,它总会调用rewind()和invalidate()方法,所以最后手势是会消散的。
多笔识别问题
我遇到一个坑爹问题就是多笔识别时,如果第一笔相同,那么这两个手势一定会判断判断为相似,如“一”,“二”,“三”等。
可以看代码:
private static float[] temporalSampler(int orientationType, Gesture gesture) {
//这里是get(0)
float[] pts = GestureUtils.temporalSampling(gesture.getStrokes().get(0),
SEQUENCE_SAMPLE_SIZE);
float[] center = GestureUtils.computeCentroid(pts);
float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]);
float adjustment = -orientation;
if (orientationType != GestureStore.ORIENTATION_INVARIANT) {
int count = ORIENTATIONS.length;
for (int i = 0; i < count; i++) {
float delta = ORIENTATIONS[i] - orientation;
if (Math.abs(delta) < Math.abs(adjustment)) {
adjustment = delta;
}
}
}
GestureUtils.translate(pts, -center[0], -center[1]);
GestureUtils.rotate(pts, adjustment);
return pts;
}
其他代码分析可以在我上文分享的链接里查看。可以看到这里只是取了第一笔,那么相同也就理所当然了。
总结
我的项目是基于Android系统开发的,所以我适当修改了源代码,这只是一种权宜之技罢了。我本人也是一个初学者,对这一块也是刚起步,所以怎么达到更好的识别,还得靠各位牛人出手以及更加深入学习了。以上只是我的一点学习心得,如有错误请各位多多指教。