輸入法原理

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不被遮擋,則不滾動

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