为什么在 TV 应用中必须实现清晰的焦点(Focus)导航?

解读

TV 场景下用户与设备之间没有触控屏,唯一输入手段是遥控器方向键(D-pad)。系统默认的 Focus 搜索算法只能按“最近物理距离”做线性查找,一旦界面出现嵌套 RecyclerView、不规则宫格、横竖滚动冲突或自定义 ViewGroup,焦点就会“跳飞”“循环丢失”甚至直接跑出屏幕。国内电视盒子、运营商 IPTV、投影厂商 ROM 的遥控器键值映射、焦点动画时长、焦点放大系数都不统一,若应用自身不建立一套“可预期、可恢复、可提示”的导航逻辑,用户按一次键就不知道焦点去哪,直接触发广电总局投诉或应用市场一星差评。因此“清晰的焦点导航”不是锦上添花,而是 TV 应用可用性的生死线。

知识点

  1. 输入方式差异:Touch 事件体系 vs KeyEvent 体系,TV 依赖 KEYCODE_DPAD_*。
  2. Focus 查找流程:ViewGroup.focusSearch() → FocusFinder.findNextFocus() → 算法只认“矩形最近”,对斜向、留白、重叠区域会失效。
  3. 焦点孤岛:RecyclerView 预加载导致 View 未附着;Fragment 切换后未主动 requestFocus;自定义 View 未实现 Focusable。
  4. 焦点记忆:系统重启或配置变更后,TV 不像手机有“上次触摸坐标”,必须靠应用自己保存并恢复 _focusedViewId。
  5. 国内适配坑:小米/海信/当贝 ROM 把方向键长按加速到 200 ms 以内,焦点动画跟不上;华为智慧屏把 DPAD_CENTER 映射成 KEYCODE_ENTER,需兼容 onKeyDown 与 onClick。
  6. 合规风险:广电总局《互联网电视应用技术规范》3.2.4 明确要求“所有可交互元素必须可通过遥控器到达”,否则下架。
  7. 辅助功能:TalkBack 在 TV 上叫“屏幕朗读”,焦点丢失会直接中断语音播报,导致无障碍审核失败。

答案

“清晰的焦点导航”是 TV 应用可用性的基石,原因可归纳为四点:

  1. 交互唯一性:TV 没有触控,所有操作依赖遥控器方向键,焦点就是用户的“光标”。
  2. 系统算法局限:默认 FocusFinder 只按矩形距离查找,遇到宫格、轮播、嵌套列表极易跳焦;必须由应用显式指定 nextFocusId、创建 FocusWrapper、重写 focusSearch() 保证路径可预期。
  3. 国内硬件碎片化:不同盒子遥控器键值、焦点动画速度、放大系数差异大,只有应用层统一焦点规则,才能屏蔽 ROM 差异,避免焦点飞出屏幕或卡在不可见区域。
  4. 合规与商业后果:广电总局和各大应用商店把“遥控器可达”列为硬性审核项,焦点丢失会被视为功能缺陷,直接下架或打回;同时焦点混乱会显著降低用户留存,造成投诉和差评。

因此,在 TV 项目中必须把焦点导航当成“一级功能”来设计:提前画焦点路径图、为每个可交互控件写 nextFocus* 属性、在 Fragment/Activity 切换时主动 requestFocus、用 TalkBack 走查无障碍,并在自动化脚本里用 Espresso.pressKey() 做回归,确保任何情况下用户都能“一眼看到焦点在哪,一键到达想去的位置”。

拓展思考

  1. 折叠屏手机展开后进入“桌面模式”,外接蓝牙键盘/遥控器,焦点规则是否直接复用 TV 方案?
  2. 在 Compose for TV 中,Google 提供 TvFocusManager 和 Modifier.focusRestorer,如何与原生 View 混编时共享同一套焦点历史栈?
  3. 国内运营商要求开机广告 5 秒可跳过,若跳过按钮在倒计时结束后自动隐藏,焦点应如何平滑过渡到下一个可见入口,才能不触发“焦点丢失”审核红线?