Slide 1

Slide 1 text

縦横無尽に駆け回るフォーカスを ユーザーフレンドリーに制御する feat. Compose for TV CA.aab #6 - 2025/05/30 Daichi Takeya

Slide 2

Slide 2 text

自己紹介 ● Daichi Takeya ○ X:@taked_oO ○ GitHub:@taked137 ● 株式会社AbemaTV ● Android-based TV向けのABEMAアプリを作っています 2

Slide 3

Slide 3 text

● リモコンを利用した操作 TV アプリの操作 "TV Navigation Controller" by Android Developers, licensed under CC BY 2.5. ・フォーカスされている  Itemを目立たせる ・フォーカスに伴って  自動でスクロール する Mobile アプリほど直感的な操作が行えない フォーカスの操作性 がユーザー体験に大きく関係する

Slide 4

Slide 4 text

● フォーカスに伴う処理をよしなに行う Android View ベースのライブラリ Leanback ライブラリ 命令的にUI描画を行うので意図せぬ状態の更新漏れが生じやすい 2025年にもなって Adapter を触りたくない 😤😤😤 RecyclerView Leanback とは言え、、、 フォーカス体験を向上 させる ロジックが既に実装されている

Slide 5

Slide 5 text

● Compose for TV は二つのライブラリが存在 ○ tv-material (stableになった🎉) ○ tv-foundation (stable な “compose-foundation” にマイグレーション🚛) Leanback から Compose for TV への移行 Leanback Compose フォーカス目立ちにくいし 縦移動時に謎の横スクロールが 生じてるよ 自分でなんとかする必要があります \ナンテコッタイ / 今回の対象 Compose for TV の時代が来た!?

Slide 6

Slide 6 text

Compose におけるデフォルトのフォーカス移動 ● 入力したキー方向で一番近い View がフォーカスされる 実際のフォーカス移動 キー方向に対応するフォーカス先 シンプルな画面だと デフォルトの挙動で十分 💯 みんな幸せ

Slide 7

Slide 7 text

デフォルトのフォーカス移動に関するクイズ Q. ピンクのアイテム上で “←” を押下すると、次は何がフォーカスされる?

Slide 8

Slide 8 text

デフォルトのフォーカス移動に関するクイズ Q. ピンクのアイテム上で “←” を押下すると、次は何がフォーカスされる? ワタシだ

Slide 9

Slide 9 text

デフォルトのフォーカス制御ロジックの深掘り フォーカス中の View よりも “左側” にあり “右側” にはみ出ていないことが 選出条件 ❌ ❌ ❌ ● なぜ “←” 押下で、一番左上のアイテム (“Title 1”) にフォーカスが当たるのか 他の View は “左右” というよりは “上下” に位置していると感じられる👏 フォーカス中の View と “Y座標” が重なっていると 優先的に選出 ⭕ ⭕ ⭕

Slide 10

Slide 10 text

デフォルトのフォーカス制御ロジックの深掘り フォーカス中の View よりも “左側” にあり “右側” にはみ出ていないことが 選出条件 ❌ ❌ ❌ ● なぜ “←” 押下で、一番左上のアイテム (“Title 1”) にフォーカスが当たるのか 他の View は “左右” というよりは “上下” に位置していると感じられる👏 フォーカス中の View と “Y座標” が重なっていると 優先的に選出 ⭕ ⭕ ⭕ この他にも多くの精巧なロジックによって フォーカス制御が行われている

Slide 11

Slide 11 text

デフォルトのフォーカス制御の限界 ● 純粋に View の位置関係だけに基づいたフォーカス移動 ○ Column や Row といった Component の単位を考慮していない 右側のリストの 初期フォーカスが 先頭のアイテムに当たらない 左側のリストに戻った時 同じアイテムが選択されない Master/Detail Flow な画面

Slide 12

Slide 12 text

フォーカス位置の保存/復元 ● “フォーカス位置の復元 ” が自然なUXを実現するための大事な要素 Compose ではフォーカス位置の復元ロジックを別途実装する必要あり Viewの位置関係だけに基づいたフォーカス移動 😚 左右にある前後のタブへ自然に移動できる 😒 何の脈略もないタブへ急に移動する フォーカス位置を復元

Slide 13

Slide 13 text

Modifier.focusRestorer ● フォーカス位置の保存/復元をよしなに実行してくれる ・Modifier に追加するだけで良い ・compose-ui 1.8.0 にて遂に stable に

Slide 14

Slide 14 text

Modifier.focusRestorer を適用した後の挙動 左右の Column それぞれに focusRestorer を設定 フォーカス位置が 復元される👍 右側のリストが更新されても 以前のフォーカス対象が 復元されてしまう 😑

Slide 15

Slide 15 text

● focusRestorer の状態を初期化したい ○ compose.runtime.key を使用 (⚠パフォーマンスとのトレードオフあり ) 明示的なコンポジションの再生成 左側の別のタブが選択されたら コンポジションを再生成 右側のリスト更新に伴って focusRestorer の状態も 初期化される👍 focusRestorer 初期化直後の フォーカス対象の選出は 位置ベースで実行される 😑 あと一息、、、!

Slide 16

Slide 16 text

focusRestorer の fallback 対象を指定 ● 初回などといったフォーカス対象の復元に失敗した際の fallback 先を指定 復元するフォーカス対象が無い場合は 右側のリストの先頭にフォーカス フォーカス対象を 識別するためのマーカー 見失わないフォーカスに 🎉 focusRestorer 初期化後は View の位置関係を利用した探索はせず 先頭の要素にフォーカスする

Slide 17

Slide 17 text

focusRestorer の fallback 対象を指定 ● 初回などといったフォーカス対象の復元に失敗した際の fallback 先を指定 復元するフォーカス対象が無い場合は 右側のリストの先頭にフォーカス フォーカス対象を 識別するためのマーカー 見失わないフォーカスに 🎉 focusRestorer 初期化後は View の位置関係を利用した探索はせず 先頭の要素にフォーカスする フォーカス対象の復元以外にも もっと柔軟なフォーカス制御を行いたい!

Slide 18

Slide 18 text

FocusRequester ● 特定の Composable に対してフォーカスをリクエストする API ○ 🚨 Modifier.focusRequester で Composable に attach していないとクラッシュ する ■ compose-ui 1.9.0-alpha01 で Exception の throw から println での警告に変更 focusRestorer の fallback 先に指定 フォーカス当てたり外したり 分割代入で一括生成も可能 Composable に attach した FocusRequester を用いてフォーカス制御を行う

Slide 19

Slide 19 text

focusProperties による柔軟なフォーカス制御 🔵Row (focusGroup) の初期フォーカスは My Button 2 🔴右キーで My Button 2 にフォーカス 🟡左キーはデフォルトのフォーカス先 🟢下キーを押してもフォーカス移動はしない FocusRequester を用いて、次のフォーカス先を明示

Slide 20

Slide 20 text

focusProperties の注意点 focusProperties で 実現してみる フォーカス制御ロジックが 支配的となり 可読性・保守性が著しく低下する コード量が約 2倍に 😫 focusProperties を使えば (おそらく) 全てのユースケースに 対応できる トレードオフを意識しながら 使用する API を検討しよう 💪

Slide 21

Slide 21 text

Compose for TV の最近のアップデート 2025/05/19時点 compose-ui 1.8.2 🎉 focusRestorer や focusProperties が stable に 🎉 ↑ に伴って、いくつかのクラッシュが解消 🚨 スクロールアニメーションが spring() に固定化 stable compose-ui 1.9.0-alpha02 ℹFocusRequester を attach し忘れて利用しても  Exception が投げられないようになる (println での警告) 🫣スクロールアニメーション問題修正してほしい   (Issue Tracker には別の方が起票済み ) alpha Android-based TV アプリの 更なる進化にご期待ください アプデ速度も早くなってきた印象 今後も Compose for TV の進化から目が離せない!

Slide 22

Slide 22 text

まとめ ● TV アプリはフォーカス操作の快適さがユーザー体験に大きく影響 ○ Leanback ライブラリは体験が向上するための工夫をよしなに実現してくれていた ○ Compose for TV では自前で実装していく必要がある ● フォーカス制御を行う API はいくつかある ○ FocusRequester, focusProperties, focusRestorer, etc… ■ 可読性・アプリパフォーマンス・エラー耐性などのトレードオフを 考慮しながら使い分けていこう