最近在android NDK开发遇到了一个麻烦问题:在底层通过opengl绘制输入界面,但没办法调用输入法(IME),只能往上调用,通过jni通知java层调用输入法。
而对java层的需求就是只弹出输入法,把输入法键盘的按键事件和输入内容直接往底层传递。看似简单的需求,却让我瞎转了几天。
这里把我碰到的问题和解决方法进行总结。
1.调用输入法的方法
InputMethodManager input = (InputMethodManager)mApp.getSystemService(Context.INPUT_METHOD_SERVICE); input.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_NOT_ALWAYS);
input.toggleSoftInput()如果输入法已经打开则隐藏它,如果是隐藏的则显示它。也可直接调用input的show()或者hide()方法直接显示或隐藏。
注:测试结果显示,系统输入法始终处于开启状态,只能隐藏它,不能关闭。
2.必须为输入法提供一个View或者EditText对象用于接收输入内容
在View或者EditText中调用Input.toggleSoftInput()方法,或者Input.showSoftInput(view, flags)把View或者EditText作为参数传递进去来开启软键盘,输入法会把输入内容传递到指定的对象中。
EditText可以通过getText()直接获取输入内容;
View则需要实现以下方法
public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new MyInputConnection(this, false); }并创建继承BaseInputConnection的类
class MyInputConnection extends BaseInputConnection{ public MyInputConnection(View targetView, boolean fullEditor) { super(targetView, fullEditor); } public boolean commitText(CharSequence text, int newCursorPosition) { Log.i("ime", "input text:" + text); return true; } public boolean sendKeyEvent(KeyEvent event) { Log.i("ime", "sendKeyEvent()" + event.getKeyCode()); return true; } }
其中还有另外一个重要的方法是sendKeyEvent()。点击软键盘的enter和backspace按键事件并没有传递到commText,而是将事件传递到sendKeyEvent(),通过这个方法可以自定义地处理该事件。
3.软键盘样式、属性设置
EditText API中有许多方法可直接调用来设置软件盘的属性,详细见android api文档,这里不再赘述。View则需要在OnCreateInputConnection(EditorInfo outAttrs)方法,通过outAttrs属性进行设置。
public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI; // outAttrs.inputType = EditorInfo.TYPE_TEXT_VARIATION_PASSWORD; // outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE; return new MyInputConnection(this, false); }
软件盘最主要的样式是全屏模式和非全屏模式;在竖屏的情况下没有全屏模式,而在横屏的情况下(尤其是游戏开发)这两种模式都用得比较多。
值得注意的是,在横屏情况下通过View调用输入法,如果是非全屏模式需要设置outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI,否则会出现软键盘没有候选栏的情况,导致无法输入中文,具体原因尚不清楚,如果有了解的朋友还请多指教。
/* TODO 持续更新 */