首先鍵盤是什么,鍵盤其實(shí)是一個系統(tǒng)的dialog。當(dāng)她出現(xiàn)的時候肯定會對屏幕的尺寸造成影響。所以屏幕會重繪什么啊,移動什么的。
特別特別重要的一點(diǎn),調(diào)用系統(tǒng)顯示鍵盤的方法時一定要先requestFocus這個editText的焦點(diǎn)。不然會出現(xiàn)一些怪異的事情,比如你掉了顯示鍵盤,他也不會彈出。
關(guān)于鍵盤是android的一個比較大的問題,像搜狗,百度都是自己的輸入法,這些都是需要對android的InputMethodManager進(jìn)行深入的研究,當(dāng)然首先肯定是看API
和INPUT_METHOD_SERVICE進(jìn)行研究,由于這里只討論工程上的如何快速開發(fā)一個app,所以我等搬磚工只進(jìn)行應(yīng)用上的研究。
首先來總結(jié)一下,android應(yīng)用中有哪些關(guān)于鍵盤的需求。
1.隨手打開一個app就會發(fā)現(xiàn)這樣的需求

點(diǎn)擊這個"寫評論"就會彈出一個輸入框,并且輸入法需要將這個輸入框頂上去。是這樣的。

用戶點(diǎn)擊這個寫評論觸發(fā)了三個操作
1.EditText這個輸入框出現(xiàn),也就是visible。
2.鍵盤彈出。
3.鍵盤將這個EditText頂上去。
一個一個的解決。
第一步很簡單,只需要在點(diǎn)擊"寫評論"的時候?qū)⑦@個EditText的狀態(tài)visible即可。
第二,彈出,我們先說說怎么彈出,這時候就涉及到了InputMethodManager?,F(xiàn)在具體說這個。
InputMethodManager,正如它的名字一樣,是一個鍵盤的管理者,里面有一些和變量可以操作鍵盤。包括打開,強(qiáng)制關(guān)閉等操作。具體代碼在github的demo里,注釋寫的很詳細(xì)了。
第三,彈出的時候需要將這個visible的edittext頂上去,這時候設(shè)計(jì)到了一個屬性叫windowSoftInputMode。
一定要注意理解windowSoftInputMode的每一個屬性的意思。
一般是state屬性和adjust屬性一起用,之間用 | 隔開。
state表示的是軟鍵盤在狀態(tài)切換,比如activity跳轉(zhuǎn),view的重繪時候鍵盤的顯示或者隱藏。
"stateUnspecified": 默認(rèn)設(shè)置,沒有什么用,依賴于theme的默認(rèn)設(shè)置。
"stateUnchanged":當(dāng)這個activity出現(xiàn)時,軟鍵盤將一直保持在上一個activity里的狀態(tài),無論是隱藏還是顯示。
"stateHidden":當(dāng)跳轉(zhuǎn)一個activity的時候,鍵盤是hide的。注意是跳轉(zhuǎn)而不是finish,也就說startActivity的時候當(dāng)前鍵盤hide,但是當(dāng)你finish當(dāng)前activity,鍵盤不會消失。
"stateAlwaysHidden":不管什么,只要activity的主窗口獲得焦點(diǎn),鍵盤就hide。
"stateVisible":軟鍵盤通常是可見的
"stateAlwaysVisible":上面的通常變成always。
"adjustUnspecified":默認(rèn)設(shè)置,通常由系統(tǒng)自行決定是隱藏還是顯示
"adjustResize": 會重新繪制view,onSizeChanged會重新調(diào)用,注意adjustPan這個方法不會調(diào)用。
"adjustPan":設(shè)置成adjustPan的時候鍵盤會去找當(dāng)前界面的焦點(diǎn),并始終焦點(diǎn)放在鍵盤的上方,使獲得焦點(diǎn)的view可見。當(dāng)前窗口的內(nèi)容將自動移動以便當(dāng)前焦點(diǎn)從不被鍵盤覆蓋和用戶能總是看到輸入內(nèi)容的部分
adjustResize 和 adjustPan 的目的很簡單,他們兩個都是做一切的努力想要為這個帶有焦點(diǎn)的editText留出空間,讓他出現(xiàn),adjustPan采用的是一種平移屏幕的方式,將editText放在鍵盤上,adjustResize采用的是壓縮屏幕的方式留出空間。為了留出空間,用心良苦啊。
其實(shí)布局頂起的正確與否,與一下因素有關(guān):
當(dāng)一個activity繼承自Activity的時候:
非全屏模式下,一切正常。
全屏模式下,不管你是adjustXXX,最后的效果都是adjustPan。AndroidBug5497Workaround
非全屏模式一律不要加AndroidBug5497Workaround
當(dāng)一個activity繼承自AppCompatActivity的時候:
非全屏模式下,一切正常。
全屏模式下,也都是adjustPan效果。但是加了AndroidBug5497Workaround就可以實(shí)現(xiàn)adjustResize。但是測量的結(jié)果可能會有偏差。
這里要注意幾點(diǎn):(如下這張圖片就是下面所講的內(nèi)容布局,寫評論就是那個editText)

1.adjustResize的時候,系統(tǒng)會重新計(jì)算布局,onMeasure,onSizeChanged,onLayout都會重新執(zhí)行,和adjustPan的區(qū)別方法是onSizeChanged會執(zhí)行。
需要彈出的editText輸入框不管怎么樣都要放到原始布局的最下方。內(nèi)容布局最好用ScrollView來包裹,這時候即使彈出也不會對內(nèi)容布局造成任何影響。如果用別的布局代替ScrollView的話,內(nèi)容布局就會按比例的壓縮到一起,效果不好。原因是該Activity總是調(diào)整屏幕的大小以便留出軟鍵盤的空間
2.一個怪異的問題是,當(dāng)這個editText的background只有color,那么adjustResize不會有問題,但是adjustPan的時候,會遮擋住editText下部的一小部分,但是當(dāng)這個background是一張.9圖的時候顯示正常,我猜想,當(dāng)時介紹adjustPan的時候說了,他只是努力將移動以便當(dāng)前焦點(diǎn)從不被鍵盤覆蓋和用戶能總是看到輸入內(nèi)容的部分,他想著我你看到哪個光標(biāo)也就是焦點(diǎn)了吧,那好我不移了。
目前來說,鍵盤還有幾個問題沒有得到優(yōu)化,后續(xù)會繼續(xù)進(jìn)行。
1.全屏與adjustResize之間的沖突,設(shè)置了全屏之后自己變?yōu)閍djustPan的效果了。(已解決,上面的內(nèi)容里有)
2.底部有虛擬鍵盤的情況
3.沉浸式狀態(tài)欄
2和3提到的問題,如果處理不了其實(shí)就是對于android的沉浸式,透明Navagation,還有android的window的view組成掌握的不熟悉,對AndroidBug5497Workaround不熟悉。。請到下幾篇文章(詳解AndroidBug5497Workaround,android的深層布局結(jié)構(gòu))里搞一搞,自己懂了原理自然就懂了。
4.鍵盤出現(xiàn)的時候布局閃動的問題,下一篇文章里會講。具體的原理依據(jù)以下源碼。
https://github.com/Jacksgong/JKeyboardPanelSwitch