WindowInsets
には Consume/Consumption(消費)の仕組みがあります。この仕組みについてまとめます。
※この記事ではComposeについてのみ解説しています。
Consume/Consumption
WindowInsetsの消費とはどういうことかというと、親要素でWindowInsetsのPaddingを設定したあとに、子要素で同じものを設定したとしても何も起きないことになります。
コード例で見ていきます。
Box(
modifier = Modifier
.fillMaxSize()
// Paddingを設定して、消費する
.windowInsetsPadding(WindowInsets.safeDrawing)
.background(Color.Blue)
) {
Box(
modifier = Modifier
.fillMaxSize()
// 親Boxで消費されてるので、このPaddingは0になる
.windowInsetsPadding(WindowInsets.safeDrawing)
.background(Color.Red)
)
}
この例では、 Box
を2つ使用していて、親Boxで WindowInsets.safeDrawing
を設定しています。さらに、 子Boxでも同じものを設定しています。
このときに、既に親で使用されてるものを子で使用した場合、既に消費されてる(使用済み)ということでPaddingの値は0となります。
この仕組みによって、重複したPaddingが設定されることなく、安全に使用することができます。
また、ライブラリ提供されてる値だけでなく、以下のように独自のWindowInsetsを作ることで自由な値をPaddingに設定、消費することが可能です。
Box(
modifier = Modifier
.fillMaxSize()
// 独自の値をPaddingに設定して、消費
.windowInsetsPadding(WindowInsets(top = 16.dp, bottom = 16.dp))
.background(Color.Blue)
) {
Box(
modifier = Modifier
.fillMaxSize()
// safeDrawing - 親で設定された値のPaddingが設定される
.windowInsetsPadding(WindowInsets.safeDrawing)
.background(Color.Red)
)
}
このときに、子Boxで指定しているWindowInsetsは safeDrawing
の値から親で消費された分がマイナスされたPaddingが設定されます。
ぼくの手元の環境だと、safeDrawing
のTopが約42.dp だったので、(42–16).dp が子Boxには設定されることになります。
消費されてない値を取得する
WindowInsetsには多くのModifierの拡張がありますが、そのほとんどがConsumeの状態を反映したものになります。例えば、 windowInsetsPadding
や windowInsetsBottomHeight
などです。
消費されたか関係なく消費前の値を取得する方法もあります。
WindowInsets.safeDrawing.asPaddingValues()
WindowInsets.safeDrawing.getBottom(LocalDensity.current)
WindowInsetsの asPaddingValues
や getBottom
を使うと消費される前の値を取得することができます。
最初のコード例の子Boxを asPaddingValues
にすると親と同じPaddingが設定されることになります。
Box(
modifier = Modifier
.fillMaxSize()
// Paddingを設定して、消費する
.windowInsetsPadding(WindowInsets.safeDrawing)
.background(Color.Blue)
) {
Box(
modifier = Modifier
.fillMaxSize()
// 親Boxで消費されてるが、asPaddingValues() では消費されてない値を設定できる
.padding(WindowInsets.safeDrawing.asPaddingValues())
.background(Color.Red)
)
}
Paddingを設定せず消費だけする
これまで見てきた実装ではPaddingと同時に消費していましたが、 consumeWindowInsets
で消費だけすることも可能です。
Box(
modifier = Modifier
.fillMaxSize()
// 消費だけして、Paddingは設定しない
.consumeWindowInsets(WindowInsets.safeDrawing)
.background(Color.Blue)
)
消費された値を取得する
onConsumedWindowInsetsChanged
を使用すると消費された値を取得することも可能です。
直接取得という感じではなくModifierからブロックとして受け取ることができます。
val mutableWindowInsets = remember { MutableWindowInsets() }
Box(
modifier = Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.safeDrawing)
.background(Color.Blue)
.onConsumedWindowInsetsChanged { consumedWindowInsets ->
// 消費された値を設定
mutableWindowInsets.insets = consumedWindowInsets
}
) {
val padding = mutableWindowInsets.asPaddingValues()
}
MutableWindowInsets
という変更用のWindowInsetsクラスがあるので、 onConsumedWindowInsetsChanged
で取得した値をそれに設定することで消費された値を他の箇所で使用することが可能になります。