自 SDK 1.6 开始,Android手机已支持内置 Gesture Builder 程序,若是被Google签署(Signed)过出厂的手机应会内置此程序。

Gesture Builder 提供了手写识别的功能,让用户以类似于涂鸦的方式绘制一个手写符号,对应一个字符串名称,存储在 /mnt/sdcard/gestures 文件中。

为了练手,编写了Gesture Builder的应用程序,运行效果如下:


界面布局如下:

gesture_builder.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/black"><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:id="@+id/gesture_builder_layout_top"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp"android:textSize="18sp"android:textColor="@android:color/white"android:text="名称:"/><EditTextandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:inputType="text"android:background="@android:color/white"android:id="@+id/gesture_builder_txt_name"/></LinearLayout><android.gesture.GestureOverlayViewandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:gestureStrokeType="multiple"android:gestureColor="#FFFF00"android:layout_below="@+id/gesture_builder_layout_top"android:layout_above="@+id/gesture_builder_layout_bottom"android:layout_marginRight="30dp"android:id="@+id/gesture_builder_gesture_overlay_view" ></android.gesture.GestureOverlayView><SlidingDrawerandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:content="@+id/gesture_builder_content"android:handle="@+id/gesture_builder_handler"android:id="@+id/gesture_builder_sliding_drawer"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:contentDescription="SlidingDrawer"android:src="@drawable/thumb_select"android:id="@+id/gesture_builder_handler"/><ListViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:choiceMode="singleChoice"android:background="@drawable/listview_bg"android:divider="@drawable/listview_divider_style"android:dividerHeight="2dp"android:id="@+id/gesture_builder_content"></ListView></SlidingDrawer><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:weightSum="2"android:layout_alignParentBottom="true"style="@android:style/ButtonBar"android:orientation="horizontal"android:id="@+id/gesture_builder_layout_bottom"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="Done"android:id="@+id/gesture_builder_btn_done"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="Discard"android:id="@+id/gesture_builder_btn_discard"/></LinearLayout></RelativeLayout>

gesture_builder_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal" android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content" android:id="@+id/gesture_builder_list_image"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:lines="1"android:textColor="#f69900"android:textSize="18sp"android:textStyle="bold"android:id="@+id/gesture_builder_list_text"/></LinearLayout>

样式风格如下:

listview_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><gradientandroid:startColor="#1C86EE"android:centerColor="#FFFFFF"android:endColor="#1C86EE"android:centerX="0.1"android:angle="135" /></shape>

listview_divider_style.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><gradientandroid:startColor="#eeee00"android:centerColor="#ff4500"android:endColor="#eeee00"/>
</shape>

适配器如下:

GestureBuilderAdapter.java

package com.xx.xx;import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;import java.util.List;public class GestureBuilderAdapter extends BaseAdapter {private Context context;private List<String> names;private List<Bitmap> bitmaps;public GestureBuilderAdapter(Context context, List<String> gestureNames, List<Bitmap> gestureBitmaps){this.context = context;this.names = gestureNames;this.bitmaps = gestureBitmaps;}@Overridepublic int getCount() {return this.names.size();}@Overridepublic Object getItem(int position) {return names.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {convertView = LayoutInflater.from(context).inflate(R.layout.gesture_builder_list_item, null);ImageView imageView = (ImageView)convertView.findViewById(R.id.gesture_builder_list_image);imageView.setImageBitmap(bitmaps.get(position));TextView textView = (TextView)convertView.findViewById(R.id.gesture_builder_list_text);textView.setText(names.get(position));return convertView;}
}

Activity如下:

GestureBuilderActivity.java

package com.xx.xx;import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
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.os.Environment;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SlidingDrawer;
import android.widget.Toast;import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class GestureBuilderActivity extends Activity {private LinearLayout top;private EditText txtName;private LinearLayout bottom;private Button btnDone;private GestureOverlayView gestureOverlayView;private SlidingDrawer slidingDrawer;private ListView listView;private ImageView imageView;/*** 当前手势*/private Gesture gesture;/*** 手势文件的存储路径*/private String gesPath;/*** 手势名称列表*/private List<String> gestureNames = new ArrayList<>();/*** 手势图片列表*/private List<Bitmap> gestureBitmaps = new ArrayList<>();/*** 适配器*/private GestureBuilderAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.gesture_builder);/*** 检测sdcard是否存在*/if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){Toast.makeText(this, "sdcard不存在!", Toast.LENGTH_SHORT).show();finish();}/*** 手势文件默认存储在“/mnt/sdcard/gestures”文件中*/gesPath = new File(Environment.getExternalStorageDirectory(), "gestures").getAbsolutePath();/*** ListView适配器*/adapter = new GestureBuilderAdapter(this, gestureNames, gestureBitmaps);top = (LinearLayout)findViewById(R.id.gesture_builder_layout_top);txtName = (EditText)findViewById(R.id.gesture_builder_txt_name);gestureOverlayView = (GestureOverlayView)findViewById(R.id.gesture_builder_gesture_overlay_view);bottom = (LinearLayout)findViewById(R.id.gesture_builder_layout_bottom);btnDone = (Button)findViewById(R.id.gesture_builder_btn_done);Button btnDiscard = (Button)findViewById(R.id.gesture_builder_btn_discard);slidingDrawer = (SlidingDrawer)findViewById(R.id.gesture_builder_sliding_drawer);imageView = (ImageView)findViewById(R.id.gesture_builder_handler);listView = (ListView)findViewById(R.id.gesture_builder_content);/*** Done按钮默认不可用*/btnDone.setEnabled(false);/*** 当名称不为空时,Done按钮可用*/txtName.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (gesture != null && txtName.getText().toString().trim().length() > 0){btnDone.setEnabled(true);} else {btnDone.setEnabled(false);}return false;}});/*** 监听gesture,实现gesture开始和结束的事件*/gestureOverlayView.addOnGestureListener(new GestureOverlayView.OnGestureListener() {@Overridepublic void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {gesture = null;btnDone.setEnabled(false);}@Overridepublic void onGesture(GestureOverlayView overlay, MotionEvent event) {}@Overridepublic void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {gesture = overlay.getGesture();if (gesture != null && txtName.getText().toString().trim().length() > 0) {btnDone.setEnabled(true);}}@Overridepublic void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {}});/*** 添加手势*/btnDone.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String name = txtName.getText().toString().trim();GestureLibrary library = GestureLibraries.fromFile(gesPath);File file = new File(gesPath);/*** 若gestures文件存在,则判断是否有同名手势已经存在,若有,则移除后添加,若没有直接添加*/if (file.exists()){if (library.load()){Set<String> entries = library.getGestureEntries();if (entries.contains(name)){List<Gesture> list = library.getGestures(name);for (int i=0;i<list.size();i++){library.removeGesture(name, list.get(i));}}}}/*** 添加手势*/library.addGesture(name, gesture);/*** 保存手势*/if (library.save()){txtName.setText("");gestureOverlayView.clear(true);btnDone.setEnabled(false);Toast.makeText(GestureBuilderActivity.this, "保存成功,路径为:"+gesPath, Toast.LENGTH_SHORT).show();}else{Toast.makeText(GestureBuilderActivity.this, "保存失败", Toast.LENGTH_SHORT).show();}/*** 拉开抽屉,显示gesture列表*/slidingDrawer.toggle();}});/*** 取消手势*/btnDiscard.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {txtName.setText("");gestureOverlayView.clear(true);gesture = null;btnDone.setEnabled(false);}});/*** 初始化ListView*/listView.setAdapter(adapter);UpdateGestureList();/*** 抽屉打开,显示ListView*/slidingDrawer.setOnDrawerOpenListener(new SlidingDrawer.OnDrawerOpenListener() {@Overridepublic void onDrawerOpened() {imageView.setImageResource(R.drawable.thumb_normal);top.setVisibility(View.GONE);gestureOverlayView.setVisibility(View.GONE);bottom.setVisibility(View.GONE);GestureBuilderActivity.this.UpdateGestureList();}});/*** 抽屉关闭,隐藏ListView*/slidingDrawer.setOnDrawerCloseListener(new SlidingDrawer.OnDrawerCloseListener() {@Overridepublic void onDrawerClosed() {imageView.setImageResource(R.drawable.thumb_select);top.setVisibility(View.VISIBLE);gestureOverlayView.setVisibility(View.VISIBLE);bottom.setVisibility(View.VISIBLE);}});/*** 长按删除*/listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {AlertDialog.Builder builder = new AlertDialog.Builder(GestureBuilderActivity.this);builder.setTitle("是否删除该项?");builder.setIcon(R.drawable.ic_launcher);builder.setMessage("点击确定,将删除该手势!");builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {String name = gestureNames.get(position);File file = new File(gesPath);if (file.exists()){GestureLibrary library = GestureLibraries.fromFile(file);if (library != null && library.load()){ArrayList<Gesture> gestures = library.getGestures(name);if (gestures != null){for (Gesture ges : gestures){library.removeGesture(name, ges);}}library.save();GestureBuilderActivity.this.UpdateGestureList();}}}});builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {return;}});AlertDialog dialog = builder.create();dialog.show();return false;}});}/*** 重新读取gestures中的手势,更新ListView*/private void UpdateGestureList(){/*** 读取gestures中的手势*/File file = new File(gesPath);if (!file.exists()){return;}gestureNames.clear();gestureBitmaps.clear();GestureLibrary library = GestureLibraries.fromFile(file);if (library == null || !library.load()){return;}Object[] names = library.getGestureEntries().toArray();if (names == null || names.length < 1){return;}for (Object obj : names){String name = obj.toString();ArrayList<Gesture> gestures = library.getGestures(name);if (gestures != null){for (Gesture ges : gestures){gestureNames.add(name);gestureBitmaps.add(ges.toBitmap(80,80,12,Color.YELLOW));}}}adapter.notifyDataSetChanged();}
}

在 AndoridManifest.xml 中需要定义访问外部存储的权限。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

参考文章:http://blog.csdn.net/ta893115871/article/details/7822816

Android : Gesture Builder:自定义手势文件相关推荐

  1. android自定义手势,Android编程实现自定义手势的方法详解

    本文实例讲述了Android编程实现自定义手势的方法.分享给大家供大家参考,具体如下: 之前介绍过如何在Android程序中使用手势,主要是系统默认提供的几个手势,这次介绍一下如何自定义手势,以及如何 ...

  2. 使用kinect和visual gesture builder建立手势库实现手势识别

    目录 写在最前 第一部分 手势分割 第二部分 使用VGB实现手势识别[重点] 2.1 Unity3D手势识别工程建立 2.2 手势库建立及使用 第三部分 进阶手势识别 结语 写在最前 不知不觉距离上一 ...

  3. Android实例-使用自定义字体文件(XE8+小米2)

    结果: 1.需要修改DELPHI自身的FMX.FontGlyphs.Android.pas,复制到程序的根目录下(红色部分为修改过的). 2.字体文件从 C:\Windows\Fonts 直接拷贝到A ...

  4. 【Android游戏开发十七】让玩家自定义手势玩转Android游戏!—Android Gesture之【输入法手势技术】...

    为什么80%的码农都做不了架构师?>>>     李华明Himi 原创,转载务必在明显处注明: 转载自 [黑米GameDev街区] 原文链接:  http://www.himigam ...

  5. 【Android游戏开发十七】让玩家自定义手势玩转Android游戏!—Android Gesture之【输入法手势技术】

    Himi  原创, 欢迎转载,转载请在明显处注明! 谢谢. 原文地址:http://blog.csdn.net/xiaominghimi/archive/2011/01/14/6137136.aspx ...

  6. android自定义手势,Android实现自定义手势和识别手势的功能

    这篇文章主要介绍了Android实现自定义手势和识别手势的功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 1. 先完成自定义手势的Activity 1.1 因 ...

  7. 【Android游戏开发十七】让玩家自定义手势玩转Android游戏!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/340.html   ...

  8. 【ANDROID游戏开发十六】ANDROID GESTURE之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/android-game/337.html - ...

  9. Android 建立自己的手写笔画图案 Gesture Builder

    利用反射去存储对对象到SharedPreferences http://www.eoeandroid.com/thread-202940-1-1.html 基于Android平台的车辆信息查询系统的开 ...

最新文章

  1. Python自动化测试框架之Pytest教程【让你小鸡变老鹰】
  2. mysql怎么设置计划任务_mysql设置定时任务
  3. 外贸常用术语_推荐必看!外贸、货代人订舱常用术语及订舱单中英对照!收藏备用...
  4. 计算机游戏50关,YELLOW游戏全50关攻略
  5. dbunit使用_使用dbUnit,JSON,HSQLDB和JUnit规则进行数据库单元测试
  6. 【LeetCode笔记】160. 相交链表(Java、链表)
  7. Swift中文教程(四) 集合类型
  8. Dubbo服务暴露(导出)流程
  9. C#笔记20:多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent
  10. SpringBoot入门教程(十四)导出Excel
  11. 解析小觅中通过双目相机生成深度图的代码
  12. Ubuntu桌面版以太网无法设置IP
  13. http://blog.csdn.net/LANGXINLEN/article/details/50421988
  14. 极智AI | 教你 tensorrt 实现 mish 算子
  15. 多位数的各位数数字提取方法
  16. 运筹优化——生产排程问题简介
  17. 试题 算法训练 无聊的逗 - 蓝桥杯
  18. 【时间序列】python与时间序列基本教程4(超过1.9万字 代码超过900行 包括49个图)...
  19. flash 林度_知乎日报
  20. CSS第三级选择器 Selectors Level 3 文档翻译

热门文章

  1. linux5.8抓包,Linux 抓包工具 tcpdump
  2. layui loading动画_javascript制作loading动画效果 loading效果
  3. pytorch 错误 ImportError numpy.core.multiarray failed to import
  4. 机智云DUT实现远程智能鱼池管理系统
  5. 微服务生态系统的4层模型
  6. 让相同的div浮动到同一行或者同一列
  7. 回忆中的经典——猫和老鼠
  8. 大数据和物联网哪个更有前景?
  9. 【译】代码中如何写出更有意义的命名
  10. 计算机网络实验:虚拟局域网VLAN的配置