ジェスチャー ナビゲーション

Android 10 (API レベル 29) 以降の Android システムは、ジェスチャー ベースのナビゲーションを完全にサポートしています。開発中のアプリがこの機能に十分対応したものとなるようにするため、アプリ デベロッパーは次の 2 つのことを行う必要があります。

  • アプリのコンテンツを画面全体に拡大する。
  • 競合するアプリ ジェスチャーに対処する。

エッジツーエッジのアプリ コンテンツ

フローティング ナビゲーション バーによって利用できるようになった追加の画面スペースを利用するためには、アプリに変更を加える必要があります。

透明なシステム バーの設定

透明なシステム バーを設定するには、以下の値をテーマに設定します。

<!-- values-29/themes.xml: -->

<style name="AppTheme" parent="...">
    <item name="android:navigationBarColor">@android:color/transparent</item>

    <!-- Optional, but recommended for full edge-to-edge rendering -->
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>
ボタンが有効になった透明なナビゲーション バー。

また、Window.setNavigationBarColor()Window.setStatusBarColor() を使用すると、透明なシステム バーを動的に設定できます。

端末がジェスチャー ナビゲーションを使用するに設定されているとき、アプリのナビゲーション バーの背景を透明にすると、ハンドルの色はハンドルの背景にあるコンテンツの色に基づいて、システムにより自動的に更新されます。ただし、2 ボタンまたは 3 ボタン ナビゲーション モードの場合、これらのボタンの色は変化しません。その代わり、システムは背景を半透明にして、ボタンが見やすく表示されるようにします。しかし、システムがこの機能を実行できるのは、アプリが API レベル 29 以上をターゲットにしている場合のみです。

UI 表示フラグの設定

ビューを画面全体にレイアウトできるようにするには、アプリでこうしたビューの処理が可能であることをアプリからシステムに伝える必要があります。そのためには、View.setSystemUiVisibility() を使用して次のフラグを設定します。

Kotlin

view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)

Java

view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

これらのフラグはいっしょになって、ナビゲーション バーとステータスバーが存在しないかのようにアプリを画面全体にレイアウトする必要があることをシステムに指示します。追加の全画面表示イベント用に SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN を設定することで、ステータスバーの背後に描画することもできます。

ステータスバーを自動的に処理するビュークラス(CoordinatorLayoutDrawerLayout など)を使用している場合、SYSTEM_UI_FLAG_LAYOUT_STABLE フラグと SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN フラグがすでに設定されていることがあります。また、setSystemUiVisibility() を使用して他のフラグ(SYSTEM_UI_FLAG_IMMERSIVE など)を設定している場合は、それらのフラグが上述のフラグを上書きしていないように注意する必要があります。

アプリがエッジ ツー エッジのビューを使用している場合でも、システムは引き続き、システムバーの場所を示すために WindowInsets API を使用します。

手動のインセットの使用

アプリでカスタムのビュー階層を使用する場合、システム ウィンドウ インセットを手動で使用する必要が生じることがあります。その場合は通常、OnApplyWindowInsetsListener インターフェースを実装します。

Kotlin

view.setOnApplyWindowInsetsListener() {v, insets ->
    insets.consumeSystemWindowInsets()

Java

view.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
    @Override
    public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
        // 1. Move views on top edge down by insets.getSystemWindowInsetTop()
        // 2. Move views on bottom edge up by insets.getSystemWindowInsetBottom()
        // 3. Also check getSystemWindowInsetLeft/Right(), such as for landscape
        // orientations
        return insets.consumeSystemWindowInsets();
    }
});

WindowInsetsgetSystemWindowInsets() を介して、すべてのシステムバーに通常の表示用インセットを提供します。また、Android 10 では以下のメソッドが WindowInsets に追加されています。

競合するアプリのジェスチャーの対処

ジェスチャー ナビゲーション モデルでは、アプリ デベロッパーが以前に使用していたジェスチャーと競合することがあります。そのため、アプリのユーザー インターフェースの調整が必要になることがあります。

「戻る」のジェスチャーとの競合

「戻る」の新しいシステム ジェスチャーは、画面の左または右端から内側へのスワイプです。このジェスチャーが、これらの領域内におけるアプリのナビゲーション要素を妨げる可能性があります。画面の左端および右端でのナビゲーション要素の機能を維持するには、タップ入力を受け入れる必要がある領域をシステムに示すことで、「戻る」ジェスチャーを選択的に無効にする必要があります。そのためには、Android 10 で導入された View.setSystemGestureExclusionRects() API に List<Rect> を渡します。このメソッドは、androidx.core:core:1.1.0-dev01 時点での ViewCompat でも使用できます。

次に例を示します。

Kotlin

var exclusionRects = listOf(rect1, rect2, rect3)

fun onLayout(
        changedCanvas: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
  // Update rect bounds and the exclusionRects list
  setSystemGestureExclusionRects(exclusionRects)
}

fun onDraw(canvas: Canvas) {
  // Update rect bounds and the exclusionRects list
  setSystemGestureExclusionRects(exclusionRects)
}

Java

List<Rect> exclusionRects;

public void onLayout(
        boolean changedCanvas, int left, int top, int right, int bottom) {
    // Update rect bounds and the exclusionRects list
    setSystemGestureExclusionRects(exclusionRects);
}

public void onDraw(Canvas canvas) {
    // Update rect bounds and the exclusionRects list
    setSystemGestureExclusionRects(exclusionRects);
}

ホーム ジェスチャーおよびクイック スイッチ ジェスチャーとの競合

ホームとクイック スイッチの新しいシステム ジェスチャーは、以前はナビゲーション バーが表示されていた画面下部のスペースでのスワイプです。アプリは、これらのジェスチャーを「戻る」ジェスチャーのように無効にすることはできません。

この問題を軽減するために、Android 10 では、タップ認識のしきい値をアプリに通知する WindowInsets.getMandatorySystemGestureInsets() API が導入されています。

ビュー階層のないゲームやアプリ

ビュー階層のないゲームやアプリでは、ユーザーがシステム ジェスチャー領域の近くをスワイプすることがよく必要になります。この場合、ゲームは Window.setSystemGestureExclusionRects() を使用して、システム ジェスチャー領域に重なる領域を除外することができます。ゲームプレイ中など、必要なときのみこうした領域を除外するように注意する必要があります。

ゲームでユーザーがホーム ジェスチャー領域の近くをスワイプする必要があれば、アプリは没入モードで配置されるようにリクエストできます。これによって、ゲームの操作中はシステム ジェスチャーが無効になりますが、ユーザーは画面を下からスワイプすることで、システム ジェスチャーを再度有効にすることができます。

参考資料

ジェスチャー ナビゲーションの詳細については、次の追加リソースを参照してください。

ブログ投稿

動画