Android各種鍵盤(pán)擋住輸入框解決辦法

作者簡(jiǎn)介? 創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog

瀟瀟鳳兒的博客地址:

http://blog.csdn.net/smileiam

正文

在開(kāi)發(fā)中,經(jīng)常會(huì)遇到鍵盤(pán)擋住輸入框的情況钮科,比如登錄界面或注冊(cè)界面,彈出的軟鍵盤(pán)把登錄或注冊(cè)按鈕擋住了彼乌,用戶(hù)必須把軟鍵盤(pán)收起,才能點(diǎn)擊相應(yīng)按鈕渊迁,這樣的用戶(hù)體驗(yàn)非常不好慰照。像微信則直接把登錄按鈕做在輸入框的上面,但有很多情況下琉朽,這經(jīng)常滿(mǎn)足不了需求毒租。同時(shí)如果輸入框特別多的情況下,點(diǎn)擊輸入時(shí)箱叁,當(dāng)前輸入框沒(méi)被擋住墅垮,但是當(dāng)前輸入框下面的輸入框卻無(wú)法獲取焦點(diǎn),必須先把鍵盤(pán)收起耕漱,再去獲取下面輸入框焦點(diǎn)算色,這樣用戶(hù)體驗(yàn)也非常不好,那有什么辦法呢螟够?

系統(tǒng)的 adjustResize 和 adjustPan 有什么區(qū)別灾梦,他們使用時(shí)的注意事項(xiàng),有什么系統(tǒng)要求及蔽端呢妓笙?

下面對(duì)幾種在開(kāi)發(fā)中常用的方法進(jìn)行總結(jié):

方法一:windowSoftInputMode:adjustResize和adjustPan

主要實(shí)現(xiàn)方法:在 AndroidManifest.xml 對(duì)應(yīng)的Activity里添加 android:windowSoftInputMode=”adjustPan” 或是 android:windowSoftInputMode=”adjustResize”屬性

這兩種屬性的區(qū)別若河,官方的解釋是:


這兩個(gè)屬性作用都是為了調(diào)整界面使鍵盤(pán)不擋住輸入框 ,我這里對(duì)這兩種屬性使用場(chǎng)景寞宫、優(yōu)缺點(diǎn)萧福、注意事項(xiàng)進(jìn)行了全方面總結(jié),不知大家平時(shí)使用時(shí)是否注意到了淆九。


adjustResize失效情況:activity 設(shè)置了全屏屬性指 Theme.Light.NotittleBar.Fullscreen 或者設(shè)置了 activity 對(duì)應(yīng)的主題中 android:windowTranslucentStatus 屬性统锤,設(shè)置方式為:android:windowTranslucentStatus=true毛俏,這時(shí)如果對(duì)應(yīng)的頁(yè)面上含有輸入框炭庙,將會(huì)導(dǎo)致點(diǎn)擊輸入框時(shí)軟鍵盤(pán)彈出后鍵盤(pán)覆蓋輸入框,導(dǎo)致輸入框看不見(jiàn)煌寇。

fitsSystemWindows=”true”,只有初始的view起作用:如果在布局中不是最外層控件設(shè)置 fitsSystemWindows=”true”, 那么設(shè)置的那個(gè)控件高度會(huì)多出一個(gè)狀態(tài)欄高度焕蹄。若有多個(gè)view設(shè)置了,因第一個(gè)view已經(jīng)消耗掉 insect阀溶,其他 view 設(shè)置了也會(huì)被系統(tǒng)忽略腻脏。

假設(shè)原始界面是一個(gè) LinearLayout 包含若干 EditText,如下圖所示鸦泳,在分別使用兩種屬性時(shí)的表現(xiàn):


1?adjustPan

整個(gè)界面向上平移,使輸入框露出永品,它不會(huì)改變界面的布局做鹰;界面整體可用高度還是屏幕高度,這個(gè)可以通過(guò)下面的截圖看出鼎姐,如點(diǎn)擊 輸入框6,輸入框會(huì)被推到鍵盤(pán)上方钾麸,但 輸入框1 被頂出去了,如果界面包含標(biāo)題欄炕桨,也會(huì)被頂出去饭尝。


2?adjustResize

需要界面的高度是可變的,或者說(shuō) Activity 主窗口的尺寸是可以調(diào)整的献宫,如果不能調(diào)整钥平,則不會(huì)起作用。

例如:Activity 的xml布局中只有一個(gè) LinearLayout 包含若干EditText,在Activity的 AndroidMainfest.xml 中設(shè)置 android:windowSoftInputMode=”adjustResize” 屬性姊途,點(diǎn)擊 輸入框6, 發(fā)現(xiàn)軟鍵盤(pán)擋住了 輸入框6,并沒(méi)有調(diào)整涉瘾,如下圖所示:


但使用這兩種屬性,我們可以總結(jié)以下幾點(diǎn):

1).使用 adjustPan, 如果需要輸入的項(xiàng)比較多時(shí)捷兰,點(diǎn)擊輸入框睡汹,當(dāng)前輸入項(xiàng)會(huì)被頂?shù)杰涙I盤(pán)上方,但若當(dāng)前輸入框下面還有輸入項(xiàng)時(shí)寂殉,卻需要先收起鍵盤(pán)囚巴,再點(diǎn)擊相應(yīng)的輸入項(xiàng)才能輸入。這樣操作太繁瑣了友扰,對(duì)于用戶(hù)體驗(yàn)不大好彤叉;

2).adjustResize 的使用,需要界面本身可顯示的窗口內(nèi)容能調(diào)整村怪,如果不能秽浇,不起作用;

方法二:在界面最外層布局包裹ScrollView

1?只使用ScrollView

在相應(yīng)界面的xml布局中甚负,最外層添加一個(gè) ScrollView柬焕,不在 AndroidMainfest.xml 中設(shè)置任何 android:windowSoftInputMode屬性,此時(shí)點(diǎn)擊輸入框梭域,輸入框均不會(huì)被軟鍵盤(pán)檔住斑举。即使當(dāng)前輸入框下方也有輸入框,在鍵盤(pán)顯示的情況下病涨,也可以通過(guò)上下滑動(dòng)界面來(lái)輸入富玷,而不用先隱藏鍵盤(pán),點(diǎn)擊下方輸入框,再顯示鍵盤(pán)輸入赎懦。

我們可以根據(jù) Android Studio 的 Inspect Layout 工具來(lái)查看界面真正占用的布局高度雀鹃,工具在:


通過(guò)該工具,我們看到:

界面真正能用的高度=屏幕高度-狀態(tài)欄高度-軟鍵盤(pán)高度

界面中藍(lán)框是真正界面所用的高度:


2?ScrollView +?adjustPan

我們?cè)僭谠擃?lèi)的 AndroidMainfest.xml 中設(shè)置 windowSoftInputMode屬性 為 adjustPan:


發(fā)現(xiàn)當(dāng)前輸入框不會(huì)被擋住励两,但是輸入框比較多時(shí)黎茎,在有鍵盤(pán)顯示時(shí),界面上下滑動(dòng)当悔,但只能滑動(dòng)部分工三,且如果輸入框在界面靠下方時(shí),點(diǎn)擊輸入框先鱼,標(biāo)題欄也會(huì)被頂出去俭正,如下圖所示:


我們借助 Inspect Layout 工具查看此設(shè)置布局可用高度,從下圖可以看出焙畔,此時(shí)布局可用高度是屏幕的高度掸读,上下滑動(dòng)也只是此屏的高度,在 輸入框9 以下的輸入框滑不出來(lái)宏多,向上滑動(dòng)儿惫,也只能滑到 輸入框1。


3?ScrollView+adjustResize

我們前面說(shuō)過(guò) adjustResize 的使用必須界面布局高度是可變的伸但,如最外層套個(gè) ScrollView 或是界面可收縮的肾请,才起作用。這里在該類(lèi)的 AndroidMainfest.xml 中設(shè)置windowSoftInputMode屬性 為 adjustResize


發(fā)現(xiàn)效果和 1 不設(shè)置任何 windowSoftInputMode屬性 類(lèi)似更胖,其使用高度也是:屏幕高度-狀態(tài)欄高度-軟鍵盤(pán)高度


我們?cè)賮?lái)看看 windowSoftInputMode 默認(rèn)屬性值 stateUnspecified:


可以看出铛铁,系統(tǒng)將選擇合適的狀態(tài),也就是在界面最外層包含一層 ScrollView 時(shí)却妨,設(shè)置默認(rèn)屬性值 stateUnspecified 其實(shí)就是 adjustResize屬性饵逐。

但以下兩方面無(wú)法滿(mǎn)足需求:

1).當(dāng) Activity 設(shè)置成全屏 fullscreen 模式時(shí)或是使用沉浸式狀態(tài)欄時(shí),界面最外層包裹 ?ScrollView彪标,當(dāng)輸入框超過(guò)一屏倍权,當(dāng)前輸入框下面的輸入框并不能上下滑動(dòng)來(lái)輸入,情況類(lèi)似于 ScrollView+adjustPan捞烟,只能滑動(dòng)部分薄声,通過(guò) Inspect Layout 也可以看到,界面可用高度是整個(gè)屏幕高度题画,并不會(huì)進(jìn)行調(diào)整高度默辨。即使設(shè)置 adjustResize,也不起作用婴程。

2).如果是類(lèi)似于注冊(cè)界面或是登錄界面廓奕,鍵盤(pán)會(huì)擋住輸入框下面的登錄按鈕抱婉。

沉浸式狀態(tài)欄下

自android系統(tǒng)4.4(API>=19)就開(kāi)始支持沉浸式狀態(tài)欄档叔,當(dāng)使用 System windows(系統(tǒng)窗口)顯示系統(tǒng)一些屬性和操作區(qū)域桌粉,如最上方的狀態(tài)及沒(méi)有實(shí)體按鍵的最下方的虛擬導(dǎo)航欄。

android:fitsSystemWindows=“true”會(huì)使得屏幕上的可布局空間位于狀態(tài)欄下方與導(dǎo)航欄上方衙四。

方法三:當(dāng)鍵盤(pán)彈起時(shí)铃肯,讓界面整體上移;鍵盤(pán)收起传蹈,讓界面整體下移

使用場(chǎng)景:針對(duì)界面全屏或是沉浸式狀態(tài)欄押逼,輸入框不會(huì)被鍵盤(pán)遮擋。主要用于一些登錄界面惦界,或是需要把界面整體都頂上去的場(chǎng)景挑格。

1?主要實(shí)現(xiàn)步驟

(1). 獲取Activity布局xml的最外層控件,如xml文件如下:


先獲取到最外層控件:

RelativeLayoutmain=(RelativeLayout) findViewById(R.id.main);

(2).獲取到最后一個(gè)控件沾歪,如上面的xml文件漂彤,最后一個(gè)控件是Button:

Buttonlogin_btn=(Button) findViewById(R.id.login_btn);

(3).給最外層控件和最后一個(gè)控件添加監(jiān)聽(tīng)事件:


2?實(shí)現(xiàn)原理

此方法通過(guò)監(jiān)聽(tīng) Activity 最外層布局控件來(lái)檢測(cè)軟鍵盤(pán)是否彈出,然后去手動(dòng)調(diào)用控件的 scrollTo方法 達(dá)到調(diào)整布局目的灾搏。

方法四:監(jiān)聽(tīng)Activity頂層View挫望,判斷軟鍵盤(pán)是否彈起,對(duì)界面重新繪制

此方法的實(shí)現(xiàn)來(lái)自android中提出的issue 5497

https://code.google.com/p/android/issues/detail?id=5497

使用場(chǎng)景:針對(duì)界面全屏或是沉浸式狀態(tài)欄狂窑,界面包含比較多輸入框媳板,界面即使包裹了一層 ScrollView,在鍵盤(pán)顯示時(shí),當(dāng)前輸入框下面的輸入不能通過(guò)上下滑動(dòng)界面來(lái)輸入泉哈。

一蛉幸、實(shí)現(xiàn)步驟

1?把 SoftHideKeyBoardUtil類(lèi) 復(fù)制到項(xiàng)目中;

2?在需要使用的Activity的onCreate方法中添加 SoftHideKeyBoardUtil.assistActivity(this) 即可丛晦。

二巨缘、實(shí)現(xiàn)原理

SoftHideKeyBoardUtil類(lèi) 具體代碼如下:


它的實(shí)現(xiàn)原理主要是:

(1).找到 Activity 的最外層布局控件,我們知道所有的 Activity 都是 DecorView采呐,它就是一個(gè) FrameLayout控件若锁,該控件id是系統(tǒng)寫(xiě)死叫 R.id.content,就是我們 setContentView 時(shí)斧吐,把相應(yīng)的 View 放在此 FrameLayout 控件里

FrameLayoutcontent=(FrameLayout) activity.findViewById(android.R.id.content);

所以 content.getChildAt(0) 獲取到的 mChildOfContent又固,也就是我們用 setContentView 放進(jìn)去的 View。

(2).給我們的 Activity 的xml布局View設(shè)置一個(gè) Listener 監(jiān)聽(tīng):


View.getViewTreeObserver() 可以獲取一個(gè) ViewTreeObserver對(duì)象——它是一個(gè)觀察者煤率,用以監(jiān)聽(tīng)當(dāng)前 View樹(shù) 所發(fā)生的變化仰冠。這里所注冊(cè)的 addOnGlobalLayoutListener,就是會(huì)在當(dāng)前的 View樹(shù) 的全局布局(GlobalLayout)發(fā)生變化蝶糯、或者其中的 View 可視狀態(tài)有變化時(shí)洋只,進(jìn)行通知回調(diào)。『軟鍵盤(pán)彈出/隱 』都能監(jiān)聽(tīng)到识虚。

(3).獲取當(dāng)前界面可用高度


如下圖所示:


(4).重設(shè)高度肢扯, 我們計(jì)算出的可用高度,是目前在視覺(jué)效果上能看到的界面高度担锤。但當(dāng)前界面的實(shí)際高度是比可用高度要多出一個(gè)軟鍵盤(pán)的距離的蔚晨。

通過(guò)上面的這種方法,一般布局輸入鍵盤(pán)擋住輸入框的問(wèn)題基本都能解決肛循。即使界面全屏或是沉浸式狀態(tài)欄情況铭腕。

總結(jié)

下面對(duì)上面幾種方法進(jìn)行對(duì)比:

方法一:

優(yōu)點(diǎn):使用簡(jiǎn)單,只需在Activity的AndroidMainfest.xml中設(shè)置windowSoftInput屬性即可多糠。

注意點(diǎn):adjustResize屬性必須要界面大小可以自身改變累舷;

缺點(diǎn):當(dāng)輸入框比較多時(shí),當(dāng)前輸入框下方的輸入框會(huì)初鍵盤(pán)擋住夹孔,須收起鍵盤(pán)再進(jìn)入輸入被盈;使用adjustPan,輸入框較多時(shí)析蝴,因它是把界面當(dāng)成一個(gè)整體害捕,只會(huì)顯示一屏的高度,會(huì)把ActionBar頂上去闷畸。

方法二:

優(yōu)點(diǎn):使用簡(jiǎn)單尝盼,只需在Activity的最外層布局包裹一個(gè)ScrollView即可。

注意點(diǎn):不可使用adjustPan屬性佑菩,否則ScrollView失效盾沫;

缺點(diǎn):對(duì)于全屏?xí)r,在鍵盤(pán)顯示時(shí)殿漠,無(wú)法上下滑動(dòng)界面達(dá)到輸入的目的赴精;

方法三:

優(yōu)點(diǎn):可以解決全屏?xí)r,鍵盤(pán)擋入按鈕問(wèn)題绞幌。

缺點(diǎn):只要有此需求的Activity均需要獲取到最外層控件和最后一個(gè)控件蕾哟,監(jiān)測(cè)鍵盤(pán)是否彈出,再調(diào)用控件的scrollTo方法對(duì)界面整體上移或是下移莲蜘。代碼冗余谭确。

方法四:

優(yōu)點(diǎn):可以解決全屏?xí)r,鍵盤(pán)擋入輸入框問(wèn)題票渠。只需要寫(xiě)一個(gè)全局類(lèi)逐哈,其他有需求的界面直接在onCreate方法里調(diào)用此類(lèi)的全局方法,即可问顷。

缺點(diǎn):多用了一個(gè)類(lèi)昂秃。

綜上所述:

1) 當(dāng)輸入框比較少時(shí)禀梳,界面只有一個(gè)輸入框時(shí),可以通過(guò)方法一設(shè)置adjustPan肠骆;

2) 如果對(duì)于非全屏/非沉浸式狀態(tài)欄需求算途,只需要使用方法二即可;

3) 如果全屏全屏/沉浸式狀態(tài)欄界面只有一個(gè)類(lèi)有鍵盤(pán)擋入輸入框需求哗戈,可使用方法三郊艘;

4) 如果大部分界面均使用全屏或沉浸式狀態(tài)欄荷科,且有此需求唯咬,則選擇方法四更恰當(dāng)。


文章原創(chuàng)作者GuoLin 書(shū)籍推薦

郭林大神原創(chuàng)android 書(shū)籍:《第一行代碼 android》

淘寶鏈接: https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末畏浆,一起剝皮案震驚了整個(gè)濱河市胆胰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刻获,老刑警劉巖蜀涨,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蝎毡,居然都是意外死亡厚柳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)沐兵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)别垮,“玉大人,你說(shuō)我怎么就攤上這事扎谎√枷耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵毁靶,是天一觀的道長(zhǎng)胧奔。 經(jīng)常有香客問(wèn)我,道長(zhǎng)预吆,這世上最難降的妖魔是什么龙填? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮拐叉,結(jié)果婚禮上岩遗,老公的妹妹穿的比我還像新娘。我一直安慰自己巷嚣,他們只是感情好喘先,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著廷粒,像睡著了一般窘拯。 火紅的嫁衣襯著肌膚如雪红且。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天涤姊,我揣著相機(jī)與錄音暇番,去河邊找鬼。 笑死思喊,一個(gè)胖子當(dāng)著我的面吹牛壁酬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恨课,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼舆乔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了剂公?” 一聲冷哼從身側(cè)響起希俩,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纲辽,沒(méi)想到半個(gè)月后颜武,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拖吼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年鳞上,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吊档。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡篙议,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出籍铁,到底是詐尸還是另有隱情涡上,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布拒名,位于F島的核電站吩愧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏增显。R本人自食惡果不足惜雁佳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望同云。 院中可真熱鬧糖权,春花似錦、人聲如沸炸站。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)旱易。三九已至禁偎,卻和暖如春腿堤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背如暖。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工笆檀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盒至。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓酗洒,卻偏偏與公主長(zhǎng)得像扶关,于是被迫代替她去往敵國(guó)和親酿矢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容