Compose のカットアウト

一部のデバイスでは、ディスプレイ カットアウトとは、ディスプレイの表面まで広がる領域のことです。それにより、デバイスの前面に重要なセンサーのスペースを確保しながら、エッジ ツー エッジのエクスペリエンスを実現できます。

縦表示のカットアウトの例
図 1. ポートレート モードでのカットアウトの例
横表示の切り抜きの例
図 2. 横表示の切り抜きの例

Android は、Android 9(API レベル 28)以降を搭載しているデバイスでディスプレイ カットアウトをサポートしています。ただし、デバイス メーカーは、Android 8.1 以前を搭載したデバイスのディスプレイ カットアウトもサポートできます。

このページでは、カットアウト領域(カットアウトを含むディスプレイ サーフェスの端から端までの長方形)を扱う方法など、カットアウトを備えたデバイスのサポートを Compose で実装する方法について説明します。

デフォルトの場合

デフォルトでは、ディスプレイ カットアウトはウィンドウ インセット情報に含まれています。そのため、ガイドに沿ってアプリの端から端まで調整しても、アプリはディスプレイ カットアウト領域に描画されません。

たとえば、Modifier.windowInsetsPadding(WindowInsets.safeContent)Modifier.windowInsetsPadding(WindowInsets.safeDrawing) を使用する場合、カットアウトが配置される領域には自動的に描画されなくなります。WindowInsets.safeContentWindowInsets.safeDrawing はどちらもディスプレイ カットアウト情報を格納し、デバイス カットアウトの位置を描画しません。

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

    WindowCompat.setDecorFitsSystemWindows(window, false)

    setContent {
        Box(Modifier.windowInsetsPadding(WindowInsets.safeContent)) {
            // Any composable inside here will avoid drawing behind cutouts
        }
    }
}

この動作をさらにカスタマイズするには、カットアウト情報を自分で処理する必要があります。

カットアウト情報を手動で処理する

カットアウトは次のいずれかの方法で処理できます。

Compose の場合、テーマ全体で windowLayoutInDisplayCutoutModedefault に設定し、WindowInsets.displayCutout を利用してコンポーザブルのインセットを処理することをおすすめします。

Canvas(modifier = Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.displayCutout)) {
    drawRect(Color.Red, style = Stroke(2.dp.toPx()))
}

このアプローチでは、必要に応じて displayCutout パディングを優先するか、不要な場合は無視できます。

または、アクティビティ テーマ android:windowLayoutInDisplayCutoutMode を別のオプションに設定するか、window.attributes.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT を使用してウィンドウ属性を設定することで、ビュー カットアウトのドキュメントで説明されている設定と同じ設定を適用できます。ただし、カットアウト モードはアクティビティ全体に適用され、個々のコンポーザブルごとに制御することはできません。

特定のコンポーザブルのディスプレイ カットアウトを優先し、他のコンポーザブルは尊重しない場合は、WindowInset.displayCutout を使用します。この API を使用すると、必要に応じてカットアウト情報にアクセスできます。

おすすめの方法

ディスプレイ カットアウトを使用する場合は、次の点を考慮してください。

  • UI の重要な要素の配置に注意してください。カットアウト領域によって、重要なテキスト、コントロール、その他の情報が隠れないようにしてください。
  • 細かいタップ認識が必要なインタラクティブ要素をカットアウト領域に配置または拡張しないでください。カットアウト領域では、タップの感度が低下することがあります。
  • エッジ ツー エッジのガイダンスに従う場合、カットアウト情報は safeDrawing / safeContent インセットに含まれます。
  • 可能であれば、Modifier.windowInsetsPadding(WindowInsets.safeDrawing) を使用して、コンテンツに適用する適切なパディングを決定します。ステータスバーの高さをハードコードすると、コンテンツが重なったり切れたりする可能性があるため、避けてください。

カットアウト付きでコンテンツがどのようにレンダリングされるかをテストする

アプリの画面と動作をすべてテストしてください。可能であれば、さまざまな種類のカットアウトを備えたデバイスでテストします。カットアウト付きのデバイスがない場合は、Android 9 以降を搭載したデバイスまたはエミュレータで一般的なカットアウト構成をシミュレートできます。手順は次のとおりです。

  1. [開発者向けオプション] を有効にします。
  2. [開発者向けオプション] 画面で、[描画] セクションまで下にスクロールし、[カットアウトがあるディスプレイのシミュレート] を選択します。
  3. カットアウトのタイプを選択します。
    エミュレータでのディスプレイ カットアウトのシミュレーション
    図 3. 開発者向けオプションを使用して、コンテンツのレンダリング方法をテストします。