本文轉載自微信公眾號【mobilehub】
作者 | Vander丶
編輯 | 蘇宓
Android軟鍵盤這塊從我入職到現在,是一個一直糾纏我的問題。
從布局擠壓,到EditText顯示不全,在到彈出時卡頓,在Android軟鍵盤面前我無數次跌倒。
因為網上大多數的知識點比較分散而且很雜,所以本篇做一個整合篇。
Android軟鍵盤這塊知識點比較密集,了解過一次之後,差不多什麼情況都可以找到原因了。
感謝Android軟鍵盤的問題,從我入職陪伴我到現在,讓我一個一個不停的解決。
本文將從以下幾個方面進行介紹:
InputMethodService的源碼解析,從源碼解讀中告訴你為什麼軟鍵盤彈出的是一個Dialog
Android軟鍵盤顯示時,設置windowSoftInputMode的作用
EditText設置imeOptions屬性對軟鍵盤的影響
軟鍵盤上面的按鍵監聽
橫屏狀態下,不希望軟鍵盤顯示全屏怎麼處理
控制軟鍵盤的彈出和關閉的方法
EditText在軟鍵盤彈出的時候顯示不全,怎麼獲取軟鍵盤彈出和關閉的監聽
軟鍵盤彈出的時候,造成頁面卡頓,這時候如何發現問題並解決問題
Android鍵盤面板衝突,布局閃動的解決方法
軟鍵盤其實是一個Dialog
InputMethodService為我們的輸入法創建了一個Dialog,並且對某些參數進行了設置,使之能夠在底部或者全屏顯示。當我們點擊輸入框時,系統會對當前的主窗口進行調整,以便留出相應的空間來顯示該Dialog在底部,或者全屏。
其實這段話我們經常在各種軟鍵盤博客所看到,但是大家並不知道Android是怎麼為我們創建的這個Dialog,所以我先帶大家來看下軟鍵盤生成這塊的源碼,了解軟鍵盤的生成流程。
我們先來看一下InputMethodService的繼承關係:
InputMethodService的繼承關係
因為InputMethodService屬於服務,接下來我們先看一下服務的入口onCreate()方法:
@Override
public void onCreate() {
//設置主題與xml裡面設置theme是一樣的道理
mTheme = Resources.selectSystemTheme(mTheme,
getApplicationInfo().targetSdkVersion,
android.R.style.Theme_InputMethod,
android.R.style.Theme_Holo_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod);
super.setTheme(mTheme);
//創建InputMethodMananger
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mSettingsObserver = SettingsObserver.createAndRegister(this);
mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
/**
* 這裡注意一下,首先這裡的命名屬於Window,然後我們發現了Gravity.BOTTOM,就更加確定了這個就是
* 軟鍵盤所創建的Dialog對象
*/
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
if (mHardwareAccelerated) {
mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
}
initViews();
mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
}
通過上面的分析,我們懷疑這裡的SoftInputWindow是軟鍵盤彈出創建的Dialog對象,下面我們看下SoftInputWindow的源碼。
public class SoftInputWindow extends Dialog{
....
}
看到這裡大家就能明白了,為什麼說軟鍵盤就是一個Dialog。而且這裡通過設置Gravity.BOTTOM來控制當前Dialog在Window中的位置。
在Android中,可以通過給Activity設置windowSoftInputMode這個屬性來控制軟鍵盤與Activity的主窗口的交互方式。
Activity 的主窗口與包含屏幕軟鍵盤的窗口的交互方式,該屬性的設置影響兩個方面:
當Activity成為用戶注意的焦點時軟鍵盤的狀態 - 隱藏還是可見。
對Activity主窗口所做的調整 - 意思是是否將其尺寸調小為軟鍵盤騰出空間,或者當窗口部分被軟鍵盤遮擋時是否平移其內容以使當前焦點可見。
該設置必須是下面所列的值之一,或者是一個「state…」值加上一個「adjust…」值的組合,在任一組中設置多個值(例如,多個「state…」值)都會產生未定義結果。各值之間使用垂直條 (|) 分隔
(1)控制軟鍵盤顯示還是隱藏
stateUnspecified-不指定軟鍵盤的狀態(隱藏還是可見) 將由系統選擇合適的狀態,或依賴主題中的設置,這是對軟鍵盤行為的默認設置
stateUnchanged-保留狀態 當 Activity 轉至前臺時保留軟鍵盤最後所處的任何狀態,無論是可見還是隱藏
stateHidden-隱藏軟鍵盤 當用戶確實是向前導航到 Activity,而不是因離開另一Activity 而返回時隱藏軟鍵盤
stateAlwaysHidden-始終隱藏軟鍵盤 當 Activity 的主窗口有輸入焦點時始終隱藏軟鍵盤
stateVisible-顯示軟鍵盤 在正常的適宜情況下(當用戶向前導航到 Activity 的主窗口時)顯示軟鍵盤
stateAlwaysVisible-顯示軟鍵盤 當用戶確實是向前導航到 Activity,而不是因離開另一Activity 而返回時.
(2)在軟鍵盤彈出時,是否需要Activity對此進行調整
adjustUnspecified 主窗口的默認行為,不指定 Activity 的主窗口是否調整尺寸以為軟鍵盤騰出空間,或者窗口內容是否進行平移以在屏幕上顯露當前焦點。 系統會根據窗口的內容是否存在任何可滾動其內容的布局視圖來自動選擇其中一種模式。 如果存在這樣的視圖,窗口將進行尺寸調整,前提是可通過滾動在較小區域內看到窗口的所有內容。
adjustResize 始終調整 Activity 主窗口的尺寸來為屏幕上的軟鍵盤騰出空間。
adjustPan 不調整 Activity 主窗口的尺寸來為軟鍵盤騰出空間, 而是自動平移窗口的內容,使當前焦點永遠不被鍵盤遮蓋,讓用戶始終都能看到其輸入的內容。 這通常不如尺寸調整可取,因為用戶可能需要關閉軟鍵盤以到達被遮蓋的窗口部分或與這些部分進行交互。
adjustNoting 軟鍵盤彈出時,主窗口Activity不會做出任何響應。
下面將通過例子來介紹adjustNoting、adjustUnspecified、adjustResize、adjustPan在軟鍵盤彈出的區別:
adjustUnspecified : 當軟鍵盤彈出時,系統自動指定窗口的調整模式,根據不同的情況會選擇adjustResize或者adjustPan的一種。
adjustPan : 當軟鍵盤彈出時,會將主窗口的平移(translateY),來適應軟鍵盤的顯示。
adjustResize : 當軟鍵盤彈出時,會讓布局重新繪製,這種一般適應於帶有滑動性質的控制,讓其向下滾動,然後適應軟鍵盤的顯示。
adjustNoting: 軟鍵盤彈出時,主窗口不會做出任何反應。
非滾動布局xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容1" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容2" />
<中間包含無數的EditText>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容12" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容13" />
</LinearLayout>
點擊最下面的EditText12
(1)設置windowSoftInputMode為adjustNoting
從上圖發現,當點擊EditText12時,彈出軟鍵盤將主窗口下半部分給遮蓋,並且主窗口沒有做出任何反應。
(2)設置windowSoftInputMode為adjustPan
當設置其屬性為adjustPan時,當軟鍵盤彈出時,主窗口布局會上移至直到顯示EditText12。
(3)設置windowSoftInputMode為adjustUnspecified
當設置其屬性為默認屬性adjustUnspecified時,發現當點擊EditText12時,主窗口上移來保持EditText12在軟鍵盤之上,這時adjustUnspecified的表現形式與adjustPan相同,所以在無滑動的控制項上,默認的指定形式為adjustPan。
(4)設置windowSoftInputMode為adjustResize
設置其屬性為adjustResize時,發現軟鍵盤彈出的狀態與adjustNoting表現一致,當設置adjustResize時,布局會為了軟鍵盤彈出而重新繪製給軟鍵盤留出空間,而由於控制項無法滑動,所以表現的形式與adjustNoting一致。
滾動布局xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容1" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容2" />
<中間有很多了EditText>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容12" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入您要輸入的內容13" />
</LinearLayout>
</ScrollView>
</LinearLayout>
還是同樣的操作,點擊最下面的EditText13
(1)設置windowSoftInputMode為adjustNoting
我們可以看出,當點擊EditText12時,彈出軟鍵盤將主窗口下半部分給遮蓋,並且主窗口沒有做出任何反應,和不加ScrollView是一樣的情況。
(2)設置windowSoftInputMode為adjustResize
我們可以發現,當設置其屬性為adjustResize時,當軟鍵盤彈出時,ScrollView會重新繪製,然後滾動EditText13位置,使其顯示在軟鍵盤之上。
(3)設置windowSoftInputMode為adjustUnspecified
當設置其屬性為默認屬性adjustUnspecified時,可以發現在添加了ScrollView控制項時,布局的窗口並不會上移(這個觀察Toolbar就可以發現),而通過重繪ScrollView,讓其滾動到最低端,並且給軟鍵盤流出控制項,而這個表現即和adjustResize完全一致。
(4)設置windowSoftInputMode為adjustPan
可以發現,在滑動空間下,設置屬性adjustPan時,依舊會將主窗口上移,來使EditText13顯示在軟鍵盤之上,可以通過觀察Toolbar得知。
windowSoftInputMode總結
通過上面的例子,我們可以完全理解adjust系列的各個參數的作用。而軟鍵盤的顯示和隱藏這裡面需要並不多,而且內容並不算複雜,大家回去自己嘗試下就可以。
在日常開發中,如果需要將軟鍵盤的Enter鍵更改為其他鍵,可以設置其android:imeOptions 屬性,這個屬性可以控制軟鍵盤的Enter鍵,以及橫屏情況下的軟鍵盤顯示狀態。
該設置必須是下面所列的值之一,或者是一個「action…」值加上一個「flag…」值的組合,在action…組中設置多個值(例如,多個「action…」值)都會產生未定義結果,而flag….可以設置多個。各值之間使用垂直條 (|) 分隔
(1)控制軟鍵盤上的Enter鍵
android:imeOptions=」normal」
當android:singleLine=」true」
輸入框後面還有輸入控制項的時候會顯示next,沒有時會顯示done(完成)
當android:singleLine=」false」
輸入框會進行換行操作
android:imeOptions=」actionUnspecified」
該屬性為默認屬性,一般情況下為「normal」的使用情形。
android:imeOptions=」actionNone」
顯示回車鍵,當singleLine為true的時候,會跳到下個可輸出的控制項,否則軟鍵盤消失,輸入完畢。
android:imeOptions=」actionGo」
顯示為Go(前往)按鈕,需要配合android:singleLine使用,否則為回車鍵起換行作用,並且需要自己寫事件。
android:imeOptions=」actionSearch」
顯示搜索(Search)按鈕,需要配合android:singleLine使用,否則為回車鍵起換行作用,並且需要自己寫事件。
android:imeOptions=」actionSend」
顯示send(發送)按鈕,需要配合android:singleLine使用,否則為回車鍵起換行作用,並且需要自己寫事件。
android:imeOptions=」actionNext」
顯示next(下一步)按鈕,作用是跳到下一個可輸入的控制項,需要配合android:singleLine使用,否則為回車鍵起換行作用。
android:imeOptions=」actionDone」
顯示done(完成)按鈕,作用編輯完成,讓軟鍵盤消失.需要配合android:singleLine使用,否則為回車鍵起換行作用。
android:imeOptions=」actionPrevious」
顯示上一步按鈕,如果前面有輸入控制項,點擊後會回到前一個控制項獲取焦點,.需要配合android:singleLine使用,否則為回車鍵起換行作用。
可能各個輸入法的顯示圖標不一樣,但是效果是一樣的,這裡用的是搜狗輸入法。
(2)橫屏下控制軟鍵盤
android:imeOptions=」flagNoFullscreen」
橫屏下設置輸入法不填充全屏。
android:imeOptions=」flagNoExtractUi」
橫屏下設置輸入法不填充全屏.看了API也不太懂與flagNoFullscreen的區別。
android:imeOptions=」flagNavigatePrevious」
橫屏下設置輸入法全屏,設置輸入框上的按鈕為(previous)上一個的作用。
android:imeOptions=」flagNavigateNext」
橫屏下設置輸入法全屏,設置輸入框上的按鈕為(Next)下一個作用。
android:imeOptions=」flagNoAccessoryAction」
橫屏下設置輸入法全屏,並且使其輸入框上的按鈕隱藏。
android:imeOptions=」flagNoEnterAction」
橫屏下設置輸入法全屏,輸入框內的按鈕為完成(Done)狀態.編輯完畢,點完成,軟鍵盤消失。
總結一下:
這裡大部分的屬性,已經介紹完畢,如果英語好的同學,可以去看下官方文檔,可以更好的理解,並且本文以搜狗輸入法為實踐,可能其他的輸入法與其顯示的不同,但是功能應該都是一樣的。
如果需要監聽軟鍵盤的右下角的按鍵,需要為EditText設置setOnEditorActionListener()監聽:
mMainEt = (EditText) findViewById(R.id.main_et);
mMainEt.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (actionId) {
//點擊GO鍵
case EditorInfo.IME_ACTION_GO:
return true;
//點擊Done
case EditorInfo.IME_ACTION_DONE:
return true;
//點擊Next
case EditorInfo.IME_ACTION_NEXT:
return true;
//點擊Previous
case EditorInfo.IME_ACTION_PREVIOUS:
return true;
//點擊None
case EditorInfo.IME_ACTION_NONE:
return true;
//點擊Send
case EditorInfo.IME_ACTION_SEND:
return true;
}
return false;
}
});
上面的方式,只是展示了如何監聽各個按鍵的方法,如果需要消費事件,則需要return true。
實際案例1:橫屏下軟鍵盤不全屏顯示
其實已經在第二方面介紹了,只要設置EditText 的android:imeOptions屬性為 flagNoFullScreen 和 flagNoExtraUI即可。
實際案例2:控制軟鍵盤彈出和關閉
一般來說,在實際項目中,都會使用工具類來控制軟鍵盤的顯示或者關閉。
(1)顯示軟鍵盤
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
view.requestFocus();
imm.showSoftInput(view, 0);
}
(2)關閉軟鍵盤
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
而如果對於這一塊有什麼不明白的,可以參考這篇博客。
實際案例3:EditText顯示不全,並且需要監聽軟鍵盤彈出和關閉
現在有一個常見的需求,EditText被布局包裹,然後需要將原生的EditText背景給替換掉或者直接設置為null(或者其他),然後和布局上下存在間距,然後整體與底部對齊。
這時候彈出軟鍵盤,請看圖:
從圖中可以發現,當原生的EditText背景被替換之後,軟鍵盤會遮蓋掉自定義區域,並且直接顯示在EditText之下,正常情況下,我們是希望軟鍵盤顯示在整個外層的Layout之下的。
當時對於這個問題,我沒有頭緒好一陣子,現在來看,那時候挺年輕的。
而這個問題,就屬於軟鍵盤遮擋布局的問題:
引用塊內容
(1)軟鍵盤遮蓋焦點:
當軟鍵盤彈出的時候,將EditText等輸入類的控制項的焦點遮蓋時,這時候可以設置adjustPan或者adjustResize可以很好的解決。
這裡如果理解好本博文第一塊內容就能很好解決這個問題。
(2)軟鍵盤遮蓋沒有遮蓋焦點,但是遮蓋了需要顯示的控制項:
這時候設置通過設置屬性adjustPan或者adjustResize還不足以解決問題,因為軟鍵盤並沒有遮蓋了EditText的焦點,所以單獨設置這兩個屬性是對軟鍵盤或者界面是無法產生改變的。
這時我們必須從另外一個角度來考慮這個問題,就是來監聽軟鍵盤的彈出和關閉來操作布局,來解決這個問題。
這時候普遍會有以下的幾種解決方案:
(1)設置adjustResize屬性,當軟鍵盤彈出的時候會重繪布局,然後設置根布局的OnLayoutChangeListener的監聽,來監聽布局的變化。
mScrollView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Log.d("new change ", "left : " + left + "top : " + top + "right : " + right + "bottom : " + bottom);
Log.d("old change ", "oldLeft : " + oldLeft + "oldTop : " + oldTop + "oldRight : " + oldRight + "oldBottom : " + oldBottom);
}
});
//當軟鍵盤彈出
07-09 21:16:22.911 23653-23653/com.xiucai.softdemo D/new change: left : 0top : 0right : 1080bottom : 817
07-09 21:16:22.911 23653-23653/com.xiucai.softdemo D/old change: oldLeft : 0oldTop : 0oldRight : 1080oldBottom : 1692
//當軟鍵盤關閉
07-09 21:16:44.457 23653-23653/com.xiucai.softdemo D/new change: left : 0top : 0right : 1080bottom : 1692
07-09 21:16:44.457 23653-23653/com.xiucai.softdemo D/old change: oldLeft : 0oldTop : 0oldRight : 1080oldBottom : 817
我們可以通過上述列印結果發現,根布局的bottom發生變化了,從1692變化到817。我們可以通過這種方式來監聽軟鍵盤的彈出和收回,然後實現平移根布局或者其他的操作來保證軟鍵盤不會遮蓋你所需要的顯示的控制項。
(2)通過getViewTreeObserver().addOnGlobalLayoutListener()監聽窗體的可見區域,來判斷軟鍵盤是否彈出。
/**
* @param root 最外層布局,需要調整的布局
* @param scrollToView 被鍵盤遮擋的scrollToView,滾動root,使scrollToView在root可視區域的底部
*/
private void controlKeyboardLayout(final View root, final View scrollToView) {
root.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
//獲取root在窗體的可視區域
root.getWindowVisibleDisplayFrame(rect);
//獲取root在窗體的不可視區域高度(被其他View遮擋的區域高度)
int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom;
//若不可視區域高度大於100,則鍵盤顯示
if (rootInvisibleHeight > 100) {
int[] location = new int[2];
//獲取scrollToView在窗體的坐標
scrollToView.getLocationInWindow(location);
//計算root滾動高度,使scrollToView在可見區域
int srollHeight = (location[1] + scrollToView.getHeight()) - rect.bottom;
root.scrollTo(0, srollHeight);
} else {
//鍵盤隱藏
root.scrollTo(0, 0);
}
}
});
}
上面代碼是借鑑android 解決輸入法鍵盤遮蓋布局問題 這篇文章而來,目的讓大家了解這種方式是怎麼判斷軟鍵盤的彈出和隱藏。
裡面需要平移的View,不一定是ScrollView,其他View也可,一般來說作為XML的根布局即可。
平常一般來說,我會使用這個工具類
package com.xiucai.common.manager;
import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import java.util.LinkedList;
import java.util.List;
/**
* Created by SuperD on 2017/5/12.
*/
public class SoftKeyBroadManager implements ViewTreeObserver.OnGlobalLayoutListener{
public interface SoftKeyboardStateListener {
void onSoftKeyboardOpened(int keyboardHeightInPx);
void onSoftKeyboardClosed();
}
private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
private final View activityRootView;
private int lastSoftKeyboardHeightInPx;
private boolean isSoftKeyboardOpened;
public SoftKeyBroadManager(View activityRootView) {
this(activityRootView, false);
}
public SoftKeyBroadManager(View activityRootView, boolean isSoftKeyboardOpened) {
this.activityRootView = activityRootView;
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
final Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
Log.d("SoftKeyboardStateHelper", "heightDiff:" + heightDiff);
if (!isSoftKeyboardOpened && heightDiff > 500) { // if more than 100 pixels, its probably a keyboard...
isSoftKeyboardOpened = true;
notifyOnSoftKeyboardOpened(heightDiff);
//if (isSoftKeyboardOpened && heightDiff < 100)
} else if (isSoftKeyboardOpened && heightDiff < 500) {
isSoftKeyboardOpened = false;
notifyOnSoftKeyboardClosed();
}
}
public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
}
public boolean isSoftKeyboardOpened() {
return isSoftKeyboardOpened;
}
/**
* Default value is zero (0)
*
* @return last saved keyboard height in px
*/
public int getLastSoftKeyboardHeightInPx() {
return lastSoftKeyboardHeightInPx;
}
public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.add(listener);
}
public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.remove(listener);
}
private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardOpened(keyboardHeightInPx);
}
}
}
private void notifyOnSoftKeyboardClosed() {
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardClosed();
}
}
}
}
不管是全屏或者其他情況,使用這個工具類來監聽軟鍵盤就可以了,具體的用法:
SoftKeyBroadManager mManager =new SoftKeyBroadManager ("根布局");
//添加軟鍵盤的監聽,然後和上面一樣的操作即可.
mSoftKeyBroadManager.addSoftKeyboardStateListener();
//注意銷毀時,得移除監聽
mSoftKeyBroadManager.removeSoftKeyboardStateListener();
最後如果感覺上面的方案不可行,Github也有一個現成方案,但是博主本人沒試過,原理都是一樣的。大家可以自行取捨。
實際案例4: 軟鍵盤彈出來卡頓,找不到原因?
正常來說博文實差不多到這裡就應該結束了,但是博主在實際開發中,也會遇到一些詭異的現象,例如軟鍵盤彈出卡頓,但是這種情況下,根本無法定位到卡頓原因。
博主遇到這個問題時,懷疑了設置屬性錯誤,懷疑了線程XX沒關,懷疑了布局太過於複雜,總之該想的博主都想了,但是無論怎麼試都是徒勞的。
因為博主犯了一個大錯
在沒找到原因之前,胡亂猜測,可能是這塊?是不是那個的問題,而不確定問題的來源這個問題我感覺大家都會遇到,不從事情的本質上下手,這樣會多花很多時間用在無用的地方,使自己的開發效率很低。
還原下我當時遇到的問題:
當時我在做一個直播間的功能,直播間從主頁跳轉進入的,給大家截一張圖,大家就懂了。
當時做直播間其他功能的時,發現直播間軟鍵盤在彈出和關閉的時候卡頓。
當時懷疑:
(1)什麼動畫沒停,什麼線程沒關。
(2)軟鍵盤 彈出的時候是不是加載的布局太多.
(3)直播間的布局太過於複雜,導致軟鍵盤彈出時繪製卡頓。
在長期的測試發現一個現象,就是在高端機型上這種狀態不明顯,而在底端機型問題比較嚴重,有時候彈出軟鍵盤卡頓很長時間。
過了半個月博主思路換了,想想軟鍵盤彈出卡頓,能不能從卡頓原因下手,來解決問題,後來找到了BlockCanary,接入使用後發現:
原因:竟然是 主頁在軟鍵盤每次彈出或者關閉的時候重新繪製.因為當時BlockCanary當時指向主頁的RecyclerView重繪,我當時想是不可能的.
最後,博主憑直覺認為和主頁SingleTask有關,因為沒有確切的理由,這裡只是提出自己的觀點,而最後問題也解決了。
如果沒有BlockCanary我永遠發現不了,卡頓的原因是在看不見的主頁。
後來我給主頁設置成adjustNothing因為主頁不需要彈出軟鍵盤。
實際案例5:Android鍵盤面板衝突,布局閃動的解決方法
這個問題是我在找Android軟鍵盤相關的問題的時候發現的,這塊我也沒遇到這個問題,所以給大家兩個相關的介紹的地址,希望能對大家有幫助。
解決Android軟鍵盤,布局閃動的相關博文:https://blog.dreamtobe.cn/2015/09/01/keyboard-panel-switch/
解決Android軟鍵盤布局閃動的Demo:https://github.com/angeldevil/KeyboardAwareDemo
開源的Android軟鍵盤布局閃動的解決方案:https://github.com/Jacksgong/JKeyboardPanelSwitch
(1)第一次寫這麼長的博客,感覺會有一些不足,各位看官如果有不合理的地方,或者有誤的地方請直接指出。
(2)本來想整理成一個Demo的,後來簡單看來下,該有的幾乎都貼出來了,有需要的可以按需複製就可以。
(3)寫完這篇博客之後,感覺博客乾貨還是不多,所以定位這篇文章算是總結性質加上實際案例性質的博客。
(4)Android軟鍵盤的總結就差不多到這裡,希望各位看官,如果看到這裡有收穫,就點點讚,灌灌水,頂一波,這樣博主才有寫下去的動力。
(5)感謝小輝同學的校驗,調整了文章中不通順的地方。
想要閱讀更多作者的文章,請點擊【閱讀原文】。
徹底搞定Android開發中軟鍵盤的常見問題:
http://blog.csdn.net/mynameishuangshuai/article/details/51567357
Android UI(EditText)詳解:
http://blog.csdn.net/qq_28057577/article/details/51919965?locationNum=12&fps=1
微信軟鍵盤布局閃動問題:
https://blog.dreamtobe.cn/2015/09/01/keyboard-panel-switch/