2010-10-13 23:46
本文是八月虎的一篇翻译稿,原文见:http://blog.7touchgroup.com/tag/android-scrollview-linearlayout-scrollbar/
触摸屏是移动设备上伟大的互动方式之一。通过触摸屏,用户可以点击、拽拉、摇晃,或在具体应用中使用快速操作动作。但是这些特性开发起来不容易。android可以轻松识别简单的手势动作,比如:刷屏动作,但是识别复杂的手势还是比较困难的,也需要开发者写很多代码。这就是我们为什么决心要介绍Android 1.6上的一个新手势API。该API位于一个新的包文件:android.gesture,你可以存储、加载、绘制和识别手势。该贴中,我会介绍如何在应用中使用android.gesture API。在这之前,你最好下载例程源码。 http://code.google.com/p/apps-for-android/downloads/detail?name=GesturesDemos.zip&can=2&q=#makechanges 一。创建手势库 Android 1.6 SDK中的模拟器内置了一个Gestures Builder软件。你可以为你的应用来创建一组预定义好的手势。它也作为一个例子来指导如何让用户为你的应用定义用户自己的手势。你可以在Android 1.6的samples目录下找到Gestures Builders的源码。在我们的例子中,我们将使用Gestures Builder来为我们生成一组手势。下面是应用增加了一些手势后的屏幕图片。 正如你看到的,一个手势总是和一个名字联系在一起。这个名字是非常重要的,因为它在你的应用中标识了各个不同的手势。名字是不必唯一的。实际上,用一个名字来标识多个手势,某种程度上还可以提高识别的准确率。使用Gestures Builder,每次edit或add一个手势时,一个文件就会在模拟器的SD Card、/sdcard/gestures目录下生成。这个文件包含了所有手势的描述,你可以将该文件打包到你的应用中,放在资源文件夹/res/raw下。 二。加载手势库 现在你已经有了一组预先定义好的手势,你需要加载它们到你的应用中。这可以使用多个方法来实现,但是最容易的方法是使用 GestureLibraries类。 mLibrary = GestureLibraries.fromRawResource(this, R.raw.spells); if (!mLibrary.load()) { finish(); } 在这个例子中,手势库从文件/res/raw/spells加载,你也可以非常容易地从其他来源加载手势库,如SD card,如果你需要把应用的手势库存储起来,SD card就比较重要。从raw 数据源加载的库是只读的,不能被修改。下面的图表展示了库结构: 三。识别手势 启动手势识别,你仅需要加载一个GestureOverlayView到你的XML Layout: <android.gesture.GestureOverlayView android:id="@+id/gestures" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1.0" /> 注意:GestureOverlayView不是通常的android.widget包的一部分。所以,你必须使用它的全称。一个手势Overlay作为一个简单的用户可以用来画自己手势的画板。你可以调整多个视觉属性,比如:手势的颜色和笔画粗细,以及注册多个listeners来响应用户的手势指令。最常用的listener是GestureOverlayView.OnGesturePerformedListener,当用户画完手势后用来触发响应: GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures); gestures.addOnGesturePerformedListener(this); 当listener触发时,你可以用GestureLibrary来识别手势。你能够得到一组预测实例结果,这些预测结果每个都对应着一个名字,也就是你当初用Gestures Builder时输入的名字,以及预测的结果分值。预测结果数组按照分值大小从高到低排序。越高的分值,说明手势越接近用户所画的手势。下面的代码片段说明了如何获取第一个预测手势结果: public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { ArrayList predictions = mLibrary.recognize(gesture); // We want at least one prediction if (predictions.size() > 0) { Prediction prediction = predictions.get(0); // We want at least some confidence in the result if (prediction.score > 1.0) { // Show the spell Toast.makeText(this, prediction.name, Toast.LENGTH_SHORT).show(); } } } 在这个例子中,当预测分值大于1.0时,第一个预测结果生效。采用什么样的阈值完全由自己决定,但是分值低于1.0的结果一般来说都是匹配不好的。下面是一个完整的应用代码,该应用可以识别预先定义好的手势。(see the source code of the project GesturesDemo): 四。手势叠加 在上述例子中,GestureOverlayView作为一个普通的视图view,嵌入到一个LinearLayout中。但是,正如其名,它也可以用来覆盖到其他多个view之上。这在游戏或者其他用户界面中非常有用。第二个例程叫GesturesListDemo, 我们可以生产一个叠加视图,覆盖在一个联系人列表上面。我们再次使用Gestures Builder来创建一组新的预定义手势: 下面是XML layout: <android.gesture.GestureOverlayView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gestures" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gestureStrokeType="multiple" android:eventsInterceptionEnabled="true" android:orientation="vertical"> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </android.gesture.GestureOverlayView> 这个应用中,手势view叠加在ListView之上。叠加view也有几个我们以前没有用到的几个属性: * gestureStrokeType: 指明我们要识别一个单笔画手势还是一个多笔画手势。对于一个 “+” 手势, 我们需要使用多笔画类型。 * eventsInterceptionEnabled: 为true时,叠加view一旦发现用户真的在画手势,将立即接管下面view的事件。当叠加view下面是一个滚动view时比较有用,当用户在画手势时,可以避免底层view滚动。 * orientation: 指明底层view的滚动方向。这种情况下,如果list滚动条为垂直滚动,那么意味着任何水平手势(如 action_delete)可以立即被当做一个手势识别。对于起始笔画为垂直笔画的手势,必须再至少包含一个水平笔画才能识别。也就是说,一个垂直线不能当做一个手势来识别,因为这与list view的滚动事件冲突。用来加载gestures library和叠加view的代码与前文部分完全一样. 唯一一点不同的是我们现在来检查预测结果,以判明用户想要的操作类型是什么: public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { ArrayList<Prediction> predictions = mLibrary.recognize(gesture); if (predictions.size() > 0 && predictions.get(0).score > 1.0) { String action = predictions.get(0).name; if ("action_add".equals(action)) { Toast.makeText(this, "Adding a contact", Toast.LENGTH_SHORT).show(); } else if ("action_delete".equals(action)) { Toast.makeText(this, "Removing a contact", Toast.LENGTH_SHORT).show(); } else if ("action_refresh".equals(action)) { Toast.makeText(this, "Reloading contacts", Toast.LENGTH_SHORT).show(); } } } 用户现在已经可以在List view上画手势,并不再担心和滚动条操作之间的冲突: 叠加view也给出了一些线索,用来判别一个手势是否被成功解读。当一个垂直overlay情况时,比如一个垂直的笔画不能作为一个手势来识别,因此,该笔画将以半透明方式呈现: 五。该你了 在应用中添加手势的功能是比较容易的,并且是一个有价值的附加功能。gestures API 不能用于识别复杂的图形,它在识别简单笔画时比较好用。我们为gestures API提供的功能而激动,我们期望看到社区里面能够制作出更多更COOL的带手势的应用出来。 |