フォーカス移動順序

ユーザーは Tab キーまたは方向(矢印 / D-pad)キーを使用して、UI 要素間でキーボード フォーカスを移動できます。

  • Tab / Shift+Tab: 1 次元の表示順序でフォーカスを前後に移動します。
  • 方向キー: フォーカスを 2 次元(上、下、左、右)に移動します。

1 次元のフォーカス走査

1 次元のフォーカス走査では、Tab キーを押すと、画面上の視覚的な表示順序に基づいて UI のフォーカスが移動します。

たとえば、4 つのボタンを行に配置する場合:

Column {
    Row {
        Button(onClick = { /* ... */ }) { Text("1st") }
        Button(onClick = { /* ... */ }) { Text("2nd") }
    }
    Row {
        Button(onClick = { /* ... */ }) { Text("3rd") }
        Button(onClick = { /* ... */ }) { Text("4th") }
    }
}

Tab キーを押すと、次の順序でボタン間でフォーカスが順番に移動します。

  1. 1 つ目のボタン(上部左側)
  2. 2 つ目のボタン(上端)
  3. 3 つ目のボタン(下部左)
  4. 4 番目のボタン(下端)

最後の要素で Tab キーを押すと、最初のフォーカス ターゲットに戻ります。Shift+Tab キーを押すと、フォーカスが逆順に移動します。

2 次元フォーカス走査

キーボードの矢印キーを押すか、D-pad を使用すると、2 次元のフォーカス走査がトリガーされます。

2 次元の走査では、システムは UI 要素の幾何学的座標と空間境界を検査して、リクエストされた方向で最も近いターゲットを決定します。

2 次元フォーカス走査はラップアラウンドしません。一番下の要素にフォーカスがあるときにユーザーが下キーを押しても、フォーカスは画面の上部に移動せず、その要素に留まります。

ポインタのクリックでフォーカス移動をリセットする

デスクトップ デバイスや大画面デバイスで物理キーボードとマウスまたはタッチパッドを切り替える場合:

  • タップまたはクリックでフォーカスをクリアする: マウスまたはタッチパッドでインタラクティブでないスペースをクリックまたはタップすると、アクティブな要素からフォーカスが解除されます。
  • トラバーサルを再開する: フォーカスがクリアされた後、次に Tab キーを押すと、以前にアクティブだった要素から再開するのではなく、視覚的な表示順序で最初のフォーカス ターゲットから 1 次元トラバーサルが再開されます。これは 2 次元フォーカス走査と同じです。方向キーを使用すると、キーボード フォーカスがリクエストされた方向の最も近いフォーカス ターゲットに移動します。

プログラムでフォーカスをクリアする方法について詳しくは、フォーカスを移動してクリアするをご覧ください。

フォーカス移動順序をカスタマイズする

トラバーサルの動作は、focusProperties 修飾子でカスタマイズできます。

1 次元の移動順序をカスタマイズする

1 次元トラバーサルをオーバーライドするには、FocusRequester を使用して next プロパティまたは previous プロパティを指定します。

  1. remember { FocusRequester() } を使用して FocusRequester オブジェクトを作成します。
  2. focusRequester 修飾子を使用して、FocusRequester をターゲット コンポーザブルにアタッチします。
  3. focusProperties 修飾子をソース コンポーザブルに適用し、FocusRequester を next(Tab の場合)または previous(Shift+Tab の場合)に割り当てます。

val (first, second, third) = remember { FocusRequester.createRefs() }

Column {
    Button(
        onClick = { /* ... */ },
        modifier = Modifier
            .focusRequester(first)
            .focusProperties { next = third }
    ) {
        Text("First (Tab jumps to Third)")
    }
    Button(
        onClick = { /* ... */ },
        modifier = Modifier.focusRequester(second)
    ) {
        Text("Second")
    }
    Button(
        onClick = { /* ... */ },
        modifier = Modifier.focusRequester(third)
    ) {
        Text("Third")
    }
}

2 次元の移動順序をカスタマイズする

同様に、focusProperties 内の up、down、start、end、left、right に FocusRequester インスタンスを割り当てることで、2 次元フォーカス移動をオーバーライドできます。

val (topButton, bottomButton) = remember { FocusRequester.createRefs() }

Button(
    onClick = { /* ... */ },
    modifier = Modifier
        .focusRequester(topButton)
        .focusProperties {
            down = bottomButton
            right = bottomButton
        }
) {
    Text("Top button")
}
Button(
    onClick = { /* ... */ },
    modifier = Modifier.focusRequester(bottomButton)
) {
    Text("Bottom button")
}

特定の方向(レイアウト境界など)へのフォーカス ナビゲーションをブロックするには、そのプロパティ(down = FocusRequester.Cancel など)に FocusRequester.Cancel を割り当てます。特定の方向に対してシステムのデフォルトのトラバーサル アルゴリズムを明示的に保持するには、FocusRequester.Default を割り当てます。