Android 15 以降を搭載したデバイスで SDK 35 以降をターゲットとすると、アプリはエッジ ツー エッジで表示されます。システムバーの背後に描画することで、ウィンドウはディスプレイの幅と高さ全体に表示されます。システムバーには、ステータスバー、キャプション バー、ナビゲーション バーがあります。
多くのアプリにはトップ アプリバーがあります。トップ アプリバーは画面の上端まで伸び、ステータスバーの背後に表示されます。必要に応じて、コンテンツのスクロール時に上部のアプリバーをステータスバーの高さに縮小できます。
多くのアプリには、ボトム アプリバーまたはボトム ナビゲーション バーもあります。また、これらのバーは画面の下端まで伸び、ナビゲーション バーの背後に表示する必要があります。そうでない場合は、アプリはナビゲーション バーの背後にスクロール コンテンツを表示する必要があります。
アプリにエッジツーエッジ レイアウトを実装する場合は、次の点に注意してください。
- エッジ ツー エッジ表示を有効にする
- 視覚的な重複を処理します。
- システムバーの背後にスクリムを表示することを検討してください。
エッジ ツー エッジ表示を有効にする
アプリが SDK 35 以降をターゲットとしている場合、Android 15 以降のデバイスではエッジツーエッジが自動的に有効になります。
以前の Android バージョンでエッジ ツー エッジ対応を有効にするには、次の手順を行います。
アプリまたはモジュールの
build.gradle
ファイルで、androidx.activity
ライブラリへの依存関係を追加します。Kotlin
dependencies { val activity_version =
activity_version
// Java language implementation implementation("androidx.activity:activity:$activity_version") // Kotlin implementation("androidx.activity:activity-ktx:$activity_version") }Groovy
dependencies { def activity_version =
activity_version
// Java language implementation implementation 'androidx.activity:activity:$activity_version' // Kotlin implementation 'androidx.activity:activity-ktx:$activity_version' }enableEdgeToEdge
拡張関数をアプリにインポートします。
Activity
の onCreate
で enableEdgeToEdge
を呼び出して、エッジ ツー エッジを手動で有効にします。setContentView
の前に呼び出す必要があります。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) ... }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { EdgeToEdge.enable(this); super.onCreate(savedInstanceState); ... }
デフォルトでは、enableEdgeToEdge()
はシステムバーを透明にします。ただし、3 ボタン ナビゲーション モードではステータスバーに半透明のスクリムが表示されます。システム アイコンとスクリムの色は、システムのライトまたはダークモードに基づいて調整されます。
enableEdgeToEdge()
関数は、アプリを端から端まで配置する必要があることを自動的に宣言し、システムバーの色を調整します。
enableEdgeToEdge()
関数を使用せずにアプリでエッジ ツー エッジ表示を有効にするには、エッジ ツー エッジ表示を手動で設定するをご覧ください。
インセットを使用して重なりを処理する
図 3 に示すように、アプリのビューの一部がシステムバーの背後に描画される場合があります。
オーバーラップに対処するには、インセットに反応します。インセットは、画面のどの部分がシステム UI(ナビゲーション バーやステータスバーなど)と交差するかを指定します。交差とは、コンテンツの上に表示されることを意味する場合もありますが、システム ジェスチャーに関係することもあります。
アプリをエッジ ツー エッジで表示する場合に適用されるインセットの種類は次のとおりです。
システムバーのインセット: タップ可能で、システムバーで視覚的に隠れてはならないビューに最適です。
ディスプレイ カットアウト インセット: デバイスの形状により画面カットアウトがある可能性のある領域に使用します。
システム ジェスチャー インセット: アプリよりも優先される、システムで使用されるジェスチャー ナビゲーション領域。
システムバーのインセット
システムバーのインセットは、最もよく使用されるタイプのインセットです。システム UI がアプリの上に Z 軸で表示される領域を表します。タップ可能で、システムバーで視覚的に隠れてはならないアプリ内のビューを移動またはパディングする場合に適しています。
たとえば、図 3 のフローティング アクション ボタン(FAB)は、ナビゲーション バーによって部分的に隠れています。
ジェスチャー モードまたはボタンモードでこのような視覚的な重複を回避するには、WindowInsetsCompat.Type.systemBars()
で getInsets(int)
を使用してビューの余白を増やすことができます。
次のコード例は、システムバーの切り欠きを実装する方法を示しています。
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) // Apply the insets as a margin to the view. This solution sets // only the bottom, left, and right dimensions, but you can apply whichever // insets are appropriate to your layout. You can also update the view padding // if that's more appropriate. v.updateLayoutParams<MarginLayoutParams> { leftMargin = insets.left, bottomMargin = insets.bottom, rightMargin = insets.right, } // Return CONSUMED if you don't want want the window insets to keep passing // down to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); // Apply the insets as a margin to the view. This solution sets only the // bottom, left, and right dimensions, but you can apply whichever insets are // appropriate to your layout. You can also update the view padding if that's // more appropriate. MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams(); mlp.leftMargin = insets.left; mlp.bottomMargin = insets.bottom; mlp.rightMargin = insets.right; v.setLayoutParams(mlp); // Return CONSUMED if you don't want want the window insets to keep passing // down to descendant views. return WindowInsetsCompat.CONSUMED; });
このソリューションを図 3 の例に適用すると、図 4 に示すように、ボタンモードで視覚的な重複がなくなります。
図 5 に示すように、ジェスチャー ナビゲーション モードにも同じことが当てはまります。
ディスプレイ カットアウトの切り欠き
一部のデバイスにはディスプレイのカットアウトがあります。通常、カットアウトは画面の上部にあり、ステータスバーに含まれます。デバイスの画面が横向きの場合、切り欠きは垂直エッジに配置されることがあります。アプリが画面に表示するコンテンツによっては、ディスプレイ カットアウトを回避するためにパディングを実装する必要があります。デフォルトでは、アプリはディスプレイ カットアウト内に描画します。
たとえば、多くのアプリ画面にはアイテムのリストが表示されます。ディスプレイの切り欠きやシステムバーでリストアイテムを隠さないでください。
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets -> val bars = insets.getInsets( WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() ) v.updatePadding( left = bars.left, top = bars.top, right = bars.right, bottom = bars.bottom, ) WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> { Insets bars = insets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() ); v.setPadding(bars.left, bars.top, bars.right, bars.bottom); return WindowInsetsCompat.CONSUMED; });
システムバーとディスプレイ カットアウト タイプの論理 OR を取得して、WindowInsetsCompat
の値を決定します。
パディングがリストアイテムとともにスクロールされるように、clipToPadding
を RecyclerView
に設定します。これにより、次の例に示すように、ユーザーがスクロールしたときにアイテムがシステムバーの後ろに表示されるようになります。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
システム ジェスチャー インセット
システム ジェスチャー インセットは、システム ジェスチャーがアプリより優先されるウィンドウの領域を表します。これらの領域は、図 6 の黄色で示されています。
システムバー インセットと同様に、getInsets(int)
と WindowInsetsCompat.Type.systemGestures()
を使用すると、システム ジェスチャー インセットの重複を回避できます。
これらのインセットを使用して、スワイプ可能なビューを端から離すように移動またはパディングします。一般的なユースケースには、ボトムシート、ゲームでのスワイプ、ViewPager2
を使用して実装されたカルーセルなどがあります。
Android 10 以降では、システム ジェスチャー インセットには、ホーム表示ジェスチャー用の下部インセットと、戻るジェスチャー用の左右のインセットが含まれます。
次のコード例は、システム ジェスチャー インセットを実装する方法を示しています。
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()) // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.updatePadding(insets.left, insets.top, insets.right, insets.bottom) // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()); // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.setPadding(insets.left, insets.top, insets.right, insets.bottom); // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. return WindowInsetsCompat.CONSUMED; });
マテリアル コンポーネント
BottomAppBar
、BottomNavigationView
、NavigationRailView
、NavigationView
など、多くのビューベースの Android マテリアル コンポーネント(com.google.android.material)は、インセットを自動的に処理します。{:.external}
ただし、AppBarLayout
はインセットを自動的に処理しません。android:fitsSystemWindows="true"
を追加して、上部インセットを処理します。
Compose のマテリアル コンポーネントでインセットを処理する方法を確認する。
没入モード
一部のコンテンツは、全画面表示で視聴することで、より没入感のあるエクスペリエンスを提供できます。WindowInsetsController
ライブラリと WindowInsetsControllerCompat
ライブラリを使用して、没入モードのシステムバーを非表示にできます。
Kotlin
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) // Hide the system bars. windowInsetsController.hide(Type.systemBars()) // Show the system bars. windowInsetsController.show(Type.systemBars())
Java
Window window = getWindow(); WindowInsetsControllerCompat windowInsetsController = WindowCompat.getInsetsController(window, window.getDecorView()); if (windowInsetsController == null) { return; } // Hide the system bars. windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); // Show the system bars. windowInsetsController.show(WindowInsetsCompat.Type.systemBars());
この機能の実装について詳しくは、没入モードのシステムバーを非表示にするをご覧ください。
参考情報
WindowInsets
、ジェスチャー ナビゲーション、インセットの仕組みについて詳しくは、次のリファレンスをご覧ください。
- Android 15 のエッジ ツー エッジの適用に関するインセット処理のヒント
- WindowInsets - レイアウトのリスナー
- ジェスチャー ナビゲーション: インセット
- Android でインセットがどのように機能するか