WindowInsets
是 Jetpack Compose 中的標準 API,用於處理部分或完全遭系統 UI 遮蔽的螢幕區域。這些區域包括狀態列、導覽列和螢幕小鍵盤。您也可以傳遞預先定義的 WindowInsetsRulers
(例如 SafeDrawing
),將內容與系統資訊列和螢幕凹口對齊,或建立自訂 WindowInsetsRulers
。Modifier.fitInside
Modifier.fitOutside
WindowInsetsRulers
的優點
- 避免耗用複雜度:在版面配置的放置階段運作。也就是說,無論上層版面配置執行了什麼操作,它都會完全略過插邊消耗鏈,並一律提供系統資訊列和螢幕凹口的正確絕對位置。如果上層可組合項錯誤地消耗插邊,使用
Modifier.fitInside
或Modifier.fitOutside
方法有助於修正問題。 - 輕鬆避開系統資訊列:有助於應用程式內容避開系統資訊列和螢幕凹口,比使用
WindowInsets
更直接。 - 高度可自訂:開發人員可將內容對齊自訂尺規,並透過自訂版面配置精確控管版面配置。
WindowInsetsRulers
的缺點
- 無法用於評估:由於這項功能是在刊登位置階段運作,因此在較早的評估階段無法取得其提供的位置資訊。
- 版面配置不穩定:如果父項版面配置大小取決於子項大小,可能會導致當機。由於使用
WindowInsetsRulers
的子項可能會在放置期間變更位置或大小,因此可能會造成不穩定的版面配置週期。
建立自訂 WindowInsetsRulers
你可以將內容對齊自訂尺規。舉例來說,假設父項可組合函式不當處理插邊,導致下游子項發生邊框間距問題。雖然這個問題可以透過其他方式解決,包括使用 Modifier.fitInside
,但您也可以建立自訂尺規,精確對齊子項可組合函式,而不必修正上游父項中的問題,如下列範例和影片所示:
@Composable fun WindowInsetsRulersDemo(modifier: Modifier) { Box( contentAlignment = BottomCenter, modifier = modifier .fillMaxSize() // The mistake that causes issues downstream, as .padding doesn't consume insets. // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars), // assume it's difficult to identify this issue to see how WindowInsetsRulers can help. .padding(WindowInsets.navigationBars.asPaddingValues()) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child // Composable without having to fix the parent upstream. .alignToSafeDrawing() // .imePadding() // .fillMaxWidth() ) } } fun Modifier.alignToSafeDrawing(): Modifier { return layout { measurable, constraints -> if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right .current(0f).roundToInt() val left = WindowInsetsRulers.SafeDrawing.current.left .current(0f).roundToInt() measurable.measure(Constraints.fixed(right - left, height)) .place(left, bottom) } } else { val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
以下影片顯示有問題的 IME 插入內容耗用情形示例,左側圖片顯示上游父項導致的問題,右側圖片則顯示如何使用自訂尺規修正問題。TextField
可組合項下方會顯示額外邊框間距,因為父項未耗用導覽列邊框間距。如先前程式碼範例所示,孩子會使用自訂尺規放置在右側圖片的正確位置。
確認家長受到限制
如要安全使用 WindowInsetsRulers
,請確認家長提供有效限制。父項必須有定義的大小,且不能取決於使用 WindowInsetsRulers
的子項大小。在父項可組合函式上使用 fillMaxSize
或其他大小修飾符。
同樣地,將使用 WindowInsetsRulers
的可組合函式放在捲動容器 (例如 verticalScroll
) 內,可能會導致非預期的行為,因為捲動容器會提供無限制的高度限制,這與尺規的邏輯不相容。