android 鍵盤遮擋、顯示隱藏、默認(rèn)焦點(diǎn)等問題

android 中關(guān)于鍵盤和焦點(diǎn)的問題,有時(shí)候處理不好,真的讓人抓狂,昨天在實(shí)現(xiàn)需求的時(shí)候被鍵盤和焦點(diǎn)的問題搞得難受,今天把昨天遇到的問題總結(jié)記錄一下。

1. 鍵盤隱藏和遮擋界面

1.1 鍵盤隱藏

在一個(gè)常見的輸入信息的界面(保存聯(lián)系人信息)為例,界面如圖所示。

有時(shí)候我們需要在進(jìn)入界面的時(shí)候隱藏輸入法鍵盤,有兩種方法:

  1. 在AndroidManifest.xml中對(duì)相應(yīng)的Activity添加一下代碼:
android:windowSoftInputMode="stateHidden"
  1. 在java代碼中調(diào)用:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

多說一句:

網(wǎng)上較多的實(shí)現(xiàn)方式是通過InputMethodManager實(shí)現(xiàn):

Timer timer=new Timer();
timer.schedule(new TimerTask() {

    public void run() {
        InputMethodManager inputMethodManager=(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    }
}, 2000);

但是在我的測(cè)試中,并沒有實(shí)現(xiàn)我的需求,這個(gè)代碼會(huì)在進(jìn)入界面時(shí)彈出鍵盤,然后在隱藏鍵盤。而我的需求是,進(jìn)入界面時(shí)就不能顯示鍵盤,所以不能通過InputMethodManager實(shí)現(xiàn),只能通過windowSoftInputMode實(shí)現(xiàn)。

1.2 鍵盤遮擋

鍵盤隱藏已經(jīng)解決了,再看看,又出現(xiàn)一個(gè)問題。如果界面中內(nèi)容較多,比如上圖中備注1的輸入框,點(diǎn)擊彈起鍵盤時(shí),默認(rèn)情況下,鍵盤會(huì)把界面中的內(nèi)容整體平移推到上面。如圖,連標(biāo)題欄也被擠到屏幕外面去了。

以下內(nèi)容摘自 徹底搞定Android開發(fā)中軟鍵盤的常見問題

Android定義了一個(gè)屬性,名字為windowSoftInputMode, 這個(gè)屬性用于設(shè)置Activity主窗口與軟鍵盤的交互模式,用于避免軟鍵盤遮擋內(nèi)容的問題。

我們可以在AndroidManifet.xml中對(duì)Activity進(jìn)行設(shè)置。如:android:windowSoftInputMode=”stateUnchanged|adjustPan”。

該屬性可選的值有兩部分,一部分為軟鍵盤的狀態(tài)控制,控制軟鍵盤是隱藏還是顯示,另一部分是Activity窗口的調(diào)整,以便騰出空間展示軟鍵盤。
android:windowSoftInputMode的屬性設(shè)置必須是下面中的一個(gè)值,或一個(gè)”state”值加一個(gè)”adjust”值的組合,各個(gè)值之間用 | 分開。

  • stateUnspecified-未指定狀態(tài):當(dāng)我們沒有設(shè)置android:windowSoftInputMode屬性的時(shí)候,軟件默認(rèn)采用的就是這種交互方式,系統(tǒng)會(huì)根據(jù)界面采取相應(yīng)的軟鍵盤的顯示模式。
  • stateUnchanged-不改變狀態(tài):當(dāng)前界面的軟鍵盤狀態(tài),取決于上一個(gè)界面的軟鍵盤狀態(tài),無論是隱藏還是顯示。
  • stateHidden-隱藏狀態(tài):當(dāng)設(shè)置該狀態(tài)時(shí),軟鍵盤總是被隱藏,不管是否有輸入的需求。
  • stateAlwaysHidden-總是隱藏狀態(tài):當(dāng)設(shè)置該狀態(tài)時(shí),軟鍵盤總是被隱藏,和stateHidden不同的是,當(dāng)我們跳轉(zhuǎn)到下個(gè)界面,如果下個(gè)頁面的軟鍵盤是顯示的,而我們?cè)俅位貋淼臅r(shí)候,軟鍵盤就會(huì)隱藏起來。
  • stateVisible-可見狀態(tài):當(dāng)設(shè)置為這個(gè)狀態(tài)時(shí),軟鍵盤總是可見的,即使在界面上沒有輸入框的情況下也可以強(qiáng)制彈出來出來。
  • stateAlwaysVisible-總是顯示狀態(tài):當(dāng)設(shè)置為這個(gè)狀態(tài)時(shí),軟鍵盤總是可見的,和stateVisible不同的是,當(dāng)我們跳轉(zhuǎn)到下個(gè)界面,如果下個(gè)頁面軟鍵盤是隱藏的,而我們?cè)俅位貋淼臅r(shí)候,軟鍵盤就會(huì)顯示出來。
  • adjustUnspecified-未指定模式:設(shè)置軟鍵盤與軟件的顯示內(nèi)容之間的顯示關(guān)系。當(dāng)你跟我們沒有設(shè)置這個(gè)值的時(shí)候,這個(gè)選項(xiàng)也是默認(rèn)的設(shè)置模式。在這中情況下,系統(tǒng)會(huì)根據(jù)界面選擇不同的模式。
  • adjustResize-調(diào)整模式:該模式下窗口總是調(diào)整屏幕的大小用以保證軟鍵盤的顯示空間;這個(gè)選項(xiàng)不能和adjustPan同時(shí)使用,如果這兩個(gè)屬性都沒有被設(shè)置,系統(tǒng)會(huì)根據(jù)窗口中的布局自動(dòng)選擇其中一個(gè)。
  • adjustPan-默認(rèn)模式:該模式下通過不會(huì)調(diào)整來保證軟鍵盤的空間,而是采取了另外一種策略,系統(tǒng)會(huì)通過布局的移動(dòng),來保證用戶要進(jìn)行輸入的輸入框肯定在用戶的視野范圍里面,從而讓用戶可以看到自己輸入的內(nèi)容。

因?yàn)椋谀J(rèn)情況下,系統(tǒng)使用的adjustPan,這種方式平移界面中的內(nèi)容,與之相當(dāng)應(yīng)另一種常用的模式是adjustResize,意為調(diào)整(壓縮)模式,他會(huì)把界面中的空間壓縮,如果有ScrollView,會(huì)讓ScrollView自動(dòng)滾動(dòng)到合適的位置,以完全顯示鍵盤。

由于我的需求不是使用adjustPan模式,所以我直接使用adjustResize模式,AndroidManifest.xml中的聲明如下:

android:windowSoftInputMode="stateHidden|adjustResize"

然后就出現(xiàn)了鍵盤遮擋輸入框的現(xiàn)象,如圖所示,之前可以看到[備注1]和[備注2]被擋住了。

為解決這種情況,需要給頂層布局嵌入一個(gè)ScrollView,然后再來測(cè)試下。

截圖如下所示,可以看到“基本正?!绷?,點(diǎn)擊輸入框會(huì)把空白區(qū)域壓縮,并滑動(dòng)ScrollView,沒有什么大問題,但是只要仔細(xì)觀察,還是可以看出一點(diǎn)不合理的地方,鍵盤頂著輸入法光標(biāo)的下邊緣,但是實(shí)際上ScrollView可以再往下滑動(dòng)一點(diǎn)點(diǎn)的。

1.3 解決輸入框的一點(diǎn)點(diǎn)遮擋的問題

輸入法鍵盤遮擋了[備注1]的EditText下面一點(diǎn)點(diǎn),實(shí)際上鍵盤是在光標(biāo)的正下方緊貼著顯示地,但是此時(shí)的UI交互體驗(yàn)較差,應(yīng)該讓鍵盤彈起時(shí),ScrollView往上多滑動(dòng)一點(diǎn)點(diǎn)。

1.3.1 fullScroll

剛開始使用比較笨的方法,檢測(cè)EditText獲得焦點(diǎn)時(shí),把ScrollView滑動(dòng)到最底端,在網(wǎng)上搜索看到ScrollView滑動(dòng)到最底層的代碼是:

scrollView.fullScroll(View.FOCUS_DOWN);

完整代碼

extra.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean b) {
        if (b) {
            scrollView.fullScroll(View.FOCUS_DOWN);
        }
    }
});

執(zhí)行代碼,發(fā)現(xiàn)[備注1]的輸入框無法輸入文字了,來看看fullScroll最終調(diào)用的地方:

public boolean fullScroll(int direction) {
    boolean down = direction == View.FOCUS_DOWN;
    int height = getHeight();

    mTempRect.top = 0;
    mTempRect.bottom = height;

    if (down) {
        int count = getChildCount();
        if (count > 0) {
            View view = getChildAt(count - 1);
            mTempRect.bottom = view.getBottom() + mPaddingBottom;
            mTempRect.top = mTempRect.bottom - height;
        }
    }

    return scrollAndFocus(direction, mTempRect.top, mTempRect.bottom);
}

最后會(huì)執(zhí)行scrollAndFocus(direction, mTempRect.top, mTempRect.bottom),

private boolean scrollAndFocus(int direction, int top, int bottom) {
    boolean handled = true;

    int height = getHeight();
    int containerTop = getScrollY();
    int containerBottom = containerTop + height;
    boolean up = direction == View.FOCUS_UP;

    View newFocused = findFocusableViewInBounds(up, top, bottom);
    if (newFocused == null) {
        newFocused = this;
    }

    if (top >= containerTop && bottom <= containerBottom) {
        handled = false;
    } else {
        int delta = up ? (top - containerTop) : (bottom - containerBottom);
        doScrollY(delta);
    }

    if (newFocused != findFocus()) newFocused.requestFocus(direction);

    return handled;
}

會(huì)把ScrollView當(dāng)前區(qū)域中的可以獲焦的View,請(qǐng)求焦點(diǎn)。導(dǎo)致本來屬于[備注1]的焦點(diǎn)又失去了,最終的現(xiàn)象就是[備注1]里無法輸入內(nèi)容。

后來將fullScroll方法替換成scrollTo或者scrollBy方法,直接讓ScrollView滑動(dòng)一個(gè)較大值,滑動(dòng)到底部。后來又發(fā)現(xiàn)通過監(jiān)聽輸入框焦點(diǎn)變化來調(diào)整ScrollView又不符合要求,在第一次點(diǎn)擊輸入框時(shí),ScrollView可以滑動(dòng)到指定位置,但是此時(shí)將鍵盤收起,再點(diǎn)擊輸入框彈起鍵盤時(shí),因?yàn)榻裹c(diǎn)沒有發(fā)生變化,所以又不能滑動(dòng)到指定位置了,在網(wǎng)絡(luò)上搜索,有一個(gè)方法
activity_main.getViewTreeObserver().addOnGlobalLayoutListener將整個(gè)布局添加鑒定,鍵盤彈起來之后可見區(qū)域的高度會(huì)變小,并認(rèn)為此現(xiàn)象就是鍵盤彈起導(dǎo)致的,然后再去滑動(dòng)ScrollView??雌饋硎强梢粤耍菦]有從根本上解決問題,可見區(qū)域高度變化超過m,就認(rèn)為是鍵盤彈起來了,程序中m寫的是100,但是不能保證所有的輸入法高度都超過100吧?

于是后來放棄了這種監(jiān)聽鍵盤彈起,再通過代碼滑動(dòng)ScrollView的方法。

通過實(shí)驗(yàn),我發(fā)現(xiàn)使用默認(rèn)的EditText竟然不會(huì)出現(xiàn)鍵盤遮擋一部分輸入框的現(xiàn)象,如圖所示。

而兩者的區(qū)別僅僅在于,出問題的EditText設(shè)置了背景:

<EditText
    android:id="@+id/extra"
    android:layout_width="0dp"
    android:layout_height="50dp"
    android:layout_weight="1"
    android:background="#aaa"
    android:hint="備注1"
    android:gravity="right|center_vertical" />
<EditText
    android:id="@+id/extra"
    android:layout_width="0dp"
    android:layout_height="50dp"
    android:layout_weight="1"
    android:hint="備注1"
    android:gravity="right|center_vertical" />

通過老王的提示,發(fā)現(xiàn)EditText默認(rèn)使用的背景是:

android:background="@android:drawable/edit_text"

而edit_text.xml中使用的背景是一張.9圖片,名為@drawable/textfield_default,在SDK的目錄下搜索圖片,找到圖片,在AS中打開,可以看到.9圖片設(shè)置的顯示的內(nèi)容區(qū)域上面和下面都有padding。

于是,我仿照著給EditText的上下邊距增加Padding值,如下:

<EditText
    android:id="@+id/extra"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:background="#aaa"
    android:paddingTop="10dp"
    android:paddingBottom="10dp"
    android:hint="備注1"
    android:gravity="right|center_vertical" />

注意高度需要設(shè)置為wrap_content,否則需要計(jì)算好高度。

我的理解就是: 鍵盤彈起的時(shí)候上端頂?shù)奈恢糜晒鈽?biāo)的高度和paddingTop和paddingBottom之和決定。也就是

這里理解的不知道對(duì)不對(duì),以后在驗(yàn)證一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作者簡(jiǎn)介 創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog 瀟瀟鳳兒的博客地址: http://b...
    木木00閱讀 10,968評(píng)論 1 43
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,036評(píng)論 25 709
  • 鳳凰涅槃_與死神交鋒閱讀 229評(píng)論 0 0
  • 吳佳培 雨點(diǎn)敲打著車窗,公路兩側(cè)的景物便模糊地飛向身后。淚痕,滑下。窗內(nèi),窗外。 母親的話似乎還在耳畔回響:“這次...
    蘇北以南閱讀 240評(píng)論 0 0
  • 清晨入定,打開后臺(tái),發(fā)現(xiàn)... 這本應(yīng)是一個(gè)秘密,可是這個(gè)數(shù)字竟如此有趣還有些牛的樣子,忍不住截圖下來,權(quán)作紀(jì)念,...
    Leo大叔閱讀 414評(píng)論 0 1

友情鏈接更多精彩內(nèi)容