输入法原理

Question1:客户端如何与输入法产生联系

首先我们要明确的是输入法就是一个Service,无论是百度输入法还是搜狗输入法,都继承自系统提供的InputMethodService类

再说一下我们如何在App中主动调起输入法,其中,InputMethodManager就是用来操作输入法的类:

InputMethodManager inputManager = InputMethodManager.peekInstance();

inputManager.showSoftInput(editText, 0);

这个是输入法的经典流程图,上面我们说过,应用进程使用的是IMM,输入法进程使用的是IMS,在IMM和IMS中间是一个系统服务,缩写是IMMS

但是日常使用中,我们并没有主动调用IMM,但是输入法却能正常使用,比如当我们进入一个有 EditText控件的界面时,会自动弹出软键盘,原因是系统默默的帮我们做了很多工作。在新增或者删除窗口时,WindowManagerService会上自下判断由哪个窗口获取焦点,WMS拿到焦点Window后会跳到的ViewRootImpl,然后通过DecorView分发到各个view,最后调的是view的onWindowFocusChanged, 布尔值参数表示当前View所在窗口得到还是失去焦点, 我们直接看得到焦点这个分支,这个判断条件表示当前view能不能拿到焦点,如果view也能拿到焦点的话,最终会走到startInputInner,在该方法中会初始化View的进程通信接口,并调用IMM的startInput方法把该接口传递给输入法,在IMMS中会完成输入法创建和进程通讯接口双向绑定的工作,当输入法生成数据后,会通过这个binder把数据传递给应用进程

Question2:从源码上看,输入法是无法获取焦点的(由于输入法Window设置了FLAG_NOT_FOCUSABLE属性,所以无法获取焦点),因此,我们第一反应是输入法拿不到硬键盘输入KeyEvent,但事实上,输入法可以完美支持硬键盘

上面仔细分析了输入法的整体流程,其中,硬键盘事件是在ViewRootImpl中处理的,当系统把焦点事件传递给获取焦点的Window时,ViewRootImpl会通过dispatchInputEvent方法把硬键盘事件传递给输入法

Question3:如何实现一个输入法应用,直接上图

我们直接继承IMS,其中setCandidatesView(View)用来设置候选词视图,setInputView(View)用来设置输入视图,getCurrentInputConnection用来获取应用进程的通讯接口(InputConnection),这里面主要有两个方法比较常用,sendKeyEvent和commitText,其中sendKeyEvent用来发送硬键盘事件(删除等),commitText用来发送文本

windowSoftInputMode:

stateUnchanged:当前界面的软键盘状态,取决于上一个界面的软键盘状态。举个例子,假如当前界面键盘是隐藏的,那么跳转之后的界面,软键盘也是隐藏的;如果当前界面是显示的,那么跳转之后的界面,软键盘也是显示状态

stateHidden:正常跳转总是隐藏键盘

stateAlwaysHidden:正常跳转或者是上一个界面被用户返回都会隐藏键盘

stateVisible:正常跳转总是显示键盘

stateAlwaysVisible:正常跳转或者是上一个界面被用户返回都会显示键盘

adjustResize:当键盘弹出时,从下往上压缩Activity布局,压缩的距离等于键盘的高度。压缩之后,不管EditText是否可见

adjustPan:当键盘弹出时,如果EditText被键盘遮挡,activity内容会向上滚动,以保证EditText不被键盘遮挡;如果EditText不被遮挡,则不滚动

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章