Compose にフォーカスする

ユーザーがアプリを操作するときは、多くの場合、画面上の要素をタップします。しかし、インタラクションの形態はこれだけではありません。その他のインタラクションには、次のようなものがあります。

  • ChromeOS ユーザーは、物理キーボードの矢印キーを使用して画面を移動できます。
  • ゲームをプレイしている人は、接続されたゲーム コントローラを使用してゲームのメニューを移動できます。
  • モバイルアプリのユーザーは、画面キーボードを使用して各要素を順番に切り替えられる場合があります。

このような場合、任意の時点でどのコンポーネントがアクティブであるかを追跡することが重要です。これを「フォーカス」と呼びます。画面上の各要素は、論理的な順序でフォーカスする必要があります。Jetpack Compose には、ほとんどの場合に適切なフォーカス処理のデフォルトの方法が用意されています。ただし、場合によっては、このデフォルトの動作を変更する必要があります。

以下のページでは、アプリでフォーカスを使用する方法について説明します。

  • フォーカス移動順序を変更する: デフォルトのフォーカス順序を変更する方法、フォーカス グループを追加する方法、コンポーザブルのフォーカスを無効にする方法について説明します。
  • フォーカス動作を変更する: フォーカスをリクエスト、キャプチャ、解放する方法と、画面に移動したときにフォーカスをリダイレクトする方法について説明します。
  • フォーカスに反応する: フォーカスの変化に反応する方法、要素に視覚的な手がかりを追加する方法、要素のフォーカス状態を把握する方法を説明しています。

デフォルトのフォーカス移動順序

フォーカス検索のデフォルトの動作を詳しく見ていく前に、階層内のレベルのコンセプトを理解することが重要です。一般的に、2 つの Composables が兄弟の場合、つまり同じ親を持つ場合、同じレベルにあると言えます。たとえば、Column 内の要素は同じレベルに存在します。レベルを上げるということは、子からその Composable の親に移動するか、同じ例を維持したまま、あるアイテムからそのアイテムを含む Column に戻るということです。レベルが下がる場合もその逆で、親である Column から含まれるアイテムに移動します。このコンセプトは、他の Composables を含めることができるすべての Composable に適用できます。

UI ナビゲーションには複数の方法がありますが、大部分のユーザーはすでにご存じかもしれません。

  • タブ: 前方または後方への 1 次元ナビゲーション。TAB ナビゲーションにより、階層内の次または前の要素にフォーカスが移動します。デフォルトでは、Compose は Composables の宣言に従います。一方向ナビゲーションは、キーボードの tab キーまたはスマートウォッチのロータリー ベゼルを使用して実現できます。このようなフォーカス検索では、画面上の各要素にアクセスします。
  • 矢印キー: 2 次元ナビゲーション(左、右、上)2 次元ナビゲーションは、テレビの D-pad やキーボードの矢印キーで行えます。移動順序は特定のレベルの要素にのみアクセスします。D-pad の中央ボタンと戻るボタンを使用して、上下に移動できます。

次のスクリーンショットの例をご覧ください。このスクリーンショットでは、4 つのボタンが上下に並んでいて、表示される順にボタンを切り替えています。Jetpack Compose では、この動作をすぐに実現できます。ツールキットでは、tab キーを使用して各コンポーザブルを上から下へ縦方向に循環させたり、矢印または矢印を押してフォーカスを移動できます。

小さなフォーム ファクタで縦方向に上下に配置されたボタンのリストのスクリーンショット。
図 1. 小さいフォーム ファクタで表示されるボタンのリスト

別の種類のレイアウトに切り替えると、状況が少し変わります。以下のレイアウトのように、レイアウトに複数の列がある場合、Jetpack Compose を使用すると、コードを追加せずに列間を移動できます。tab キーを押すと、Jetpack Compose は 1 番目から 4 番目のアイテムを宣言順に自動的にハイライト表示します。キーボードの矢印キーを使用すると、2D 空間で目的の方向に選択されます。

Column {
    Row {
        TextButton({ }) { Text("First field") }
        TextButton({ }) { Text("Second field") }
    }
    Row {
        TextButton({ }) { Text("Third field") }
        TextButton({ }) { Text("Fourth field") }
    }
}

Composables は 2 つの Rows で宣言され、フォーカス要素は 1 番目から 4 番目の順に宣言されます。tab キーを押すと、フォーカス順序は次のようになります。

大きなフォーム ファクタで、2 つの列に並べて配置されたボタンのリストのスクリーンショット。
図 2. 大きなフォーム ファクタで 2 列に並べて配置されたボタンのリスト

以下のスニペットでは、Rows ではなく Columns でアイテムを宣言しています。

Row {
    Column {
        TextButton({ }) { Text("First field") }
        TextButton({ }) { Text("Second field") }
    }
    Column {
        TextButton({ }) { Text("Third field") }
        TextButton({ }) { Text("Fourth field") }
    }
}

このレイアウトは、画面の始点から終端に向かって上から下へ、アイテムを垂直方向に走査します。

大きなフォーム ファクタで、2 つの列に並べて配置されたボタンのリストのスクリーンショット。
図 3. 大きなフォーム ファクタで 2 列に並べて配置されたボタンのリスト

前の 2 つのサンプルは、一方向ナビゲーションが異なりますが、2 次元ナビゲーションについては同じエクスペリエンスを提供します。これは通常、画面上のアイテムが両方の例で同じ地理的位置を示していることが原因です。最初の Column から右に移動するとフォーカスが 2 番目のフォーカスに移動し、最初の Row から下に移動するとフォーカスが下のフォーカスに移動します。