Android开发:软键盘任意按键按下时执行函数的实现方法
Android没有提供官方全局的软键盘按键监听API,根据适配场景可以选择以下3种落地方式,按推荐优先级排序:
方案1:TextWatcher监听文本变化(适配绝大多数普通场景)
这是兼容性最好、实现成本最低的方案,不管是系统原生输入法还是第三方定制输入法,只要按键操作导致输入框内容变化(输入字符、删除内容、选择候选词)都会触发。缺点是无法捕获输入框为空时按下删除键这类不改变文本内容的操作。
实现代码:// 给目标输入框加文本变化监听 binding.targetEt.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { // 输入内容变化即触发目标函数 callYourSpecifiedFunction() } override fun afterTextChanged(s: Editable?) {} })方案2:自定义InputConnection全场景捕获(适配需要覆盖边缘操作的场景)
如果需要捕获空输入时按删除、输入法功能键这类不改变文本内容的按键操作,直接自定义输入控件,包装InputConnection拦截输入法和输入框的所有通信事件即可,这个方案对第三方输入法的适配率能到99%。
实现代码:// 自定义可监听软键盘操作的EditText class SoftKeyListenEditText @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : AppCompatEditText(context, attrs) { // 按键触发的回调 var onSoftKeyPressed: (() -> Unit)? = null override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection { val originConnection = super.onCreateInputConnection(outAttrs) return object : InputConnectionWrapper(originConnection, true) { override fun sendKeyEvent(event: KeyEvent?): Boolean { // 捕获输入法派发的实体类按键事件(比如删除键、回车、功能键) if (event?.action == KeyEvent.ACTION_DOWN) { onSoftKeyPressed?.invoke() } return super.sendKeyEvent(event) } override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean { // 捕获输入法提交文本的操作(输入字符、选候选词、输入表情) onSoftKeyPressed?.invoke() return super.commitText(text, newCursorPosition) } override fun deleteSurroundingText(beforeLength: Int, afterLength: Int): Boolean { // 捕获删除操作,包括输入框为空时按删除键的场景 onSoftKeyPressed?.invoke() return super.deleteSurroundingText(beforeLength, afterLength) } } } }使用时直接在布局里替换原生EditText,代码中设置回调即可:
binding.targetEt.onSoftKeyPressed = { callYourSpecifiedFunction() }方案3:setOnKeyListener监听按键事件(仅适配原生AOSP输入法,不推荐)
直接给输入框设置按键监听,这个方案只能捕获系统原生输入法派发的标准按键事件,对国内大部分定制第三方输入法完全失效,仅适合系统定制类开发场景,普通应用开发不要用。
实现代码:binding.targetEt.setOnKeyListener { _, keyCode, event -> if (event.action == KeyEvent.ACTION_DOWN) { callYourSpecifiedFunction() } false // 返回false不拦截原有输入逻辑,避免影响正常输入 }
避坑提示:
不要尝试实现脱离输入控件的全局软键盘按键监听,Android的输入法安全机制不允许普通应用获取其他输入框的软键盘输入事件,这类实现要么需要系统权限,要么在大部分机型上完全失效。
不要用布局全局监听判断键盘高度变化的方式来抓按键,这类方案只能感知键盘的显示/隐藏,完全捕获不到按键操作。
内容的提问来源于stack exchange,提问作者Chris

