1.EditText作為一個比較成熟的View,在Android的應用開發中得到極為廣泛的使用。在某些特殊情況下,我們可能需要定制EditText的輸入內容,
只允許指定功能的輸入,例如輸入一個”ddd:mm:ssssss“格式的度分秒角度。
一些錯誤的思路有:
(1)OnKeyListener,實現EditText的OnKeyListener並不能攔截EditText的輸入,OnKeyListener只能夠監聽到一些按物理鍵事件,例如菜單鍵、返回鍵、音量鍵等,
而輸入法作為一個單獨的進程,EditText與輸入法的通訊顯然是OnKeyListener所無能為力的;
(2)TextWatcher,相信很多同志做這個功能的第一反應都是使用TextWatcher,因為TextWatcher可以監聽到EditText輸入前后內容的變化,但那也只是監聽到而已
,它並沒有辦法真正攔截到輸入,而只是在某一字符輸入發生后,對EditText做一個事后的處理。典型的例子如下,假設我監聽到了”s“的輸入,但實際上我是不允許”s“輸入的,那
么我在TextWatcher中監聽到”s“輸入了以后,重新設置EditText的內容。但這樣做的惡果就是重設EditText的內容后,又會回調TextWatcher的那幾個方法,造成死循環。當然您可以
設置一個標志位來停止這個循環,但麻煩不止於此。因為你是先讓字符輸入,然后再手動把它刪除,那么這其中涉及到的光標位置調整,將無窮無盡……
2.講述了上面兩種典型的錯誤之后(事實上也是LZ曾經犯過的),介紹一下LZ對於真正EidtText輸入攔截的實現。
既然系統給的接口都無法實現,那么勢必要通過源碼來解決問題了。EditText是繼承與TextView的,TextView的源碼量非常大,一個個函數看
肯定不現實,那么按關鍵字搜吧,搜索”input“可以查到”onCreateInputConnection“這個方法 ,字面意思創建與輸入法的通信,返回的對象是InputConnection,
很有可能就是它了,InputConnectionWrapper 實現了InputConnection, 而這個類的實現方法中有兩個極為可靠的方法,commitText, sendKeyEvent,字面意思提交文本
和按鍵事件。看到這里,想必思路也差不多了:
(1)重載onCreateInputConnection方法,它需要返回一個InputConnection對象;
(2)繼承於InputConnectionWrapper, 實現自己的InputConnection 並且在onCreateInputConnection中返回。
(3)在自定義的InputConnectionWrapper類中,實現輸入法輸入和按鍵時間的攔截。
(4)攔截條件:在commitText方法中,如果執行父類的 commitText(即super.commitText(text, newCursorPosition))那么表示不攔截,如果返回false則表示攔截,
輸入法的字符串則無法傳送到EditText。在sendKeyEvent中,如果執行父類的sendKeyEvent(即super.sendKeyEvent(event))那么表示不攔截,如果返回false表示攔截。
3.至此,EditText的定制輸入的最總要環節,攔截EditText與輸入法的通訊已經成功實現,接下來的就是根據你的定制規則去重載你的commitText和sendKeyEvent方法吧。
幾個重要的方法,
設置光標位置:setSelection(cursor - 1, cursor -1);
刪除光標坐標0(m)個到光標右邊1(n)個字符:deleteSurroundingText(0, 1);
此外,不同的輸入法的KeyEvent方法可能有些不同,你需要查看SoftKeyboard示例源碼來對你的應用進行調試,以使它能夠兼容主流的輸入法。