一箫一剑平生意,负尽狂名十五年。这篇文章主要讲述对Android 软键盘向下的监听相关的知识,希望能为你提供帮助。
因为业务需要,
有时候我们好监听软键盘向下的动作,
当我们按下向下的按钮时,
可以进行监听,
从而执行相应的动作。
![对Android 软键盘向下的监听](http://img.readke.com/220415/100A52047-0.jpg)
文章图片
于是我们写下下面的代码
@
Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode =
=
KeyEvent.KEYCODE_BACK){
Log.i(TAG, "
onKeyDown"
);
}
return super.onKeyDown(keyCode, event);
}
我们按下向下的按钮, 滴, 没反应。再按一次, 滴, 握草, 直接退出了, 这个时候才有 log 打印出来。这个 log 是退出当前 Activity, 而不是软键盘向下的。
【对Android 软键盘向下的监听】如果没有想到好的解决方案, 就问 google , 于是我们得到了解决方法, 就是对 Edittext.onKeyPreIme() 方法重写
/**
*拦截键盘向下的 EditTextView
*/
public class TextEditTextView extends EditText {
public TextEditTextView(Context context) {
super(context);
}public TextEditTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}public TextEditTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}@
Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode =
=
KeyEvent.KEYCODE_BACK &
&
event.getAction() =
=
1) {
Log.i("
main_activity"
, "
键盘向下 "
);
super.onKeyPreIme(keyCode, event);
return false;
}
return super.onKeyPreIme(keyCode, event);
}
}
在布局中
<
?xml version=
"
1.0"
encoding=
"
utf-8"
?>
<
RelativeLayout
android:id=
"
@
+
id/activity_main"
xmlns:android=
"
http://schemas.android.com/apk/res/android"
android:layout_width=
"
match_parent"
android:layout_height=
"
match_parent"
android:background=
"
@
android:color/white"
>
<
com.yxhuang.myapplication.TextEditTextView
android:id=
"
@
+
id/edt_text"
android:layout_width=
"
match_parent"
android:hint=
"
测试"
android:layout_marginTop=
"
30dp"
android:textColorHint=
"
@
android:color/black"
android:layout_height=
"
wrap_content"
/>
<
/RelativeLayout>
![对Android 软键盘向下的监听](http://img.readke.com/220415/100A52b1-1.jpg)
文章图片
点击向下后, 可以看到 log
![对Android 软键盘向下的监听](http://img.readke.com/220415/100A54261-2.jpg)
文章图片
这是键盘向下的监听, 我们得到了, 然后可以执行相应的动作。
作为一个程序员, 我们不仅要知道怎样做, 还应该知道为什么会这样。这个问题就涉及到 Android 输入系统, 详情见上一篇博文 Android 输入系统
为什么 重写 Activity.onKeyDown() 方法为什么没有用?
根据 Android 输入系统 一文, 我们知道事件的流水线处理顺序
![对Android 软键盘向下的监听](http://img.readke.com/220415/100A52506-3.jpg)
文章图片
Ime 是键盘输入法, ViewPreImeStage 是在输入法之前, ImeStage 是输入法处理, ViewPostImeStage 才是最终传递到 Activity.onKeyDown() 的。
ViewPreImeStage 中可以将键盘向下的事件传递到 View, 而到了 ViewPostImeStage 则没有, 那应该是有东西消耗了这个事件。当我们按下向下的按钮, 键盘会收起来, 显然是键盘消耗了这个事件。
我们看看 ImeStage 的源码
/**
* Delivers input events to the ime.
* Does not support pointer events.
*/
final class ImeInputStage extends AsyncInputStage
implements InputMethodManager.FinishedInputEventCallback {
public ImeInputStage(InputStage next, String traceCounter) {
super(next, traceCounter);
}@
Override
protected int onProcess(QueuedInputEvent q) {
if (mLastWasImTarget) {
// 获取 InputMethodManager 实例
InputMethodManager imm =
InputMethodManager.peekInstance();
if (imm !=
null) {
final InputEvent event =
q.mEvent;
// dispatchInputEvent 方法处理了事件
int result =
imm.dispatchInputEvent(event, q, this, mHandler);
if (result =
=
InputMethodManager.DISPATCH_HANDLED) {
return FINISH_HANDLED;
} else if (result =
=
InputMethodManager.DISPATCH_NOT_HANDLED) {
return FINISH_NOT_HANDLED;
} else {
return DEFER;
// callback will be invoked later
}
}
}
return FORWARD;
}@
Override
public void onFinishedInputEvent(Object token, boolean handled) {
QueuedInputEvent q =
(QueuedInputEvent)token;
if (handled) {
finish(q, true);
return;
}
forward(q);
}
}
我们看到如果 InputMethodeManager.dispatchInputEvent(…) 方法返回的结果是
InputMethodManager.DISPATCH_HANDLED 则结束事件的传递。事件就传递不到 ViewPostImeStage, 从而也就传递不到 Activity.onKeyDown() 中了。
到这来我们终于知道了为什么重写 Activity.onKeyDown() 方法没用了, 想要监听键盘向下的事件, 需要重写 Edittext.onKeyPreime() 方法, 在这个方法里进行监听了。
推荐阅读
- Appium的一点一滴:Android KEYCODE键值
- Android隐式启动Activity可能存在的坑
- Android - 进阶之自定义视图浅析
- Android UI(矢量图使用)
- Android 的漂浮动画,下雪动画
- Android中活动条ActionBar的详细使用
- Android Material Design 系列之 SnackBar详解
- Android程序中如何执行shell脚本
- Android 性能测试——Heap Viewer 工具