首届 Google 暑期大学生博客分享大赛——2010 Andriod 篇

经过了一段Android的学习,基本上了解了Android的基础知识。今天,我们来研究一下Android中特有的手势识别技术,即Gesture。首先,我从网上找了很多资料,具体归纳起来有2类:一类是触摸屏手势识别,另一类是输入法手势识别。

我们先来讨论一下第一类触摸屏手势识别,这个比较简单,就是利用触摸屏的Fling、Scroll等Gesture(手势)来操作屏幕,比如用Scroll手势在 浏览器中滚屏,用Fling在阅读器中翻页等。在Android系统中,手势的识别是通过 GestureDetector.OnGestureListener接口来实现的。下面通过我自己的一个动手实验来进行介绍。

首先,我们在Eclipse中创建一个工程,名称叫SignFilpDemo。然后,在src中创建一个SignFilpDemo源文件。这个工程是基于Android1.6的。因为,在Android 1.6之前的版本中,需要开发者编写大量的代码才能实现某些更为复杂的Gestures功能。而在之后的版本SDk中嵌入标准的Gestures API库(Package: android.gesture),包括了所有与Gesture技术相关的操作:存储、加载、创建新Gestures和识别等。其工程结构如下:


图1

接着,我们知道Android的事件处理机制是基于Listener(监听器)来实现的,比如我们今天所说的触摸屏相关的事件,就是通过onTouchListener。因此,我们在源代码中要实现这个接口。另外,我们还要实现OnGestureListener接口,因为,那个手势的识别是通过 GestureDetector.OnGestureListener接口来实现的。其中,onTouchEvent方法则是实现了OnTouchListener中的抽象方法,我们只要在这里添加逻辑代码即 可在用户触摸屏幕时做出响应。在这里我们调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给 GestureDetector 来分析是否有合适的callback函数来处理用户的手势。接下来,就是实现了以下6个抽象方法,其中最有用的当然是onFling()、onScroll()和onLongPress()了。下面介绍一下:

(1) 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发,其源代码如下:

public boolean onDown(MotionEvent e) {

return false;

}

public void onShowPress(MotionEvent e) {

}

(2) 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发,其源代码如下:

public boolean onSingleTapUp(MotionEvent e) {

return false;

}

(3) 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发

// 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发

public void onLongPress(MotionEvent e) {

}

// 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,float distanceY) {

return false;

}

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {

return false;

}

我们今天来做一个onFling()事件的处理吧,这里需要注意的是Fling事件的处理代 码中,除了第一个触发Fling的ACTION_DOWN和最后一个ACTION_MOVE中包含的坐标等信息外,我们还可以根据用户在X轴或者Y轴上的 移动速度作为条件。在这个例子中,我们是根据用户在屏幕上移动的x轴坐标或者是y轴坐标位移来判断方向。如果x轴坐标位移大于50向左,小于-50向右,如果y轴坐标位移大于50向上,小于-50向下。源代码如下:

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,

float velocityY) {

if (e1.getX() - e2.getX() > 50) {

Toast.makeText(SignFlipDemo.this, "左", Toast.LENGTH_LONG).show();

return true;

} else if (e1.getX() - e2.getX() < -50) {

Toast.makeText(SignFlipDemo.this, "右", Toast.LENGTH_LONG).show();

return true;

} else if (e1.getY() - e2.getY() > 50) {

Toast.makeText(SignFlipDemo.this, "上", Toast.LENGTH_LONG).show();

return true;

} else if (e1.getY() - e2.getY() < -50) {

Toast.makeText(SignFlipDemo.this, "下", Toast.LENGTH_LONG).show();

return true;

}

return false;

}

如果鼠标向上移动,运行效果如下图2所示:


图2

如果鼠标向下移动,运行效果如下图3所示:


图3

如果鼠标向左移动,运行效果如下图4所示:


图4

如果鼠标向右移动,运行效果如下图5所示:


图5

通过上面的运行结果可以看出,只要鼠标向上下左右四个方向移动,就是相应地识别出,并且显示出相应的方向。这里需要注意的是因为是模拟器,所以只有通过鼠标来模拟,在真机环境中,就是触摸屏的识别了。

接下来,我们来讨论一下第二种输入法手势识别。这种方法就是需要定义一个描述手势动作的文件。在手写输入中,会为每一个字符定义一个特征码,这些特征码都保存在相应的文件中(可能有一个或多个这样的文件),当用户绘制一个描述字符的图形时,系统会为所绘制的图形提取特征码,然后会在保存特征码文件中查找相对应的特征码,如果找到,就会将对应的字符返回。其中,这些文件被称为手势文件。这里我们讨论的是在Android 2.1中提供了一个GestureBuilder工程(实际上从Android 1.6就带这个例子了),这个工程是一个手势API的演示,主要功能是建立手势信息,并将手势信息保存在手势文件中。下面,我们来演示一下。

首先在Eclipse中打开这个工程,然后可以直接导入运行。运行后界面如图6所示。


图6

由于上面还没建立手势,所以手势列表为空。下面开始建立我们的第一个手势。单击“Add gesture”按钮,会进入建立手势的界面。如图7所示。建立手势需要两个信息:手势名和手势图形。在文本框中输入任意的字符串,如“矩形”,并且在文本框下面画一个如图7所示的矩形(差不多就行,不一定要很标准)。然后单击“Done”按钮,第一个手势已经建立成功了。按着这种方法,再建立几个手势。每成功建立完一个手势后,会在主界面的列表中看到我们所建立的手势,如图8所示。进入DDMS透视图,会在SD卡的根目录看到一个gestures文件,如图9所示。然后将该文件导出到PC上,以备以后使用。


图7


图8


图9

通过前面的介绍,我们知道绘制手势图像好像是在一个类似画布的区域,实际上,这是一个android.gesture.GestureOverlayView组件。我们可以在这个组件上绘制手势,并会触发一个识别手势的事件。了解了原理,接下来,我们利用手势自动输入字符串。

首先需要在布局文件中添加一个EditText和GestureOverlayView组件,代码如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<EditText android:id="@+id/edittext"

android:layout_height="wrap_content" android:layout_width="fill_parent"/>

<android.gesture.GestureOverlayView

android:gestureStrokeType="multiple" android:id="@+id/gestures"

android:layout_height="fill_parent" android:layout_width="fill_parent"/>

</LinearLayout>

接着,使用手势文件的第一步是装载手势文件。可以将手势文件放在SD卡的相应目录,也可以放在apk中一起打包。在本例中将gestures文件放在了工程目录的res\raw目录中,因此,这个手势文件是包含在apk文件中的。下面在onCreate方法中装载这个手势文件,代码如下:

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

edittext = (EditText)findViewById(R.id.edittext);

// 从res\raw目录中装载gestures文件

gestureLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures);

// 如果成功装载手势文件,获得GestureOverlayView对象,并向该对象注册事件

if(gestureLibrary.load())

{

setTitle("手势文件装载成功。");

GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);

gestures.addOnGesturePerformedListener((OnGesturePerformedListener) this);

}

else

{

setTitle("手势文件装载失败。");

}

}

处理手势识别事件需要实现GestureOverlayView.OnGesturePerformedListener接口,该接口有一个事件方法,当绘制完手势图形后被调用,可根据相应的API来判断是否成功识别了当前手势,该事件的代码如下:

public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture){

ArrayList predictions = gestureLibrary.recognize(gesture);

if(predictions.size()>0){

// predictions保存了所有与当前手势可能匹配的候选手势

for(int i=0;i<predictions.size();i++)

{

Prediction prediction = (Prediction) predictions.get(i);

if(prediction.score>1.0)

{

// 只选择了第一个与当前手势匹配的手势,将手势名输出的文本框中

edittext.append(prediction.name);

break;

}

}

}


}

运行效果如图10







图10

上面,我们已经实现了输入手势识别,绘制手势,程序自动输入对应的文本。主要是导入外部的手势文件进行识别。

本文主要介绍了Android中的两种手势识别技术。一类是触摸屏手势识别,另一类是输入法手势识别。相比较,第一种容易实现,第二种实现起来复杂,还要创建手势文件。在实验中,我碰到一个问题,那就是DDMS中没有显示sdcard文件,这耗费我很长时间,后来只能通过外面的DDMS工具导入gestrue文件。如果有知道的朋友告诉我一下,在此表示谢谢。其实,在第二种识别中,我们可以不用自带的GestureBuilder文件来创建手势文件,那个相对复杂一些,可以自己写一个工程来创建。这里篇幅有限,就留给读者自己思考了。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tsdl2009/archive/2010/08/13/5810922.aspx
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值