Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
縦横無尽に駆け回るフォーカスをユーザーフレンドリーに制御する feat. Compose fo...
Search
Daichi Takeya
May 30, 2025
Programming
0
68
縦横無尽に駆け回るフォーカスをユーザーフレンドリーに制御する feat. Compose for TV
2025/05/30 CA.aab #6の登壇資料です
Daichi Takeya
May 30, 2025
Tweet
Share
More Decks by Daichi Takeya
See All by Daichi Takeya
Worry free TV App development for users and developers - a focus on Compose internal implementation
taked137
0
16
ユーザーも開発者も悩ませない TV アプリ開発 ~Compose の内部実装から学ぶフォーカス制御~
taked137
0
300
Other Decks in Programming
See All in Programming
知られているようで知られていない JavaScriptの仕様 4選
syumai
0
160
CloudflareのSandbox SDKを試してみた
syumai
0
120
Introducing RemoteCompose: break your UI out of the app sandbox.
camaelon
2
530
PHPライセンス変更の議論を通じて学ぶOSSライセンスの基礎
matsuo_atsushi
0
140
AsyncSequenceとAsyncStreamのプロポーザルを全部読む!!
s_shimotori
1
270
エンジニアに事業やプロダクトを理解してもらうためにやってること
murabayashi
0
140
開発生産性が組織文化になるまでの軌跡
tonegawa07
0
140
Blazing Fast UI Development with Compose Hot Reload (droidcon London 2025)
zsmb
0
490
開発組織の戦略的な役割と 設計スキル向上の効果
masuda220
PRO
10
2.2k
Private APIの呼び出し方
kishikawakatsumi
2
820
Researchlyの開発で参考にしたデザイン
adsholoko
0
120
OSS開発者の憂鬱
yusukebe
2
1.3k
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
Optimising Largest Contentful Paint
csswizardry
37
3.5k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
Balancing Empowerment & Direction
lara
5
740
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
37
2.6k
A better future with KSS
kneath
239
18k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
Reflections from 52 weeks, 52 projects
jeffersonlam
355
21k
Stop Working from a Prison Cell
hatefulcrawdad
272
21k
Transcript
縦横無尽に駆け回るフォーカスを ユーザーフレンドリーに制御する feat. Compose for TV CA.aab #6 - 2025/05/30
Daichi Takeya
自己紹介 • Daichi Takeya ◦ X:@taked_oO ◦ GitHub:@taked137 • 株式会社AbemaTV
• Android-based TV向けのABEMAアプリを作っています 2
• リモコンを利用した操作 TV アプリの操作 "TV Navigation Controller" by Android Developers,
licensed under CC BY 2.5. ・フォーカスされている Itemを目立たせる ・フォーカスに伴って 自動でスクロール する Mobile アプリほど直感的な操作が行えない フォーカスの操作性 がユーザー体験に大きく関係する
• フォーカスに伴う処理をよしなに行う Android View ベースのライブラリ Leanback ライブラリ 命令的にUI描画を行うので意図せぬ状態の更新漏れが生じやすい 2025年にもなって Adapter
を触りたくない 😤😤😤 RecyclerView Leanback とは言え、、、 フォーカス体験を向上 させる ロジックが既に実装されている
• Compose for TV は二つのライブラリが存在 ◦ tv-material (stableになった🎉) ◦ tv-foundation
(stable な “compose-foundation” にマイグレーション🚛) Leanback から Compose for TV への移行 Leanback Compose フォーカス目立ちにくいし 縦移動時に謎の横スクロールが 生じてるよ 自分でなんとかする必要があります \ナンテコッタイ / 今回の対象 Compose for TV の時代が来た!?
Compose におけるデフォルトのフォーカス移動 • 入力したキー方向で一番近い View がフォーカスされる 実際のフォーカス移動 キー方向に対応するフォーカス先 シンプルな画面だと デフォルトの挙動で十分
💯 みんな幸せ
デフォルトのフォーカス移動に関するクイズ Q. ピンクのアイテム上で “←” を押下すると、次は何がフォーカスされる?
デフォルトのフォーカス移動に関するクイズ Q. ピンクのアイテム上で “←” を押下すると、次は何がフォーカスされる? ワタシだ
デフォルトのフォーカス制御ロジックの深掘り フォーカス中の View よりも “左側” にあり “右側” にはみ出ていないことが 選出条件 ❌
❌ ❌ • なぜ “←” 押下で、一番左上のアイテム (“Title 1”) にフォーカスが当たるのか 他の View は “左右” というよりは “上下” に位置していると感じられる👏 フォーカス中の View と “Y座標” が重なっていると 優先的に選出 ⭕ ⭕ ⭕
デフォルトのフォーカス制御ロジックの深掘り フォーカス中の View よりも “左側” にあり “右側” にはみ出ていないことが 選出条件 ❌
❌ ❌ • なぜ “←” 押下で、一番左上のアイテム (“Title 1”) にフォーカスが当たるのか 他の View は “左右” というよりは “上下” に位置していると感じられる👏 フォーカス中の View と “Y座標” が重なっていると 優先的に選出 ⭕ ⭕ ⭕ この他にも多くの精巧なロジックによって フォーカス制御が行われている
デフォルトのフォーカス制御の限界 • 純粋に View の位置関係だけに基づいたフォーカス移動 ◦ Column や Row といった
Component の単位を考慮していない 右側のリストの 初期フォーカスが 先頭のアイテムに当たらない 左側のリストに戻った時 同じアイテムが選択されない Master/Detail Flow な画面
フォーカス位置の保存/復元 • “フォーカス位置の復元 ” が自然なUXを実現するための大事な要素 Compose ではフォーカス位置の復元ロジックを別途実装する必要あり Viewの位置関係だけに基づいたフォーカス移動 😚 左右にある前後のタブへ自然に移動できる
😒 何の脈略もないタブへ急に移動する フォーカス位置を復元
Modifier.focusRestorer • フォーカス位置の保存/復元をよしなに実行してくれる ・Modifier に追加するだけで良い ・compose-ui 1.8.0 にて遂に stable に
Modifier.focusRestorer を適用した後の挙動 左右の Column それぞれに focusRestorer を設定 フォーカス位置が 復元される👍 右側のリストが更新されても
以前のフォーカス対象が 復元されてしまう 😑
• focusRestorer の状態を初期化したい ◦ compose.runtime.key を使用 (⚠パフォーマンスとのトレードオフあり ) 明示的なコンポジションの再生成 左側の別のタブが選択されたら コンポジションを再生成
右側のリスト更新に伴って focusRestorer の状態も 初期化される👍 focusRestorer 初期化直後の フォーカス対象の選出は 位置ベースで実行される 😑 あと一息、、、!
focusRestorer の fallback 対象を指定 • 初回などといったフォーカス対象の復元に失敗した際の fallback 先を指定 復元するフォーカス対象が無い場合は 右側のリストの先頭にフォーカス
フォーカス対象を 識別するためのマーカー 見失わないフォーカスに 🎉 focusRestorer 初期化後は View の位置関係を利用した探索はせず 先頭の要素にフォーカスする
focusRestorer の fallback 対象を指定 • 初回などといったフォーカス対象の復元に失敗した際の fallback 先を指定 復元するフォーカス対象が無い場合は 右側のリストの先頭にフォーカス
フォーカス対象を 識別するためのマーカー 見失わないフォーカスに 🎉 focusRestorer 初期化後は View の位置関係を利用した探索はせず 先頭の要素にフォーカスする フォーカス対象の復元以外にも もっと柔軟なフォーカス制御を行いたい!
FocusRequester • 特定の Composable に対してフォーカスをリクエストする API ◦ 🚨 Modifier.focusRequester で
Composable に attach していないとクラッシュ する ▪ compose-ui 1.9.0-alpha01 で Exception の throw から println での警告に変更 focusRestorer の fallback 先に指定 フォーカス当てたり外したり 分割代入で一括生成も可能 Composable に attach した FocusRequester を用いてフォーカス制御を行う
focusProperties による柔軟なフォーカス制御 🔵Row (focusGroup) の初期フォーカスは My Button 2 🔴右キーで My
Button 2 にフォーカス 🟡左キーはデフォルトのフォーカス先 🟢下キーを押してもフォーカス移動はしない FocusRequester を用いて、次のフォーカス先を明示
focusProperties の注意点 focusProperties で 実現してみる フォーカス制御ロジックが 支配的となり 可読性・保守性が著しく低下する コード量が約 2倍に
😫 focusProperties を使えば (おそらく) 全てのユースケースに 対応できる トレードオフを意識しながら 使用する API を検討しよう 💪
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 の進化から目が離せない!
まとめ • TV アプリはフォーカス操作の快適さがユーザー体験に大きく影響 ◦ Leanback ライブラリは体験が向上するための工夫をよしなに実現してくれていた ◦ Compose for
TV では自前で実装していく必要がある • フォーカス制御を行う API はいくつかある ◦ FocusRequester, focusProperties, focusRestorer, etc… ▪ 可読性・アプリパフォーマンス・エラー耐性などのトレードオフを 考慮しながら使い分けていこう