Compose Multiplatform でのエッジツーエッジ
Android は SDK 35 以降をターゲットとするアプリにエッジツーエッジを強制し、36 ではオプトアウトが削除されます。iOS アプリはステータスバーとホームインジケーターの下に描画することが期待されます。最初からすべての画面をエッジツーエッジで構築しましょう。
ルール: 背景はシステムバーの背後に描画し、コンテンツとコントロールはインセットでパディングします。
有効化
Android (androidApp の MainActivity)、setContent の前に:
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
setContent { App() }
}
マニフェストでアクティビティに android:windowSoftInputMode="adjustResize" を設定し、IME インセットが Compose に届くようにします。
iOS (ContentView.swift): Compose が画面全体を所有するようにします。そうしないと SwiftUI が先にセーフエリアを適用し、Compose がインセットをゼロと認識します。
ComposeView().ignoresSafeArea()
Scaffold がほとんどの作業を行います
Scaffold(
topBar = { TopAppBar(title = { Text(title) }) }, // ステータスバー用に自身をパディング
bottomBar = { NavigationBar { /* ... */ } }, // ナビゲーションバー用に自身をパディング
) { innerPadding ->
LazyColumn(
contentPadding = innerPadding, // コンテンツはバーの下をスクロール
modifier = Modifier.fillMaxSize(),
) { /* items */ }
}
- 常に
innerPaddingを使用します。リストの場合はcontentPaddingとして渡すことで、項目が半透明のバーの背後をスクロールできるようにします。スクロールしないコンテンツにはModifier.padding(innerPadding)を使用します。 - Material 3 のバーは自身のインセットを消費します。
TopAppBarの上にstatusBarsPadding()を追加しないでください。 - ネストされた Scaffold はパディングが二重になります。内側の Scaffold には
contentWindowInsets = WindowInsets(0)を指定するか、外側のコンテンツにconsumeWindowInsets(innerPadding)を適用します。
Scaffold のない画面
Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) { // 背景が画面を埋める
Column(Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.safeDrawing)) { /* content */ }
}
WindowInsets.safeDrawing はステータスバー、ナビゲーションバー、ディスプレイカットアウト、キーボードをカバーします。ジェスチャーが重要な場合は safeContent を使用します。インセットのパディングは、コンテンツを所有するレベルで一度だけ適用し、親と子の両方には適用しないでください。
キーボード
- 入力画面: スクロールコンテナに
Modifier.imePadding()を使用するか、safeDrawingを使用します(safeDrawingには既に IME が含まれています)。 - キーボードの上に表示する必要がある下部ボタン: スクフォールドの
bottomBarにModifier.imePadding()を付けて配置するか、WindowInsets.ime.union(WindowInsets.navigationBars)を使用します。 - コンテンツをスクロール可能にして、フォーカスされたフィールドが表示されるようにします。
フルブリードコンテンツ
画像、マップ、ビデオ、カメラプレビューはインセットを無視して画面全体を埋める必要があります。コントロールをその上にオーバーレイし、コントロールのみを WindowInsets.safeDrawing でパディングします。
システムバーのコントラスト
バーは透明なので、アイコンのコントラストはあなたの責任です。Android では enableEdgeToEdge() がシステムテーマから明るいまたは暗いアイコンを選択します。アプリに独自のテーマ切り替えがある場合は、テーマが変更されたときに一致する SystemBarStyle を指定して再度呼び出します。3ボタンナビゲーションでは Android が半透明のスクリムを追加します。ボトムバーが既に不透明な背景を提供している場合を除き、そのままにしておきます。
広告バナー
下部のバナーはスクフォールドの bottomBar スロット内、ナビゲーションバーのインセットの上に配置し、その高さを予約してコンテンツがジャンプしないようにします。バナーをジェスチャーバーの下に置いたり、ナビゲーションコントロールと重ねたりしないでください。これはレイアウトのバグであると同時に広告ポリシーの問題でもあります。
すべての画面のチェックリスト
- 背景が上部と下部の物理エッジに達している。
- テキストやコントロールがステータスバー、カットアウト、ナビゲーションバー、ホームインジケーターの下にない。
- 最後のリストアイテムがボトムバーの上まで完全にスクロールできる。
- フォーカスされたテキストフィールドがキーボードを開いた状態で表示され続ける。
- 横向き(カットアウトが側面にある場合)とダークテーマで正しく表示される。
- インセットは一度だけ適用され、二重になっていない。
Google の edge-to-edge スキルがインストールされている場合は、これを使用して Android 固有のトラブルシューティングを行ってください。