focusGroup 修飾子を使用すると、複数のフォーカス ターゲットをグループ化できます。グループ化により、フォーカス階層の管理、論理 UI 領域(ツールバー、ダイアログ アクション、カードリストなど)の分離、フォーカスが領域に入ったときや領域から出たときのインターセプトが可能になります。
フォーカス グループのコンセプト: 開始、終了、デフォルトのトラバーサル
フォーカス グループは、子フォーカス ターゲットの周囲にまとまりのあるナビゲーション境界を確立します。この境界を越えてフォーカスが移動する仕組みを理解するには、次の 2 つの重要なコンセプトを理解する必要があります。
- Enter: フォーカスがフォーカス グループ外の要素からグループ内の要素に移動したときに発生するイベント。
- 終了: フォーカスがグループの最後の内部要素から離れ、外部のフォーカス ターゲットに移行したときに発生するイベント。
デフォルトのフォーカス走査動作
デフォルトでは、フォーカス グループが外部からフォーカスを受け取ると、次のようになります。
- グループに入る: Compose は、内部の子フォーカス ターゲットを自動的に選択します。1 次元(Tab)ナビゲーションの場合、視覚的な表示順序で最初の子が選択されます。2 次元(矢印キーまたは D-pad)ナビゲーションの場合、入力方向に幾何学的に最も近い子を選択します。
- グループ内の移動: 移動キーを繰り返し押すと、グループで囲まれた兄弟フォーカス ターゲット間でフォーカスが移動します。
- グループの終了: ユーザーがグループ内の最後のフォーカス ターゲットを通過すると、次のキー操作でグループが終了し、グループ外の隣接するフォーカス ターゲットにフォーカスが移動します。
フォーカス エントリのリダイレクトをカスタマイズする
多くの UI 設計では、デフォルトのエントリ ターゲット(表示順序の最初の子など)は、ユーザーにとって最も論理的または便利な選択肢ではありません。
目的とユースケース
左側に [キャンセル] ボタン、右側にメインの [確認] ボタンがある確認ダイアログを考えてみましょう。ユーザーがフォーム フィールドからボタンバーに移動した場合:
- デフォルトの動作: [キャンセル] は視覚的な表示順序で最初のボタンであるため、フォーカスは [キャンセル] に移動します。
- 意図した動作: [Confirm] はメインの推奨される対応であるため、フォーカス順序の早い段階でボタングループに入るときに、フォーカスが [Confirm] に直接移動するようにします。必要に応じて、ユーザーが Left を押して [Cancel] を選択できるようにします。
その他の一般的なユースケースは次のとおりです。
TabRowに入るときに、現在選択されているタブにフォーカスを直接移動する。- メディア再生バーに入ったときに、フォーカスを [再生 / 一時停止] コントロールに直接移動する。
onEnter と FocusRequester を使用した実装
フォーカス グループに入ったときにフォーカスをリダイレクトするには:
- 関連するフォーカス ターゲットを囲む親コンテナに
focusGroup修飾子を適用します。 - コンテナに
focusProperties修飾子を適用し、onEnterコールバックを構成します。 onEnterコールバック(FocusEnterExitScopeにスコープ設定)で、focusRequesterを使用して、優先されるデフォルトの子に関連付けられたFocusRequesterでrequestFocus()を呼び出します。
val defaultChildRequester = remember { FocusRequester() } Row( modifier = Modifier .focusGroup() .focusProperties { // Intercept entry into this group and redirect focus to the primary action onEnter = { defaultChildRequester.requestFocus() } } ) { Button(onClick = { /* Cancel action */ }) { Text("Cancel") } Button( onClick = { /* Confirm action */ }, modifier = Modifier.focusRequester(defaultChildRequester) ) { Text("Confirm (Default)") } }
onEnter と onExit の内部で cancelFocusChange() を呼び出して、境界を越えるフォーカス遷移を完全にブロックすることも、requestedFocusDirection を検査して、ユーザーが Tab、Down、Left のいずれを使用して移動したかに基づいてルーティングをカスタマイズすることもできます。
スクロール可能なコンテナはデフォルトでフォーカス グループになる
Jetpack Compose では、LazyRow、LazyColumn、LazyVerticalGrid などのスクロール可能なコンテナが自動的にフォーカス グループとして機能します。onEnter コールバックまたは onExit コールバックを設定するために、focusGroup 修飾子を明示的に適用する必要はありません。
あなたへのおすすめ
- 注: JavaScript がオフになっている場合はリンクテキストが表示されます
- フォーカス ターゲット
- フォーカス移動順序
- テキスト フィールドのフォーカス
- フォーカスを復元する
- プログラムでフォーカスをリクエストする
- フォーカス ナビゲーションをテストする