目录

一、实现一个可以模拟输入的软键盘

一开始,我们的需求是在用户经常使用的部分界面中,增加虚拟软键盘,减少用户对于外接键盘的依赖

如图,在整单改价界面右侧增加了方便用户快捷输入的软键盘,用户不需要使用外接键盘,即可完成常见的商品改价等操作。

那么这个代码逻辑实现起来比较简单,因为业务中有许多类似界面需要使用该软键盘功能,所以我们将它单独封装为一个View:

mView = View.inflate(context, R.layout.res_keypad_view, this)

val map = hashMapOf()

map[tv_num_1] = KeyEvent.KEYCODE_NUMPAD_1

map[tv_num_2] = KeyEvent.KEYCODE_NUMPAD_2

map[tv_num_3] = KeyEvent.KEYCODE_NUMPAD_3

map[tv_num_4] = KeyEvent.KEYCODE_NUMPAD_4

map[tv_num_5] = KeyEvent.KEYCODE_NUMPAD_5

map[tv_num_6] = KeyEvent.KEYCODE_NUMPAD_6

map[tv_num_7] = KeyEvent.KEYCODE_NUMPAD_7

map[tv_num_8] = KeyEvent.KEYCODE_NUMPAD_8

map[tv_num_9] = KeyEvent.KEYCODE_NUMPAD_9

map[tv_num_0] = KeyEvent.KEYCODE_NUMPAD_0

map[tv_num_dot] = KeyEvent.KEYCODE_NUMPAD_DOT

map[tv_num_del] = KeyEvent.KEYCODE_DEL

map.iterator().forEach { item ->

item.key.setOnClickListener {

(mView.parent as View).dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, item.value))

}

}

做好布局后,在代码中建立每个view与它所代表的键码的对应关系,使用map持有它们,最后遍历map集合,给每个view设置点击事件,触发点击事件时,我们构造一个KeyEvent对象,然后找到当前view(即软键盘view)的父view,调用其dispatchKeyEvent()方法,向其分发键盘事件,然后依靠安卓自身的事件处理机制,该事件就能被正确的传递给需要它的EditText。

利用系统自身的事件传递机制,去帮我们实现将KeyEvent转化为字符,输入进EditText,是再好不过的,我们就不需要考虑直接操作EditText可能带来的各种问题。

那么,软键盘view封装好了,其他界面如何使用呢?

非常简单:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:layout_width="400dp"

android:layout_height="350dp"

android:orientation="vertical">

<.....keypadview>

android:layout_width="263dp"

android:layout_height="match_parent"

android:layout_marginLeft="10dp"

android:background="@drawable/res_best_white_button_default" />

只需要一个LinearLayout 将原本的业务view和软键盘view包括起来就OK了

好的,那么正当我测试了几个界面没有问题的时候,我把这个软键盘应用在另一个界面时,问题出现了:

二、问题:点击软键盘,没有任何反应,输入框没有填入字符

就是这个界面,我没有发现它与正常界面有何区别,于是只能尝试通过底层源码,来寻找问题原因

那么我首先怀疑是因为dispatchKeyEvent()方法没有正确将按键事件传递给EditText,但是经过调试后,发现事件确实有传递过来

首先,当我们通过debug模式,查看安卓源码时,记得打开源文件后,在右上角选择和你运行的机器对应的安卓sdk版本,比如我的真机,安卓版本是5.1.1,那么此处我要选择查看api 22 版本的源代码。这样就不会出现断点乱跳,无法定位代码的问题。

断点之后,通过代码逻辑可知,返回0表示没有处理/消耗此事件,那么问题很有可能出现在这个doKeyDown()方法内

在doKeyDown()方法内部,我发现了可疑代码,这段代码判断了,当KeyEvent的按键动作是按下时,使用了类似于数据库事务操作的方式,对其进行编辑

并返回一个布尔值,如果为true,则返回到外部:1,表示该keyEvent被处理/消耗。

继续深入该方法,发现KeyListener是一个接口,拥有好几个实现类

鼠标停留在变量上,可以看到此时,实现类是TextKeyListener

跟踪TextKeyListener的onKeyDown方法,最终发现,它实际调用的是QwertyKeyListener的onKeyDown()方法

此时,我发现了一行关键的代码,当我使用小键盘的1的code(KEYCODE_NUMPAD_1),和大键盘的1的code(KEYCODE_1),得到了截然不同的结果

接着看KeyEvent的getUnicodeChar()方法

/**

* Gets the Unicode character generated by the specified key and meta

* key state combination.

*

* Returns the Unicode character that the specified key would produce

* when the specified meta bits (see {@link MetaKeyKeyListener})

* were active.

*

* Returns 0 if the key is not one that is used to type Unicode

* characters.

*

* If the return value has bit {@link KeyCharacterMap#COMBINING_ACCENT} set, the

* key is a "dead key" that should be combined with another to

* actually produce a character -- see {@link KeyCharacterMap#getDeadChar} --

* after masking with {@link KeyCharacterMap#COMBINING_ACCENT_MASK}.

*

*

* @param metaState The meta key modifier state.

* @return The associated character or combining accent, or 0 if none.

*/

public int getUnicodeChar(int metaState) {

return getKeyCharacterMap().get(mKeyCode, metaState);

}

原因:传入小键盘键码,和大键盘键码,得到的结果不一致

根据注释,可以得知该方法即为将按键事件,转为字符的核心方法,根据keyCode和键盘控制键(如Ctrl,Shift,NumLock等),获得一个字符

当我们传入小键盘的键码时,无法正确获得对应字符,当传入大键盘的键码时,却可以获得字符,这就是问题的原因。

那么,下一个问题来了,

三、为什么在前面经过测试的其他界面中,软键盘却又可以正常录入字符呢?

那么,我们找到可以正常使用软键盘的界面,再重复一遍以上过程,

发现这次,代码没有进入TextKeyListener和QwertyKeyListener,而是进入了另一个实现类,NumberKeyListener的onKeyDown方法

可以发现,此处的区别是,它并没有用上面的getUnicodeChar()方法去转换字符,而是通过自己的lookup()方法,转换字符

原因:使用了不同的KeyListener实现类

那么,结合类名和现象,我们可以推测出:

TextKeyListener和QwertyKeyListener,他们的字符转换功能,不支持小键盘的键码(即虚拟键盘失效,有问题的界面)

NumberKeyListener的字符转换功能,支持小键盘键码(即前面测试过,功能ok的界面)

找到原因后,修复的办法也显而易见,只要让我们存在问题的界面内的EditText,使用NumberKeyListener做字符转换即可

使用EditText的 setInputType(EditorInfo.TYPE_CLASS_NUMBER)

将其设置为只能输入数字即可

但是,突然又想到,这个界面是需要支持输入商品编码的,而我们的部分商品编码是以字母Z开头的,所以设置为只能输入数字,将会影响业务逻辑

此时,看到了最开始我们发射事件的代码,

map[tv_num_1] = KeyEvent.KEYCODE_NUMPAD_1

map[tv_num_2] = KeyEvent.KEYCODE_NUMPAD_2

map[tv_num_3] = KeyEvent.KEYCODE_NUMPAD_3

map[tv_num_4] = KeyEvent.KEYCODE_NUMPAD_4

map[tv_num_5] = KeyEvent.KEYCODE_NUMPAD_5

map[tv_num_6] = KeyEvent.KEYCODE_NUMPAD_6

map[tv_num_7] = KeyEvent.KEYCODE_NUMPAD_7

map[tv_num_8] = KeyEvent.KEYCODE_NUMPAD_8

map[tv_num_9] = KeyEvent.KEYCODE_NUMPAD_9

map[tv_num_0] = KeyEvent.KEYCODE_NUMPAD_0

map[tv_num_dot] = KeyEvent.KEYCODE_NUMPAD_DOT

里面的键码全部是用的小键盘键码,直接把它们都改为大键盘键码,问题不就都迎刃而解了吗

改来改去,最后发现问题的原因只是最初发射事件的源头。。

哈哈,最后针对安卓中的键盘事件处理机制,做一下总结

安卓KeyEvent的处理机制总结:

如果需要做虚拟键盘,模拟键盘输入时,可以借助安卓本身的KeyEvent机制,自己构造KeyEvent对象,使用dispatchKeyEvent()方法将事件分发给父View,剩下的都可以交给系统自行处理~

如果出现事件无效的问题,检查自己构造的键码是否正确,切换大/小键盘键码进行尝试

将KeyEvent事件转换为字符输入的工作,是由KeyListener的实现类完成的

KeyListener有很多实现类,每个实现类的职责不同,我们可以通过EditText的setInputType()方法,选择不同的实现类,来实现最终目的

matlab edittext 回车,安卓中的虚拟键盘实现,KeyEvent的事件分发、处理机制。EditText是如何将KeyEvent事件转为字符输入的?...相关推荐

  1. 安卓中的虚拟键盘实现,KeyEvent的事件分发、处理机制。EditText是如何将KeyEvent事件转为字符输入的?

    目录 一.实现一个可以模拟输入的软键盘 二.问题:点击软键盘,没有任何反应,输入框没有填入字符 原因:传入小键盘键码,和大键盘键码,得到的结果不一致 三.为什么在前面经过测试的其他界面中,软键盘却又可 ...

  2. 如何在WPF中使用虚拟键盘

    在使用WPF做触屏功能开发时,发现有时候对触屏支持不甚友好,特别是虚拟键盘.于是上网找资料,发现一般有两种方法,一种是打开C:\Program Files\Common Files\microsoft ...

  3. android 展示虚拟键盘,在android TabLayout中显示虚拟键盘

    我正在使用TabLayout来显示不同的输入方法.第一个选项卡包含按钮,第四个选项卡应显示此TabLayout中嵌入的标准键盘.这里有截图如何: TabLayout到目前为止工作.我尝试使用Keybo ...

  4. 安卓中的虚拟手机莫名其妙出现问题,百度了好久,最终还是不管用。最终得到了来自陌生人的指导,希望我发布的这篇文章能将这份凌晨的温暖传递下去。也在此对这位陌生人表示真挚的感谢。

    11/05 22:41:42: Launching 'person1' on Unknown Device.Installation did not succeed.The application c ...

  5. 如何在 JavaScript 中创建虚拟键盘

  6. 安卓虚拟键盘_像科幻片里那样隔空打字,虚拟键盘会成为未来趋势吗?

    最极客最具极客精神的新媒体近日,Facebook Reality Labs为虚拟现实体验开发了一种名为"PinchType"的输入法.主要依靠手部追踪,将不同字母输入固定分配给特定 ...

  7. 安卓虚拟键盘_Logitech罗技 key to go蓝牙键盘使用体验

    苹果官网的图片 自从我买下了iPad2018之后,就心仪这款键盘很久.一方面iPad2018没有官方的键盘保护套,另一面Logitech的这款键盘在外形上也很吸引人. 整体外观 与官网图片一致,key ...

  8. 【小贴士】虚拟键盘与fixed带给移动端的痛!

    前言 今天来公司的主要目的就是研究虚拟键盘与fixed的问题,期间因为同事问起闭包与事件委托(阻止冒泡)相关问题,便穿插了一篇别的: [小贴士]工作中的"闭包"与事件委托的&quo ...

  9. QT 虚拟键盘使用问题

    完整项目地址: https://download.csdn.net/download/qq_32854345/87173147?spm=1001.2014.3001.5501 将虚拟键盘编译,并生成动 ...

最新文章

  1. 阿里官方Redis开发规范!
  2. 图像处理、语音处理的应用及前沿技术_华北工控:工业平板电脑在智慧医院中的广泛应用...
  3. 如何加快HTML页面加载速度
  4. Android使用ImageView显示网络图片
  5. [转]C#中多路IP摄像机的视频监控系统
  6. Vue采用input实现文件上传与删除
  7. linux ubantu扩展空间,ubuntu 扩展存储空间
  8. 十种常见排序算法欢聚一堂
  9. linux源代码剖析之一
  10. 2021年的第一本书,就从这里选
  11. 2022华为软件精英挑战赛-总结
  12. 关于SQL2005安装完毕后,没有SQL Server Management Studio问题的解决方法
  13. java生成多页pdf_java 多页pdf转化为多张图片
  14. 2.《JSP应用开发案例教程》第1章 JSP概述
  15. C++调用c#的.net Standard类库流程
  16. 一文搞懂 FlinkSQL函数 LAST_VALUE 的原理
  17. python为你写诗_套了个经典歌名就变成电影了:为你写不出叫好的诗
  18. java判断101-200之间有多少个素数_并输出所有素数_编程基础练习:题目:判断101-200之间有多少个素数,并输出所有素数。 - 菜鸟头头...
  19. Spark 用代码实现求分位数Percentile(Quentile)的方法
  20. @click.stop作用(阻止点击事件继续传播,即阻止事件冒泡)

热门文章

  1. php转换音频采样率,非整数倍SRC采样率转换问题样本试听
  2. 显示unc路径服务器根目录,路径解释:绝对、相对、UNC 和 URL
  3. 职业规划要看的书单。
  4. Flash服务端常见架构方案
  5. 2023超好用的Mac清理优化工具CleanMyMacX
  6. Java仿QQ聊天系统Eclipse+MySql实现
  7. emqx使用自制CA证书登录配置(双向认证)
  8. vue3时间戳格式转换
  9. Python tell 和 seek用法
  10. 游戏引擎设计 - 粒子系统