各種 Android WindowInsets 偵測的姿勢

如何取得狀態列的高度以及瀏海長度

Jui Yuan Liou
5 min readOct 6, 2018
「瀏海只剪一點就好。」

這週做了各種偵測狀態列、導航列的高度,為了怕忘記所以來記一篇筆記。會遇見這種問題的原因是目前專案的需求需要將圖片 UI 繪製於狀態列之下,Android 在預設的狀況下,頂部會由狀態列之下開始計算。所以如果沒有需要遮住後方 UI 的需求,理論上不需要去使用以下分享的各種技巧。

首先,想要開啟全畫面繪製,需要開啟 SYSTEM_UI_FLAG_FULLSCREENSYSTEM_UI_FLAG_LAYOUT_STABLE 這兩個 System flag。

開啟後,畫面計算會以整個畫面來算。也就是指 Layout 會繪製於狀態列及導航列的後方,當然必須先將 statusBarColornavigationBarColor 設成透明的才行。補充一點 setStatusBarColor()需要 API Level 21 (Lollipop, 5.0) 以上才能使用。

另外,因為設定了 SYSTEM_UI_FLAG_LAYOUT_STABLE 。 一方面希望保留狀態列、導航列可以繪製出下方,但又希望 Layout 可以從狀態列底部開始算起 (也就是跟一般狀況非 SYSTEM_UI_FLAG_FULLSCREEN時一樣,位置以狀態列底部至導航列頂部計算)。想要達成這種效果,可以為該 Layout 的 root view 加上 fitSystemWindow="true"
如此一來,將 ListViewRecyclerViewclipToPadding 參數設定為 false。基本上就做出了列表滾動時,狀態列下方可以看到滾動的列表內容,就像是 Google App 的效果。

不過本文主要想要來分享一些取得狀態列、導航列等系統 Layout 高度大小的各種技巧。

取得狀態列的高度,可以透過系統的 Resource ID 去拿到狀態列的高度:

現在這是完全可以取得的。但是,一來有鑒於這是系統內部的參數設定,二來是近來 Android 對於內部的方法取用越來越緊縮。所以這個做法目前並不推薦,如此一來只能想想別種方式取得。

第二種處理方式,是去監聽系統的 WindowInsets 的變化。

透過 Callback 取得 windowInsets.getSystemWindowInsetTop() ,這個數值就是「目前」狀態列的高度; windowInsets.getSystemWindowInsetBottom() 則為「目前」導航列的高度。

這兩者的數值會隨著畫面上的狀態列或導航列的狀態而改變,例如有些手機的導航列可以隱藏起來,這時透過 windowInsets.getSystemWindowInsetBottom() 取得的數值即是 0,所以可以藉由這個數值變化來判斷使用者是否隱藏了導航列或是狀態欄。

另外,不希望數值跟著畫面調整而改變,無論如何都需要一個完整的大小數字。可以透過 windowInsets.getStableInsetTop() 或是 windowInsets.getStableInsetBottom() 每次都取得完整的大小。

切記沒有監聽 Insets 變化的需要單純只是為了取得狀態列或導航列的大小,記得要將 Listener 清掉。

不過,上述的 setOnApplyWindowInsetsListener() 需要 API Level 19 (4.4 KitKat) 以上才支援,而取得 System Window Insets 的方法則需要 API Level 20 (有人知道這其實是第一版的 Android Wear 嗎? 😆 ) 以上。需要相容於各個版本,可以透過 ViewCompat 提供的 API 去監聽 WindowInsets 的變化。

Android 9 (Pie) 可以在開發人員選項開啟瀏海模擬

似乎不能漏掉最近廣受大家喜愛的瀏海,Android 9 (Pie) 上已經官方支援了瀏海,不過在 Pie 以前已經有其他廠商跟上這個風潮。要取得螢幕瀏海的資料大家自己弄自己的非常麻煩

在 API Level 28 (9, Pie) SDK 推出之後,新增了可以取瀏海大小的 API。並且 Support Library 28 版 (也就是 AndroidX 1.0.0 版左右) 新增了可以向下相容的 API。雖然,只要是在狀態列的高度之下都應該是安全顯示範圍。但狀態列的高度並不是都與瀏海的高度是一樣的,可以參考 Android 9 之中的雙螢幕凹口模擬,可以發現瀏海的高度與狀態列、導航列的高度不同。如果有最大化顯示畫面的需求,就需要另外取得瀏海的資訊。

同樣,可以透過 ViewCompat 來取得 DisplayCutoutCompat

有這些資訊以後就可以在全螢幕繪製模式下,透過調整 Padding 或 Margin 來避免一些細部的細節被影響到。也能用來新增一些很酷的 UI 效果,例如在狀態列與導航列上一層漸變的陰影。

希望這篇文章對瀏海與各種 WindowInsets 數值取得有些幫助,別忘了可以訂閱這個 Medium,來追蹤我的文章分享。也歡迎分享給喜歡 Hardcore 去弄 UI 的朋友們。 🤗

--

--