前一段時間,項目中有一個頁面,如圖所示
圖片中的最下方的按鈕,取消預約,這兩個按鈕,在正常的頁面中是正常顯示的,但是會出現頭部的ToolBar會被頂出頁面,也就是在彈出輸入框的時候,然後測試小夥伴就給我提了bug,沒有辦法,只好去尋找解決辦法;
1.最開始尋找的解決辦法,就是在androidMnifest,清淡文件中加入
"android:windowSoftInputMode="adjustPan|stateHidden"
,但是沒啥用啊,後來又詳細的查看了相對應的其他幾個參數,也都挨個試驗了,最後失敗;只好再次去另尋他法
2.第二個方法就是進行讓整個頁面進行滑動,NestedScrollView使用相關的,將整個頁面除了toolbar,都包裹進去,然後在彈出輸入框的時候進行頁面的整體調整,最後勉強通過測試,但是展示效果不理想,而且按鈕也跟着滑動,明顯的不符合自己的需求;
3.實在沒有辦法了,繼續百度,找方法吧;然後就找到了本片文章的主題ViewTreeObserver,
ViewTreeObserver 註冊一個觀察者來監聽視圖樹,當視圖樹的佈局、視圖樹的焦點、視圖樹將要繪製、視圖樹滾動等發生改變時,ViewTreeObserver都會收到通知,ViewTreeObserver不能被實例化,可以調用View.getViewTreeObserver()來獲得。
官方文檔的描述ViewTreeObserver是用來監聽一些全局變化的。
在 ViewTreeObserver 中,包含了以下幾個接口:
interface ViewTreeObserver.OnGlobalFocusChangeListener
interface ViewTreeObserver.OnGlobalLayoutListener
interface ViewTreeObserver.OnPreDrawListener
interface ViewTreeObserver.OnScrollChangedListener
interface ViewTreeObserver.OnTouchModeChangeListener
具體的使用方法
View decorView = getWindow().getDecorView();
View contentView = findViewById(Window.ID_ANDROID_CONTENT);
decorView.getViewTreeObserver().addOnGlobalLayoutListener(getGlobalLayoutListener(decorView, contentView));
在這裏開始進行監聽的編寫,然後實現對應的監聽方法,對其中的對應的數據contentView.setPadding,設置好他的偏移量,這樣就可以在彈出輸入框的時候,不會讓我們的toolbar被頂上去,也不會遮擋住我們的EditText,而且按鈕也不會被遮蓋
private ViewTreeObserver.OnGlobalLayoutListener getGlobalLayoutListener(final View decorView, final View contentView) {
return () -> {
Rect r = new Rect();
decorView.getWindowVisibleDisplayFrame(r);
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
if (diff != 0) {
if (contentView.getPaddingBottom() != diff) {
contentView.setPadding(0, 0, 0, diff);
} else {
contentView.setPadding(0, 0, 0, 0);
}
};
}
然後在我以爲大功告成的時候,我們的測試小夥伴又提bug了,在小米的劉海屏手機上
這兩個按鈕,只展示了頭部的一丟丟,取消 和預約按鈕的字基本都看出出來;這就很煩人,但是沒有辦法之後繼續加判斷
這裏獲取是不是小米的機型判斷
public static boolean isMiui() {
String manufacturer = Build.MANUFACTURER;
//這個字符串可以自己定義,例如判斷華爲就填寫huawei,魅族就填寫meizu
return !"xiaomi".equalsIgnoreCase(manufacturer);
}
然後在ViewTreeObserver之中加上相關的判斷,然後大功告成
private ViewTreeObserver.OnGlobalLayoutListener getGlobalLayoutListener(final View decorView, final View contentView) {
return () -> {
Rect r = new Rect();
decorView.getWindowVisibleDisplayFrame(r);
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
if (diff != 0) {
if (contentView.getPaddingBottom() != diff) {
if (isMiui()) {
contentView.setPadding(0, 0, 0, diff);
}else{
contentView.setPadding(0, 0, 0, 0);
}
}
} else {
if (contentView.getPaddingBottom() != 0) {
contentView.setPadding(0, 0, 0, 0);
}
}
};
}
開始以爲ViewTreeObserver,這個看起來肯定很難,畢竟看起來好像很難的樣子,但是實際使用時,沉下心,一切問題就有不太大了.