當前位置:編程學習大全網 - 源碼下載 - 狀態欄,導航欄,輸入法彈起終極適配方案

狀態欄,導航欄,輸入法彈起終極適配方案

目前常用的沈浸式狀態欄的適配壹般都是,style中配置

<item name="android:windowTranslucentNavigation">false</item>

<item name="android:windowTranslucentStatus">true</item>

又或者設置window的flag,如:

if (Build.VERSION.SDK_INT >= 21) {

int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;

decorView.setSystemUiVisibility(option);

window.setStatusBarColor(Color.TRANSPARENT);

}

然後配合 : fitsSystemWindows = true來解決部分控件不需要沈浸的問題

當然還有更野的,直接固定狀態欄高度,比如tim,網易雲音樂,手機淘寶等

當狀態欄高度為0時,瞬間就暴露出來了,當然也有做的好的,比如微信,等

在實際開發中這些api是完全無法滿足我們對視覺的追求,其中最常見的就是首頁,有的tab需要沈浸式,有些不需要,就完全無法完美實現.

然後就是虛擬導航欄了,設置

<item name="android:windowTranslucentNavigation">true</item> 後,布局會沈入導航欄,還有壹些其它的問題,解決起來也還不算太麻煩,這裏就不詳細說了

還有壹個就是虛擬鍵盤彈起時,布局被蓋住,或者彈起的問題了,當然這個也很好解決

只需要設置android:windowSoftInputMode="adjustResize" 或者 adjustPan就可以輕松解決絕大多數問題.

雖然上面的3個問題都可以或復雜,或簡單的解決,但是想要實現壹些高要求的需求時就有些無力了.

如果能夠監聽到狀態欄,導航欄,虛擬鍵盤高度的變化,是不是這些都可以迎刃而解,而且還能實現壹些更有意思的功能?

如何才能監聽到狀態欄,導航欄,虛擬鍵盤高度的變化呢?

接下來我們先研究研究系統是如何處理這些問題的.

首先我們先用布局查看器來查看界面的布局

可以看到,在未設置沈浸式狀態欄時,對第decorView的第0個view設置paddingtop和marginBottom,同時再在上面覆蓋兩個view來充當狀態欄和導航欄的顏色

當輸入法彈起時同樣是對第decorView的第0個view設置paddingBottom來實現的,這說明decorView的第0個view是可以監聽到我們想要的東西的.

通過查看系統源碼,終於讓我找到了vew的dispatchApplyWindowInsets這個方法

仔細查看了壹下這個源碼

終於讓我找到了給view設置padding的方法.

同時發現decorView重新了onApplyWindowInsets方法,並在這裏添加了充當狀態欄和導航欄顏色的背景view

decorView***有5處調用addView的邏輯,具體如何實現的就不深究了.

既然知道了系統的處理方案接下來我們只需在系統調用dispatchApplyWindowInsets時我們能收到相應的監聽就可以了.

還好系統為我們提供了setOnApplyWindowInsetsListener方法.

我們驗證下我們的成果

到這裏,要講的核心東西已經講完了,只剩下使用問題了.

至於如何使用可以根據個人情況,進行自行選擇.這裏只介紹兩種使用方式.

這裏先警告壹下,setOnApplyWindowInsetsListener後會破壞系統的事件傳遞機制

不過可以通過手動調用onApplyWindowInsets來進行解決

val viewGroup = window.decorView as ViewGroup

viewGroup.setOnApplyWindowInsetsListener { v, insets ->

println("--------$insets")

v.post {

//在這裏動態通知需要適配狀態欄,導航欄,輸入法彈起的控件

}

v.onApplyWindowInsets(insets)

}

2.完全中斷系統的適配方案,由我們自行處理,如:

val viewGroup = window.decorView as ViewGroup

viewGroup[0].setOnApplyWindowInsetsListener { v, insets ->

println("--------$insets")

v.post {

//在這裏動態通知需要適配狀態欄,導航欄,輸入法彈起的控件

insets.run {

//視情況而定

// v.setPadding(stableInsetLeft, stableInsetTop, stableInsetRight, stableInsetBottom)

v.setPadding(systemWindowInsetLeft, systemWindowInsetTop, systemWindowInsetRight, 0)

val h = findViewById<View>(R.id.llBottom)?.height ?: 0

findViewById<View>(R.id.flEt)?.setPadding(0,0,0,systemWindowInsetBottom-h)

}

}

insets.consumeSystemWindowInsets()

}

至於為什麽要在decorView 的第0個view進行監聽自行研究體會.

其中第二種方式可以在不需要對activity進行任何style或者flag的設置就可以實現沈浸式狀態欄效果.可玩性也更強.如果配上

<item name="android:windowTranslucentNavigation">true</item>那可玩性就更強了.至於能發揮到什麽程度就看各人的想法了.

至此,所有的東西都已經寫完了.

最後介紹壹個可以實現的場景:

在輸入法彈起時,我們可以自定義我們需要頂起的控件

  • 上一篇:摩托羅拉V8的理解
  • 下一篇:QQ騰訊的圖標為什麽是企鵝?
  • copyright 2024編程學習大全網