ウィンドウ インセットを設定する

アクティビティですべてのインセットの処理を制御したら、Compose API を使用して、コンテンツが隠れていないこと、操作可能な要素がシステム UI と重なっていないことを確認できます。これらの API は、インセットの変更に合わせてアプリのレイアウトを同期します。

パディング修飾子またはサイズ修飾子を使用してインセットを処理する

たとえば、アプリ全体のコンテンツにインセットを適用する最も基本的な方法は次のとおりです。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

このスニペットでは、アプリのコンテンツ全体にパディングとして safeDrawing ウィンドウ インセットを適用しています。これにより、操作可能な要素がシステム UI と重ならないようにできますが、アプリがシステム UI の背後に描画されず、エッジ ツー エッジ効果を実現できません。ウィンドウ全体を最大限に活用するには、画面ごとまたはコンポーネントごとにインセットを適用する場所を微調整する必要があります。

これらのインセット タイプはすべて、API 21 にバックポートされた IME アニメーションで自動的にアニメーション化されます。さらに、これらのインセットを使用するすべてのレイアウトも、インセット値の変化に応じて自動的にアニメーション化されます。

インセットを処理してコンポーザブル レイアウトを調整するには、次の 3 つの方法があります。

パディング修飾子

Modifier.windowInsetsPadding(windowInsets: WindowInsets) は、指定されたウィンドウ インセットをパディングとして適用し、Modifier.padding と同様に動作します。たとえば、Modifier.windowInsetsPadding(WindowInsets.safeDrawing) は、安全な描画インセットを 4 辺すべてにパディングとして適用します。

最も一般的なインセット タイプ用の組み込みユーティリティ メソッドもいくつかあります。 Modifier.safeDrawingPadding() はそのようなメソッドの 1 つで、Modifier.windowInsetsPadding(WindowInsets.safeDrawing) と同等です。次の表に、組み込みのパディング修飾子と、それぞれが適用する WindowInsets タイプを示します。

Modifier.safeDrawingPadding()

WindowInsets.safeDrawing

Modifier.safeGesturesPadding()

WindowInsets.safeGestures

Modifier.safeContentPadding()

WindowInsets.safeContent

Modifier.statusBarsPadding()

WindowInsets.statusBars

Modifier.navigationBarsPadding()

WindowInsets.navigationBars

Modifier.captionBarPadding()

WindowInsets.captionBar

Modifier.systemBarsPadding()

WindowInsets.systemBars

Modifier.imePadding()

WindowInsets.ime

Modifier.systemGesturesPadding()

WindowInsets.systemGestures

Modifier.mandatorySystemGesturesPadding()

WindowInsets.mandatorySystemGestures

Modifier.displayCutoutPadding()

WindowInsets.displayCutout

Modifier.waterfallPadding()

WindowInsets.waterfall

各インセット タイプがカバーする内容については、ウィンドウ インセットについてをご覧ください。

インセット サイズ修飾子

次の修飾子は、コンポーネントのサイズをインセットのサイズに設定することで、ウィンドウ インセットの量を適用します。

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

windowInsets の開始側を幅として適用します(Modifier.width など)。

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

windowInsets の終了側を幅として適用します(Modifier.width など)。

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

windowInsets の上部を高さとして適用します(Modifier.height など)。

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

windowInsets の下側を高さとして適用します(Modifier.height など)。

これらの修飾子は、インセットのスペースを占有する Spacer のサイズを設定する場合に特に便利です。

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

インセットの消費

インセット パディング修飾子(windowInsetsPadding と safeDrawingPadding などのヘルパー)は、パディングとして適用されるインセットの部分を自動的に消費します。コンポジション ツリーを深く掘り下げていくと、ネストされたインセット パディング修飾子とインセット サイズ修飾子は、インセットの一部が外側のインセット パディング修飾子によってすでに消費されていることを認識し、インセットの同じ部分を複数回使用しないようにします。これにより、余分なスペースが過剰に発生するのを防ぎます。

インセット サイズ修飾子は、インセットがすでに消費されている場合に、同じインセットを複数回使用することも回避します。ただし、サイズを直接変更しているため、インセット自体は消費されません。

その結果、パディング修飾子をネストすると、各コンポーザブルに適用されるパディングの量が自動的に変更されます。

前と同じ LazyColumn の例を見ると、LazyColumn は imePadding 修飾子によってサイズ変更されています。LazyColumn 内の最後のアイテムは、システムバーの下部の高さになるようにサイズが設定されます。

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

IME が閉じている場合、imePadding() はパディングを適用しません。そのため、インセットは消費されず、Spacer の高さは下部のシステムバーと一致します。

IME が開くと、IME のサイズに合わせて IME インセットがアニメーション化され、imePadding() 修飾子が下部のパディングを適用して、IME が開くときに LazyColumn のサイズを変更します。imePadding() 修飾子が下部のパディングを適用し始めると、その量のインセットの消費も開始されます。そのため、Spacer の高さが減少し始めます。これは、システムバーの間隔の一部が imePadding() 修飾子によってすでに適用されているためです。imePadding() 修飾子がシステムバーよりも大きい下部パディングを適用すると、Spacer の高さはゼロになります。

IME が閉じると、逆の変更が行われます。imePadding() が下部のシステムバーよりも小さく適用されるため、Spacer は高さゼロから拡大します。最後に、IME のアニメーションが完全に終了すると、Spacer の高さがシステムバーと一致します。

図 2. TextField を使用したエッジ ツー エッジの遅延列。

この動作は、すべての windowInsetsPadding 修飾子間の通信によって実現されます。また、他のいくつかの方法でも影響を受ける可能性があります。

Modifier.consumeWindowInsets(insets: WindowInsets) も Modifier.windowInsetsPadding と同じ方法でインセットを使用しますが、使用したインセットをパディングとして適用しません。これは、インセット サイズ修飾子と組み合わせて、特定の量のインセットがすでに消費されていることを兄弟に伝える場合に便利です。

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues) は、WindowInsets 引数を持つバージョンと非常によく似た動作をしますが、消費する任意の PaddingValues を受け取ります。これは、インセット パディング修飾子以外のメカニズム(通常の Modifier.padding や固定高さのスペーサーなど)によってパディングや間隔が提供される場合に、子に通知するのに役立ちます。

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

消費せずに未加工のウィンドウ インセットが必要な場合は、WindowInsets 値を直接使用するか、WindowInsets.asPaddingValues() を使用して、消費の影響を受けないインセットの PaddingValues を返します。ただし、次の注意事項があるため、可能な限りウィンドウ インセット パディング修飾子とウィンドウ インセット サイズ修飾子を使用することをおすすめします。

インセットと Jetpack Compose のフェーズ

Compose は、基盤となる AndroidX Core API を使用してインセットの更新とアニメーション化を行います。この API は、インセットを管理する基盤となるプラットフォーム API を使用します。このプラットフォームの動作により、インセットは Jetpack Compose のフェーズと特別な関係にあります。

インセットの値は、コンポジション フェーズの後、レイアウト フェーズの前に更新されます。つまり、コンポジションでインセットの値を読み取ると、通常は 1 フレーム遅れたインセットの値が使用されます。このページで説明する組み込みの修飾子は、インセットの値の使用をレイアウト フェーズまで遅らせるように構築されています。これにより、インセットの値は更新されたフレームと同じフレームで使用されます。