InputMethodManager類
Android中軟鍵盤的管理主要是通過(guò)InputMethodManager類來(lái)完成的。?
InputMethodManager對(duì)象的獲取方法如下:
獲取到InputMethodManager對(duì)象后就可以通過(guò)調(diào)用其成員方法來(lái)對(duì)軟鍵盤進(jìn)行操作吃靠。不過(guò)在使用InputMethodManager對(duì)象前通常都需要判斷其是否為null膊升,避免運(yùn)行時(shí)異常:
顯示軟鍵盤
Android中可以通過(guò)InputMethodManager的showSoftInput()方法來(lái)顯示軟鍵盤。?
InputMethodManager的showSoftInput()方法原型為:
它有兩個(gè)參數(shù)嫩舟,第一個(gè)參數(shù)表示當(dāng)前要接收軟鍵盤輸入的view少态,第二個(gè)參數(shù)是軟鍵盤顯示時(shí)的控制參數(shù)幻妓。使用InputMethodManager的showSoftInput()方法來(lái)顯示軟鍵盤有如下注意事項(xiàng):
? ? ????1.第一個(gè)參數(shù)中view必須是EditText帖鸦,或者EditText的子類芝薇,如果是其他類型的View、如Button作儿、TextView等洛二,showSoftInput()方法不起作用。
? ? ????2.第一個(gè)參數(shù)中的view必須是可以獲取焦點(diǎn)的(即view.isFocusable()返回true)攻锰,如果不能獲取焦點(diǎn)晾嘶,則showSoftInput()方法不起作用。EditText默認(rèn)是可獲取焦點(diǎn)的娶吞,所以此條件一般都可以滿足垒迂。如果不滿足,可以通過(guò)view.setFocusable(true);將其設(shè)置為可獲取焦點(diǎn)的view妒蛇。
? ? ????3.第一個(gè)參數(shù)中的view當(dāng)前必須已經(jīng)獲取到焦點(diǎn)(即view.isFocused()返回true)机断,如果當(dāng)前焦點(diǎn)不在該view上,則showSoftInput()方法不起作用绣夺。雖然EditText默認(rèn)是可獲取焦點(diǎn)的吏奸,但由于一個(gè)布局中可能會(huì)有多個(gè)控件可以獲取焦點(diǎn),焦點(diǎn)位置不一定會(huì)恰好在EditText上陶耍,所以此條件不一定滿足奋蔚。為了讓showSoftInput()可以起作用,必須在之前showSoftInput()前先通過(guò)view.requestFocus()獲取焦點(diǎn)烈钞。然后再執(zhí)行showSoftInput()泊碑。
? ????? 4.第一個(gè)參數(shù)中的view必須是可見(jiàn)的,即view.getVisibility()等于View.VISIBLE棵磷,如果view是不可見(jiàn)的蛾狗,無(wú)論view.getVisibility()是View.INVISIBLE還是View.GONE,showSoftInput()方法都不起作用仪媒。如果view是不可見(jiàn)的,可以先通過(guò)view.setVisibility(View.VISIBLE)將其設(shè)置為可見(jiàn)谢鹊。
? ? ????5.當(dāng)前布局必須已經(jīng)完成加載算吩,如果還未繪制完成,則showSoftInput()方法不起作用佃扼。特別的偎巢,在Activity的onCreate()中執(zhí)行showSoftInput()是不起作用的。如果要再布局文件加載后就顯示軟鍵盤兼耀,可以通過(guò)postDelayed的方式來(lái)延遲執(zhí)行showSoftInput()压昼。延遲時(shí)間不能太短求冷,一般要在50ms以上。代碼示例如下:
????????6.InputMethodManager類中提供了另外一個(gè)顯示軟鍵盤的方法showSoftInputFromInputMethod窍霞,和showSoftInput不同的是匠题,第一個(gè)參數(shù)傳入的不是一個(gè)View對(duì)象,而是一個(gè)View對(duì)象的windowToken(對(duì)一個(gè)view對(duì)象可以通過(guò)getWindowToken()的方法獲取到其windowToken但金。不過(guò)實(shí)際情況是韭山,即使上述所有條件都滿足,通過(guò)showSoftInput(view冷溃,flag)已經(jīng)可以顯示軟鍵盤钱磅,但是通過(guò)showSoftInputFromInputMethod(view.getWindowToken(), flag)仍然無(wú)法顯示軟鍵盤。
? ? ????7.參照Android官方文檔似枕,第二個(gè)參數(shù)提供一些額外的操作標(biāo)記(additional operating flags)盖淡,可以取0或者SHOW_IMPLICIT,0表示什么含義沒(méi)有說(shuō)明凿歼,SHOW_IMPLICIT表示本次顯示軟鍵盤的請(qǐng)求不是來(lái)自用戶的直接請(qǐng)求禁舷,而是隱式的請(qǐng)求。且不說(shuō)一會(huì)用數(shù)字毅往,一會(huì)用常量名牵咙,光SHOW_IMPLICIT的說(shuō)明恐怕除了這個(gè)接口的開(kāi)發(fā)人員,沒(méi)人能看懂這句話是什么意思攀唯。實(shí)際上這個(gè)參數(shù)還可以取第三個(gè)值SHOW_FORCED洁桌,直接在文檔中被遺忘了。經(jīng)過(guò)試驗(yàn)侯嘀,這個(gè)參數(shù)的取值對(duì)軟鍵盤的顯示沒(méi)有任何影響另凌,無(wú)論取哪一個(gè)值軟鍵盤都能夠正常顯示(即使隨便輸入一個(gè)整數(shù),軟鍵盤都可以顯示)戒幔。實(shí)際上這個(gè)參數(shù)影響的并不是軟鍵盤的顯示吠谢,而是軟鍵盤的隱藏。
隱藏軟鍵盤
Android在InputMethodManager類中并沒(méi)有提供一個(gè)和showSoftInput()對(duì)應(yīng)的hideSoftInput()方法來(lái)隱藏軟鍵盤诗茎,而是提供了一個(gè)showSoftInputFromInputMethod()相對(duì)應(yīng)的hideSoftInputFromWindow()方法來(lái)隱藏軟鍵盤工坊。幸運(yùn)的是,雖然showSoftInputFromInputMethod()不能正常顯示軟鍵盤敢订,hideSoftInputFromWindow()倒是能夠隱藏軟鍵盤王污。
InputMethodManager的hideSoftInputFromWindow()方法原型為:
它同樣有兩個(gè)參數(shù),第一個(gè)參數(shù)是一個(gè)View的windowToken楚午,第二個(gè)參數(shù)是軟鍵盤隱藏時(shí)的控制參數(shù)昭齐。使用?InputMethodManager的hideSoftInputFromWindow()方法來(lái)隱藏軟鍵盤有如下注意事項(xiàng):
? ? ????1.第一個(gè)參數(shù)并不是指定一個(gè)View,而是一個(gè)View的windowToken矾柜。對(duì)一個(gè)view可以通過(guò)getWindowToken()的方法獲取到其windowToken阱驾。
? ? ????2.按照官方文檔就谜,第一個(gè)參數(shù)中的windowToken應(yīng)當(dāng)是之前請(qǐng)求顯示軟鍵盤的View的windowToken,也就是執(zhí)行showSoftInput()時(shí)第一個(gè)參數(shù)中的View的windowToken里覆。但是實(shí)際情況是丧荐,用任意一個(gè)當(dāng)前布局中的已經(jīng)加載的View的windowToken都可以隱藏軟鍵盤,哪怕這個(gè)View被設(shè)置為INVISIBLE或GONE租谈。因此篮奄,如果不知道之前是誰(shuí)請(qǐng)求顯示的軟鍵盤,可以隨便傳入一個(gè)當(dāng)前布局中存在的View的windowToken割去。特別的窟却,可以傳入一個(gè)Activity的頂層View的windowToken,即getWindow().getDecorView().getWindowToken()呻逆,來(lái)隱藏當(dāng)前Activity中顯示的軟鍵盤夸赫,而不用管之前調(diào)用showSoftInput()的究竟是哪個(gè)View,示例代碼如下:
這里還要注意的是咖城,可以隨便傳入一個(gè)當(dāng)前布局中存在的View的windowToken茬腿,并不代表可以傳入任意一個(gè)View的windowToken,如下代碼不能實(shí)現(xiàn)隱藏軟鍵盤:
對(duì)新創(chuàng)建的view宜雀,必須將其加入到當(dāng)前布局中后才可以用來(lái)隱藏軟鍵盤切平。如下代碼可以實(shí)現(xiàn)隱藏軟鍵盤:
????????3.參照Android官方文檔,第二個(gè)參數(shù)同樣是提供了一些額外的操作標(biāo)記(additional operating flags)辐董,可以取0或者HIDE_IMPLICIT_ONLY悴品,0表示什么含義同樣是沒(méi)有說(shuō)明,HIDE_IMPLICIT_ONLY表示當(dāng)前的軟鍵盤應(yīng)當(dāng)只在其不是被用戶顯式的顯示的時(shí)候才隱藏(the soft input window should only be hidden if it was not explicitly shown by the user)简烘。這句話雖然很拗口苔严,但總算是有點(diǎn)有用的信息了。在顯示軟鍵盤時(shí)孤澎,可以使用的flag有0届氢,SHOW_IMPLICIT和SHOW_FORCED,參照之前的描述覆旭,當(dāng)顯示軟鍵盤指定flag為SHOW_IMPLICIT時(shí)表示隱式的顯示退子,也就是這里非用戶顯式的顯示,再參照這里的描述姐扮,如果隱藏軟鍵盤時(shí)使用的flag為HIDE_IMPLICIT_ONLY絮供,那么軟鍵盤只有在非用戶顯式的顯示的時(shí)候才隱藏,這意味著如果隱藏軟鍵盤時(shí)使用的flag為HIDE_IMPLICIT_ONLY茶敏,那么只有當(dāng)顯示軟鍵盤時(shí)指定的flag為SHOW_IMPLICIT時(shí),軟鍵盤才會(huì)隱藏缚俏,如果顯示軟鍵盤時(shí)指定的flag不是SHOW_IMPLICIT惊搏,而是0或者SHOW_FORCED贮乳,那么軟鍵盤就不會(huì)隱藏。為了更完整的看出不同flag對(duì)隱藏軟鍵盤的影響(再聲明下恬惯,無(wú)論是顯示軟鍵盤時(shí)指定的flag向拆,還是隱藏軟鍵盤時(shí)指定的flag都只對(duì)隱藏軟鍵盤有影響,對(duì)顯示軟鍵盤無(wú)影響)酪耳, 分別在調(diào)用showSoftInput()時(shí)使用三個(gè)不同的標(biāo)記浓恳,以及在調(diào)用hideSoftInputFromWindow()是使用三個(gè)不同的標(biāo)記(隱藏軟鍵盤時(shí)同樣還有一個(gè)HIDE_NOT_ALWAYS標(biāo)記,它同樣在文檔中被遺忘了)碗暗,對(duì)是否能夠隱藏軟鍵盤進(jìn)行測(cè)試颈将,測(cè)試結(jié)果如下:
(T表示可以隱藏,F(xiàn)表示不能隱藏)
可以看到言疗,在隱藏軟鍵盤時(shí)使用HIDE_IMPLICIT_ONLY標(biāo)記晴圾,確實(shí)只有在顯示軟鍵盤時(shí)使用SHOW_IMPLICIT時(shí)才會(huì)隱藏。此外噪奄,當(dāng)隱藏軟鍵盤時(shí)使用0作為標(biāo)記死姚,無(wú)論showSoftInput()時(shí)使用的是哪個(gè)參數(shù),都可以隱藏軟鍵盤勤篮。
切換軟鍵盤狀態(tài)
在InputMethodManager類中還提供了一個(gè)toggleSoftInput()的方法來(lái)在顯示和隱藏軟鍵盤之間切換都毒,也就是說(shuō),如果當(dāng)前軟鍵盤是隱藏的碰缔,那么執(zhí)行toggleSoftInput()方法時(shí)會(huì)顯示軟鍵盤账劲,如果當(dāng)前軟鍵盤是顯示的,那么執(zhí)行toggleSoftInput()方法時(shí)會(huì)隱藏軟鍵盤手负。
InputMethodManager的toggleSoftInput()方法原型為:
它同樣有兩個(gè)參數(shù)涤垫,第一個(gè)參數(shù)是顯示軟鍵盤時(shí)使用的標(biāo)記,第二個(gè)參數(shù)是隱藏軟鍵盤時(shí)使用的標(biāo)記竟终。使用InputMethodManager的toggleSoftInput()方法來(lái)切換軟鍵盤顯示狀態(tài)有如下注意事項(xiàng):
? ? ????1.showFlags為顯示軟鍵盤時(shí)使用的標(biāo)記蝠猬,只有當(dāng)前軟鍵盤處于隱藏狀態(tài)時(shí)才會(huì)使用。hideFlags是隱藏軟鍵盤時(shí)使用的標(biāo)記统捶,只有當(dāng)前軟鍵盤處于顯示狀態(tài)時(shí)才會(huì)使用榆芦。
? ? ????2.showFlags和hideFlags取值范圍,以及不同取值的影響和上文分析的一樣喘鸟。即showFlags和hideFlags都只影響軟鍵盤的隱藏匆绣,不影響軟鍵盤的顯示。不同取值對(duì)軟鍵盤隱藏的影響參見(jiàn)上文中的表格什黑。
? ? ????3.和showSoftInput()方法不同的是崎淳,使用toggleSoftInput()顯示軟鍵盤時(shí),并不要求當(dāng)前界面布局中有一個(gè)已經(jīng)獲取焦點(diǎn)的EditText愕把,即使當(dāng)前布局是完全空白的拣凹,一個(gè)View也沒(méi)有(除了最外層的Layout)森爽,toggleSoftInput()也能夠顯示軟鍵盤。不過(guò)如果沒(méi)有一個(gè)已經(jīng)獲取焦點(diǎn)的EditText嚣镜,那么軟鍵盤中的按鍵輸入都是無(wú)效的爬迟。就像這樣。
? ? ????4.顯示軟鍵盤時(shí)菊匿,要求當(dāng)前布局必須已經(jīng)加載完成付呕,如果還未繪制完成,則toggleSoftInput()方法不起作用跌捆。這點(diǎn)和之前調(diào)用showSoftInput()顯示軟鍵盤時(shí)描述的第5點(diǎn)要求是一樣的徽职。特別的,在Activity的onCreate()中執(zhí)行toggleSoftInput()必須通過(guò)postDelayed的方式來(lái)延遲執(zhí)行疹蛉。延遲時(shí)間一般要在50ms以上活箕。
? ????? 5.當(dāng)隱藏軟鍵盤時(shí),不需要知道之前觸發(fā)軟鍵盤顯示的View是哪一個(gè)或獲取當(dāng)前布局中任何一個(gè)View的windowToken可款,只要hideFlags能夠隱藏就可以育韩。由于hideFlags為0時(shí)總是能夠隱藏的,因此闺鲸,使用toggleSoftInput(0, 0)應(yīng)當(dāng)是最方便的無(wú)條件隱藏軟鍵盤的方法筋讨,前提是知道當(dāng)前軟鍵盤確實(shí)是處于顯示狀態(tài)。不過(guò)遺憾的是Android沒(méi)有任何API可以直接獲取到軟鍵盤的狀態(tài)是顯示還是隱藏的摸恍。
部分源碼解讀
顯示和隱藏軟鍵盤的源碼大都在InputMethodManagerService.java文件里悉罕。這個(gè)文件有3000多行代碼,還有很多是其他類的交互立镶,我也沒(méi)有仔細(xì)研究壁袄,這里只是將其在一些片段貼出來(lái),做一個(gè)大概的分析:
? ? 1.showSoftInput?
????showSoftInput()會(huì)進(jìn)入到showCurrentInputLocked()方法中媚媒,這里有這樣一段:
? ? 2.hideSoftInputFromWindow?
????hideSoftInputFromWindow會(huì)進(jìn)入hideCurrentInputLocked()方法,在hideCurrentInputLocked()方法的開(kāi)頭有這樣一段:
結(jié)論
顯示軟鍵盤最可靠的方法如下:
隱藏軟鍵盤最方便的方法如下: