WindowInsetsのConsumeについて

Kenji Abe
6 min readJul 2, 2023

--

Photo by Jonathan Borba on Unsplash

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の状態を反映したものになります。例えば、 windowInsetsPaddingwindowInsetsBottomHeight などです。

消費されたか関係なく消費前の値を取得する方法もあります。

WindowInsets.safeDrawing.asPaddingValues()

WindowInsets.safeDrawing.getBottom(LocalDensity.current)

WindowInsetsの asPaddingValuesgetBottom を使うと消費される前の値を取得することができます。

最初のコード例の子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 で取得した値をそれに設定することで消費された値を他の箇所で使用することが可能になります。

参考

--

--

Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO