UI がウィンドウ インセットで機能することを確認する

アクティビティがすべてのインセットの処理を制御できるようになったら、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 アニメーションで自動的にアニメーション化されます。これらのインセットを使用するすべてのレイアウトも、インセット値が変更されると自動的にアニメーション化されます。

これらのインセット タイプを使用してコンポーザブル レイアウトを調整するには、主に 2 つの方法があります。パディング修飾子とインセット サイズ修飾子です。

パディング修飾子

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

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

インセット サイズの修飾子

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

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
            )
        )
    }
}

インセットの使用量

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

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

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

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

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

IME が閉じている場合、IME には高さがないため、imePadding() 修飾子はパディングを適用しません。imePadding() 修飾子ではパディングが適用されないため、インセットは使用されず、Spacer の高さはシステムバーの下側のサイズになります。

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

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 コア API を使用してインセットを更新し、アニメーション化します。このインセットは、インセットを管理する基盤となるプラットフォーム API を使用します。このようなプラットフォームの動作により、インセットは Jetpack Compose のフェーズと特別な関係があります。

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