アプリでコンテンツをエッジ ツー エッジで表示する

Compose を試す
Jetpack Compose は Android で推奨される UI ツールキットです。Compose でエッジ ツー エッジを扱う方法を学びます。

システムバーの背後に描画することで、ディスプレイの幅と高さ全体を使用してアプリのエッジ ツー エッジを表示できます。システムバーは、ステータスバーとナビゲーション バーです。

エッジ ツー エッジのレイアウトを実装するには、アプリで次のことを行う必要があります。

  • ナビゲーション バーの背後に描画して、より魅力的でモダンなユーザー エクスペリエンスを実現します。
  • 全幅画像の場合など、コンテンツとレイアウトに適している場合は、ステータスバーの背後に描画します。そのためには、画面上部に固定されるアプリバーを定義する AppBarLayout などの API を使用します。
図 1.エッジ ツー エッジのレイアウトのシステムバー。

アプリにエッジ ツー エッジのレイアウトを実装する手順は次のとおりです。

  1. 狭額縁ディスプレイを有効にする。
  2. 視覚的な重なりがあれば対処します。
ステータスバーの背後に画像があるアプリを示す画像
図 2.ステータスバーの背後に画像を表示するアプリの例

狭額縁ディスプレイを有効にする。

アプリでエッジ ツー エッジ ディスプレイを有効にするには、ActivityonCreateenableEdgeToEdge を呼び出します。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 メソッドは、アプリを端から端までレイアウトする必要があることを自動的に宣言し、システムバーの色を調整します。なんらかの理由でエッジ ツー エッジ ディスプレイを手動でセットアップする必要がある場合は、エッジ ツー エッジ ディスプレイを手動でセットアップするをご覧ください。

インセットを使用して重複を処理する

エッジ ツー エッジ ディスプレイを有効にすると、図 3 に示すように、アプリのビューの一部がシステムバーの背後に描画されることがあります。

画面のどの部分がナビゲーション バーやステータスバーなどのシステム UI と交差するかを指定するインセットに反応することで、重複に対処できます。交差とは、コンテンツの上に表示されることを意味しますが、アプリにシステム ジェスチャーを通知することもできます。

アプリのエッジ ツー エッジ表示に適用されるインセットのタイプは次のとおりです。

  • システムバー インセット: タップ可能で、システムバーによって視覚的に隠してはならないビューに最適です。

  • システム ジェスチャー インセット: アプリよりも優先される、システムが使用するジェスチャー ナビゲーション領域に使用します。

システムバー インセット

システムバー インセットは、最も一般的なタイプのインセットです。これは、システム UI がアプリの上の Z 軸に表示される領域を表します。タップ可能で、システムバーで視覚的に隠してはならないアプリ内のビューを移動またはパディングするのに最適です。

たとえば、図 3 のフローティング アクション ボタン(FAB)は、ナビゲーション バーによって部分的に覆われています。

端から端まで実装されているが、ナビゲーション バーが FAB を覆う画像
図 3. エッジ ツー エッジ レイアウトで FAB に重なったナビゲーション バー。

ジェスチャー モードとボタンモードのどちらでも、このような視覚的な重なりを防ぐには、getInsets(int)WindowInsetsCompat.Type.systemBars() を使用してビューのマージンを大きくします。

次のコード例は、システムバー インセットを実装する方法を示しています。

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 に示すように、ボタンモードで視覚的な重なりは発生しません。

半透明のナビゲーション バーが FAB を覆っていない画像
図 4. ボタンモードでの視覚的な重なりの解決

ジェスチャー ナビゲーション モードについても同様です(図 5 を参照)。

ジェスチャー ナビゲーションによるエッジ ツー エッジの画像
図 5.ジェスチャー ナビゲーション モードでの視覚的な重なりの解決

システム ジェスチャー インセット

システム ジェスチャー インセットは、ウィンドウ内でシステム ジェスチャーがアプリよりも優先される領域を表します。これらの領域は、図 6 でオレンジ色で示されています。

システム ジェスチャー インセットを示す画像
図 6.システム ジェスチャー インセット。

システムバー インセットと同様に、getInsets(int)WindowInsetsCompat.Type.systemGestures() を使用すると、システム ジェスチャー インセットの重複を回避できます。

このインセットを使用すると、スワイプ可能なビューを端から離れるように移動したり、パディングしたりできます。一般的なユースケースには、ボトムシート、ゲーム内のスワイプ、ViewPager2 を使用して実装されたカルーセルなどがあります。

Android 10 以降では、システム ジェスチャー インセットには、ホーム ジェスチャー用の下部インセットと、「戻る」ジェスチャー用の左右のインセットが含まれています。

システム ジェスチャーのインセットの測定値を示す画像
図 7. システム ジェスチャーのインセット測定。

次のコード例は、システム ジェスチャー インセットを実装する方法を示しています。

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

没入モード

コンテンツによっては全画面表示が推奨され、ユーザーの没入感が高まります。没入モードのシステムバーを非表示にするには、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、ジェスチャー ナビゲーション、インセットの仕組みについて詳しくは、以下のリファレンスをご覧ください。