进行软件开发时,通常我们都喜欢使用较新版本的工具,但这里我为什么使用低版本的SDK来开发Android游戏呢?这里介绍下原因:

1、Android SDK 属于向下兼容!那么低版本可以运行的,高版本基本上更是没问题!(当然每次SDK的更新也会带来新功能,或者修改了一些原来的BUG等等,那么其实对于游戏开发来说,如果你的游戏中不需要更高的SDK版本的支持情况下,完全不必去追求最新的SDK!)

2、使用低版本进行游戏开发这样能兼顾更多的机型,获取更多的用户!

3、大家都知道Android SDK 每次版本的更新,底层代码也会更健壮和优化了!比如我们公司的网游Android版在G2(SDK1.5)上跑起来稍微有些卡,而在我的手机上(SDK2.2)运行起来流畅的没说的~各种舒坦~~但是这样也会带来一些弊端,比如我们自己游戏如果上来就用高版本SDK进行开发,那么对于性能、内存上到底如何,我们都不会很容易的看出其效果,如果我们用低版本的SDK则会让我们明显的感受到性能到底如何~你想想如果你的游戏在1.5 ,1.6上跑起来很流畅,那放在更高版本的SDK机器上更是没说的啦~

总结:游戏开发中,如果你游戏不需要更高的API的支持,那么推荐基于SDK 1.5和1.6来开发!

在上一篇中我给大家介绍了触摸屏手势操作,但是这种触屏手势的操作比较有局限性;比如我们都知道Android可以利用手势来解锁,类似九宫格形式的,通过自定义的一个单笔画手势可以解开屏幕锁,还可以自定义笔画手势来启动一个应用等,那么这种所谓的笔画手势其实就是今天我要给大家讲解的输入法手势识别技术!这种手势是我们可以自己来自定义,而不像之前的触屏手势操作只是利用Android 对一些触屏动作的封装罢了。下面上几张手机自定义笔划手势解锁的的截图:

OK,那么既然利用手势既然能进行解锁等操作,那么我们游戏开发中,更是可以加入这一亮点了,比如在游戏中我画个圆形执行换背景操作,画个X表示退出游戏等等,等等、哈哈 是不是感觉很有意思了?好的,下面就开始进入讲解!

首先本篇主要学习两点:

  1、如何创建输入法手势、删除输入法手势、从SD卡中读取出手势文件!

2、当输入法手势创建后,如何来匹配出我们的自定义手势!

下面我们来熟习两个类和几个概念:

1、什么是 GestureOverlayView ?  简单点说其实就是一个手写绘图区;

2、什么是 GestureLibrary ?   这个类是对手势进行保存、删除等操作的,一个存放手势的小仓库!

3、笔划是什么,字体笔画?  是的,其实就是跟我们写字的笔划一个概念!

4、什么是笔划类型?   输入法手势操作中,笔划类型有两种;一种是:单一笔划,另外一种是:多笔划

所谓单一笔划笔划就是一笔划画出一个手势,从你手指接触屏幕开始到你离开屏幕笔画就会立刻形成一个手势!一气呵成!

而多笔划则是可以在一定紧凑时间内随意几笔划都可,然后超过这个紧凑时间后便会形成一个手势!

先出项目截图,简单说下其功能和操作:

图1界面中分为3块,从上到下依次是:TextView ,EditText,SurfaceView;然后在SurfaceView后面还有一个覆盖全屏的GestureOverlayView!

图2界面是在创建好的手势中匹配手势的界面,这里很清晰看出来,找的很对 ~嘿嘿~

先看下main.xml:

XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical" android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <TextView android:id="@+id/himi_tv" android:layout_width="fill_parent"
  6. android:layout_height="wrap_content" android:text="@string/hello"
  7. android:textSize="15sp" android:textColor="#FFFFFF00" />
  8. <EditText android:id="@+id/himi_edit" android:layout_width="fill_parent"
  9. android:layout_height="wrap_content" />
  10. <RelativeLayout android:layout_width="fill_parent"
  11. android:layout_height="wrap_content" android:layout_weight="1">
  12. <com.himi.MySurfaceView android:id="@+id/view3d"
  13. android:layout_width="fill_parent" android:layout_height="fill_parent" />
  14. <android.gesture.GestureOverlayView
  15. android:id="@+id/himi_gesture" android:layout_width="fill_parent"
  16. android:layout_height="fill_parent" android:layout_weight="1.0"/>
  17. </RelativeLayout>
  18. </LinearLayout>

xml中注册的有我们自定义的surfaceview,对此不太熟悉可以去看下Android游戏开发6,不多解释了。关于GestureOverlayView这里也只是简单的定义了宽高,还有一些重要的属性设置在代码中设置了,当然xml也可以设置的。

下面看MainActivity.java:

Java代码
  1. /**
  2. *@author Himi
  3. *@输入法手势识别
  4. *@注意: android.gesture这个类在api-4(SDK1.6)才开始支持的!
  5. *@提醒:默认存到SD卡中,所以别忘记在AndroidMainfest.xml加上SD卡读写权限!
  6. */
  7. public class MainActivity extends Activity {
  8. private GestureOverlayView gov;// 创建一个手写绘图区
  9. private Gesture gesture;// 手写实例
  10. private GestureLibrary gestureLib;//创建一个手势仓库
  11. private TextView tv;
  12. private EditText et;
  13. private String path;//手势文件路径
  14. private File file;//
  15. @Override
  16. public void onCreate(Bundle savedInstanceState) {
  17. super.onCreate(savedInstanceState);
  18. this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  19. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  20. this.requestWindowFeature(Window.FEATURE_NO_TITLE);
  21. setContentView(R.layout.main);
  22. tv = (TextView) findViewById(R.id.himi_tv);
  23. et = (EditText) findViewById(R.id.himi_edit);
  24. gov = (GestureOverlayView) findViewById(R.id.himi_gesture);
  25. gov.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);//设置笔划类型
  26. // GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE 设置支持多笔划
  27. // GestureOverlayView.GESTURE_STROKE_TYPE_SINGLE 仅支持单一笔划
  28. path = new File(Environment.getExternalStorageDirectory(), "gestures").getAbsolutePath();
  29. //得到默认路径和文件名/sdcard/gestures
  30. file = new File(path);//实例gestures的文件对象
  31. gestureLib = GestureLibraries.fromFile(path);//实例手势仓库
  32. gov.addOnGestureListener(new OnGestureListener() { // 这里是绑定手写绘图区
  33. @Override
  34. // 以下方法是你刚开始画手势的时候触发
  35. public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
  36. tv.setText("请您在紧凑的时间内用两笔划来完成一个手势!西西~");
  37. }
  38. @Override
  39. // 以下方法是当手势完整形成的时候触发
  40. public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
  41. gesture = overlay.getGesture();// 从绘图区取出形成的手势
  42. if (gesture.getStrokesCount() == 2) {//我判定当用户用了两笔划
  43. //(强调:如果一开始设置手势笔画类型是单一笔画,那你这里始终得到的只是1!)
  44. if (event.getAction() == MotionEvent.ACTION_UP) {//判定第两笔划离开屏幕
  45. //if(gesture.getLength()==100){}//这里是判定长度达到100像素
  46. if (et.getText().toString().equals("")) {
  47. tv.setText("由于您没有输入手势名称,so~保存失败啦~");
  48. } else {
  49. tv.setText("正在保存手势...");
  50. addGesture(et.getText().toString(), gesture);//我自己写的添加手势函数
  51. }
  52. }
  53. } else {
  54. tv.setText("请您在紧凑的时间内用两笔划来完成一个手势!西西~");
  55. }
  56. }
  57. @Override
  58. public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
  59. }
  60. @Override
  61. public void onGesture(GestureOverlayView overlay, MotionEvent event) {
  62. }
  63. });
  64. //----这里是在程序启动的时候进行遍历所有手势!------
  65. if (!gestureLib.load()) {
  66. tv.setText("Himi提示:手势超过9个我做了删除所有手势的操作,为了界面整洁一些!"
  67. + " 输入法手势练习~(*^__^*)~ 嘻嘻!/n操作介绍:(画手势我设置必须画两笔划才行哦~)/n1." +
  68. "添加手势:先EditText中输入名称,然后在屏幕上画出手势!/n2.匹配手势:"
  69. + "在EditText输入/"himi/",然后输入手势即可! ");
  70. } else {
  71. Set<String> set = gestureLib.getGestureEntries();//取出所有手势
  72. Object ob[] = set.toArray();
  73. loadAllGesture(set, ob);
  74. }
  75. }
  76. }

这个就是MainActivity主要代码了,其中添加手势、匹配手势、遍历手势、将手势转成图片这些我都单独写成了函数,这样让各位童鞋更清晰思路一些。

从以上代码中我们看出在创建手势之前,手写绘图区(GestureOverlayView)肯定先被创建出来,然后我们就可以在其区域中进行笔划绘画手势了,当然绘画手势前,我们也需要设置了笔划类型,也就是我一开始给大家介绍的,其后最重要的就是手写绘图区的手势监听器绑定,增加OnGestureListener这个监听器重写了四个函数,这里最重要的就两个函数:

onGestureStarted   和  onGestureEnded  :手势开始和手势结束的监听函数。

尤其是手势结束监听这个函数尤为重要,在其中我设置好几个条件语句,这么几个条件一方面是让大家了解Gesture中一些比较重要常用的方法,另一方面我要提醒各位童鞋:

如果你设置笔划类型是多笔划类型的,那么理想状态下,应该是在一段紧凑时间内,不管你使用了几笔划来绘制手势,系统都应该在判定你在一定短暂时间内没有再进行笔划的时候才应该创建手势,并且系统响应此函数;

其实错了,一开始我也这么想,但是发现,不管你设置的笔划类型是单一的还是多笔划当你手指离开屏幕,不管你当前是第几笔,Android都会去响应这个完成函数,so~ 我在这里调用手势Gesture类中的getStrokesCount()函数,这个函数会记录在紧凑时间内你绘制手势的笔划数,那么根据这个函数我们就可以解决手指离开屏幕总被响应的问题了,因为单一笔划类型永远这个值不会大于1!

而 if (event.getAction() == MotionEvent.ACTION_UP) {}写这个只是给大家演示第二个参数按键动作该怎么用。

那么我们下面就来看如何创建一个手势:

Java代码
  1. public void addMyGesture(String name, Gesture gesture) {
  2. try {
  3. if (name.equals("himi")) {
  4. findGesture(gesture);
  5. } else {
  6. // 关于两种方式创建模拟器的SDcard在【Android2D游戏开发之十】有详解
  7. if (Environment.getExternalStorageState() != null) {// 这个方法在试探终端是否有sdcard!
  8. if (!file.exists()) {// 判定是否已经存在手势文件
  9. // 不存在文件的时候我们去直接把我们的手势文件存入
  10. gestureLib.addGesture(name, gesture);
  11. if (gestureLib.save()) {保存到文件中
  12. gov.clear(true);//清除笔画
  13. // 注意保存的路径默认是/sdcard/gesture ,so~别忘记AndroidMainfest.xml加上读写权限!
  14. // 这里抱怨一下,咳咳、其实昨天就应该出这篇博文的,就是因为这里总是异常,今天仔细看了
  15. // 才发现不是没写权限,而是我虽然在AndroidMainfest.xml中写了权限,但是写错了位置..哭死!
  16. tv.setText("保存手势成功!因为不存在手势文件," + "所以第一次保存手势成功会默认先创" +
  17. "建了一个手势文件!然后将手势保存到文件中.");
  18. et.setText("");
  19. gestureToImage(gesture);
  20. } else {
  21. tv.setText("保存手势失败!");
  22. }
  23. } else {//当存在此文件的时候我们需要先删除此手势然后把新的手势放上
  24. //读取已经存在的文件,得到文件中的所有手势
  25. if (!gestureLib.load()) {//如果读取失败
  26. tv.setText("手势文件读取失败!");
  27. } else {//读取成功
  28. Set<String> set = gestureLib.getGestureEntries();//取出所有手势
  29. Object ob[] = set.toArray();
  30. boolean isHavedGesture = false;
  31. for (int i = 0; i < ob.length; i++) {//这里是遍历所有手势的name
  32. if (((String) ob[i]).equals(name)) {//和我们新添的手势name做对比
  33. isHavedGesture = true;
  34. }
  35. }
  36. if (isHavedGesture) {//如果此变量为true说明有相同name的手势
  37. //----备注1-------------------//gestureLib.removeGesture(name, gesture);//删除与当前名字相同的手势
  38. /*----备注2-----------------*/gestureLib.removeEntry(name);
  39. gestureLib.addGesture(name, gesture);
  40. } else {
  41. gestureLib.addGesture(name, gesture);
  42. }
  43. if (gestureLib.save()) {
  44. gov.clear(true);//清除笔画
  45. gestureToImage(gesture);
  46. tv.setText("保存手势成功!当前所有手势一共有:" + ob.length + "个");
  47. et.setText("");
  48. } else {
  49. tv.setText("保存手势失败!");
  50. }
  51. ------- --以下代码是当手势超过9个就全部清空 操作--------
  52. if (ob.length > 9) {
  53. for (int i = 0; i < ob.length; i++) {//这里是遍历删除手势
  54. gestureLib.removeEntry((String) ob[i]);
  55. }
  56. gestureLib.save();
  57. if (MySurfaceView.vec_bmp != null) {
  58. MySurfaceView.vec_bmp.removeAllElements();//删除放置手势图的容器
  59. }
  60. tv.setText("手势超过9个,已全部清空!");
  61. et.setText("");
  62. }
  63. ob = null;
  64. set = null;
  65. }
  66. }
  67. } else {
  68. tv.setText("当前模拟器没有SD卡 - -。");
  69. }
  70. }
  71. } catch (Exception e) {
  72. tv.setText("操作异常!");
  73. }
  74. }

这里也都很好理解,套路类似之前File文件存储的套路,先判断SD是否存在,然后是文件是否存在:

如果文件不存在就先直接添加到手势到手势仓库中,然后手势仓调用gestureLib.save()才算把手势存到SD卡的手势文件中。

文件存在的话还要去判定是否文件中包含了相同名字的手势;当然这里可以不判定是否有相同手势名存在,然后进行删除操作!其实也可不删除,直接添加进去当前新建的手势;原因看了下面的备注解释就明白了;

备注1:因为gestureLib保存的手势是个HashMap, key=手势的名字,value=手势,所以gestureLib.removeGesture(name, gesture);这种删除方式只是删除了手势,该手势名字依旧保存在hashmap中,下次还有相同的name手势存入的时候Hashmap就直接覆盖本条目了。所以根据Hashmap的特征,我们可以不进行删除操作,可以直接gestureLib.addGesture(name, gesture);因为如果出现相同的手势名字的手势,Hashmap就会根据key(手势的名字)直接覆盖其条目的value(手势)滴~

备注2:这里也是一种删除手势的方式,但是这种方式跟备注1的不同,这里是将Hashmap中的条目删除,也就是说key和value都被删去!

下面看下如何把手势转成bitmap:

Java代码
  1. public void gestureToImage(Gesture ges) {//将手势转换成Bitmap
  2. //把手势转成图片,存到我们SurfaceView中定义的Image容器中,然后都画出来~
  3. if (MySurfaceView.vec_bmp != null) {
  4. MySurfaceView.vec_bmp.addElement(ges.toBitmap(100, 100, 12, Color.GREEN));
  5. }
  6. }

下面是如何遍历手势:

Java代码
  1. public void loadAllGesture(Set<String> set, Object ob[]) { //遍历所有的手势
  2. if (gestureLib.load()) {//读取最新的手势文件
  3. set = gestureLib.getGestureEntries();//取出所有手势
  4. ob = set.toArray();
  5. for (int i = 0; i < ob.length; i++) {
  6. //把手势转成Bitmap
  7. gestureToImage(gestureLib.getGestures((String) ob[i]).get(0));
  8. //这里是把我们每个手势的名字也保存下来
  9. MySurfaceView.vec_string.addElement((String) ob[i]);
  10. }
  11. }
  12. }

下面最后来看看手势的匹配:

Java代码
  1. public void findGesture(Gesture gesture) {
  2. try {
  3. // 关于两种方式创建模拟器的SDcard在【Android2D游戏开发之十】有详解
  4. if (Environment.getExternalStorageState() != null) {// 这个方法在试探终端是否有sdcard!
  5. if (!file.exists()) {// 判定是否已经存在手势文件
  6. tv.setText("匹配手势失败,因为手势文件不存在!!");
  7. } else {//当存在此文件的时候我们需要先删除此手势然后把新的手势放上
  8. //读取已经存在的文件,得到文件中的所有手势
  9. if (!gestureLib.load()) {//如果读取失败
  10. tv.setText("匹配手势失败,手势文件读取失败!");
  11. } else {//读取成功
  12. List<Prediction> predictions = gestureLib.recognize(gesture);
  13. //recognize()的返回结果是一个prediction集合,
  14. //包含了所有与gesture相匹配的结果。
  15. //从手势库中查询匹配的内容,匹配的结果可能包括多个相似的结果,
  16. if (!predictions.isEmpty()) {
  17. Prediction prediction = predictions.get(0);
  18. //prediction的score属性代表了与手势的相似程度
  19. //prediction的name代表手势对应的名称
  20. //prediction的score属性代表了与gesture得相似程度(通常情况下不考虑score小于1的结果)。
  21. if (prediction.score >= 1) {
  22. tv.setText("当前你的手势在手势库中找到最相似的手势:name =" + prediction.name);
  23. }
  24. }
  25. }
  26. }
  27. } else {
  28. tv.setText("匹配手势失败,,当前模拟器没有SD卡 - -。");
  29. }
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. tv.setText("由于出现异常,匹配手势失败啦~");
  33. }
  34. }

那么最后给各位童鞋说一下,其实输入法手势操作很是适合游戏中使用,不管是触摸屏手势操作还是今天讲的输入法手势操作如果加到游戏中那都是相当赞的!

自定义手势--输入法手势技术相关推荐

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

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

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

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

  3. 用 JavaScript 实现手势库 — 手势动画应用【前端组件化】

    前端<组件化系列>目录 「一」用 JSX 建立组件 Parser(解析器) 「二」使用 JSX 建立 Markup 组件风格 「三」用 JSX 实现 Carousel 轮播组件 「四」用 ...

  4. Win32输入法编程技术的分析研究

    作者:新疆大学 巴力登 陆莲芳 [摘要]本文论述了Win32输入法编程技术的基本原理.技术要点及其实现的方法. 并分析研究了基于IMM-IME结构的输入法的构成.接口.设计方法与核心技术问题.  [关 ...

  5. Windows10-1803版本设置自定义切换输入法的快捷键

    对于使用win10的朋友,大部分人对输入法都不习惯,如果你把英语输入法删除了,在中文输入法里没有美式键盘,让ctrl+空格与ctrl+Shift都能在中文输入法和美式键盘切换.下面就一起来看看怎么让W ...

  6. iOS自定义长按手势,随意拖动Cell

    起因 最近在做一个项目,要对UITableViewCell进行拖动蹂躏,具体效果如下: 本来打算用UIRespon这几个方法来做,最后发现在UITableViewController中这几个方法不会被 ...

  7. IOS 自定义 滑动返回 手势

    /** 只需要在你自定义的导航控制器中,改成如下代码即可,自定义手势返回 */ #define KEY_WINDOW [[UIApplication sharedApplication] keyWin ...

  8. android 手势输入法,搜狗手机输入法Android 4.6版新增手势操作

    手势操作,让输入更随心 相信绝大多数人都有过这样的经历,在和朋友聊微信.QQ或者互发短信的时候,想要删除或修改一句中的某个字,但移动光标怎么都不能准确移动到那个字的后面(英文字更小就更难点,坑爹啊), ...

  9. 自定义View----Android九宫格手势密码解锁

    好久没更新blog了,最近公司比较忙,旧的项目上线时间赶.加上新的项目又来了,于是导致都好久没去鸿洋的群里扯蛋了,做了一个不称职的管理员.说了好多遍的自定义萌系进度条都没有分享出来,在这给群里的各位说 ...

最新文章

  1. 在CentOS 7.7 x86_64上安装python3的selenium 3模块实录
  2. 网络拓扑图一般用什么软件画_视频后期一般用什么软件
  3. kernel vim阅读 设置tags的标签
  4. Java多线程闲聊(四):阻塞队列与线程池原理
  5. 你真的了解 Cookie 和 Session 吗?
  6. oracle 账户 锁定 密码忘记了,Oracle System密码忘记 密码修改、删除账号锁定lock
  7. python 协程池gevent.pool_进程池\线程池,协程,gevent
  8. 在墙上找垂直线_墙上如何快速找水平线
  9. Win11任务栏怎么隐藏
  10. C++ 深拷贝和浅拷贝
  11. 将xml转为txt_HZ文章转短视频工具v1.0 快速将文章转为短视频 自动配音 配字幕 配图...
  12. spring boot开发环境搭建
  13. system占用cpu过高
  14. 织梦采集插件自动图片本地化提升内容原创度
  15. 大数据第一季--Hadoop(day7)-徐培成-专题视频课程
  16. 概率论复习用 更新中
  17. python 爬虫,获取携程网站机票数据
  18. Latex书籍模板分享
  19. Msfvenom的简单用法
  20. java 判断文件损坏_Java校验文件是否损坏

热门文章

  1. 如何通过解决精益问题提高敏捷团队生产力
  2. S-DES加密与解密
  3. mvc @html.action() 跨area调用controller 中的action
  4. C++ 採集音频流(PCM裸流)实现录音功能
  5. Win7部署基础知识(2):制作WinPE
  6. 关于设计模式的感悟2
  7. 云计算三重奏:SAAS、PAAS和IAAS
  8. 这里有一个让你变成技术大牛的机会
  9. Ribbon的初始化源码
  10. array_shift -- 将数组开头的单元移出数组