遥控器操作的播放器该长什么样:一次十英尺适配实录

更新于 2026 年 8 月 31 日 · 基于原生鸿蒙智慧屏(HarmonyOS 6.0 / API 20 及以上)与 ArkUI 的真机适配

一句话:把手机播放器搬上电视,真正的工作量不在「布局放大」,而在「遥控器能不能走到那儿」——ArkUI 的焦点默认不点亮、布局容器根本进不了走焦、走到行末还会把焦点甩出这一行直接换页。下面八条全是真机上一层层剥出来的,共同点是编译期没有任何提示、日志里也不报错,只有把遥控器拿在手里才看得见。每条给症状、原因、做法。

先对一下这块屏的基准

智慧屏的屏幕是 1280×720vp(3840×2160px,density 3),不是 Android TV 规范基准的 960×540dp。规范里的 dp 值要乘以 1.333 才是这里的 vp,1920×1080 基准写的 px 则要除以 1.5。

布局尺寸要按实际内容区反算,而不是照搬缩放后的数字。照着规范把五列卡片宽换算过来直接用,实测一屏排出了六列半——因为规范里那个数字对应的是它自己的安全区和栅格间距。正确的算法是拿内容区反推:(1280 - 安全区 64x2 - 间距 27x4) / 5 = 208,这才是真的五列。

还有一条工程上的现实:智慧屏没有触摸屏,真机和模拟器上发点击事件都点不动任何东西,只能发遥控器按键。所以下面这些问题没有捷径,全部只能在真机上用方向键一格一格试出来。

下面八条按「走焦 → 视觉 → 布局」分成三组,可以先扫一眼这张速查表:

症状根因做法
方向键一格都不动,无报错焦点态默认未激活,遥控器没有 Tab 键主动激活焦点,并给页面一个默认落点
某张卡片怎么都选不中布局容器进不了走焦用透明的内置 Button 把卡片包起来
焦点在行标题间横跳,碰不到海报横向列表与上下键方向不匹配,被整个跳过滚动容器标成焦点组 + 首项设组内默认焦点
获焦卡片只剩两条竖线放大后超出行边界被裁切横滚行关掉裁切,行高按放大倍率留余量
下键第一个撞上「全部」,碰不到海报入口在标题行,垂直方向挡在海报前挪到行末当最后一张卡
行末按右键直接换了页面走焦回退到线性算法,落点是顶部页签行首吃掉左键、行尾吃掉右键
第一行海报只露出上半截顶栏加页面大标题吃掉近三成首屏TV 上不渲染页面大标题,顶栏随滚动收起
详情页四条左边界,简介一行读不完竖屏纵向流横过来会散为 TV 单独排一套,全部对齐同一条基线

走焦:三条让整个界面「按不动」的坑

一、焦点默认不点亮,而遥控器没有 Tab 键

症状:装上去,方向键按下去,一格都不动。没有任何报错,界面看着完全正常。

原因:ArkUI 的焦点态默认是未激活的,要按一次 Tab 键才「点亮」。桌面和键鼠场景下这个设计完全合理,问题是遥控器上没有 Tab 键

做法:应用要主动激活焦点态。这里有个必须注意的参数:激活时不能让它「触摸后自动熄灭」——那是默认行为,而智慧屏没有触摸屏,一旦熄灭就再也没有东西能把它点回来。

光激活还不够,页面还必须指定一个默认焦点落点。没有落点时焦点会停在页面根节点的一个占位节点上,走焦请求直接失败。诊断办法是打开焦点相关的日志过滤,看到 Request next focus ... Return 0 就是没落点。所以每新增一个页面都要补这一行,这条比想象中容易漏。

二、布局容器进不了走焦,卡片必须用按钮包起来

症状:整张卡片选不中。方向键按过去,焦点直接跳到下一个,中间那张卡当不存在。

原因:这条非常反直觉——Row / Column / Stack 这类布局容器进不了遥控器走焦,给它们设可聚焦属性是无效的。能走焦的是内置可交互组件(Button、TextInput、Toggle、Slider、Checkbox 之类)和叶子文本组件(Text 实测可以,筛选胶囊就靠它);SymbolGlyph、Circle 这类图形叶子不可靠。

这条是用三层二分探针试出来的,结论比预期更严格:同一个网格项里,原生 Button 能获焦;换成自定义组件就不能——给它的根节点设可聚焦没用、在使用处设也没用、把根节点换成 Button 还是没用、连内联展开也不行。与焦点样式、有没有显式宽度全都无关。

做法:在列表项、网格项里用一个透明的内置 Button 把卡片整个包起来(Normal 类型、关掉按压效果、背景透明、内边距归零),焦点样式和点击都挂在这个 Button 上。挂回卡片内部不会生效:焦点在外层,内层永远进不了获焦态。设置页的下钻行、文件页的源列表行也是同一处理。新增可点元素时先问一句:它的宿主是不是内置可交互组件或文本组件?不是就包一层。

三、横滚行整个进不去,因为方向对不上

症状:焦点在各行标题之间上下横跳,海报一张都碰不到。

原因:横向列表的走焦方向是水平的,而上下键发来的走焦请求是垂直的,方向不匹配时 ArkUI 会整个跳过这个容器,回退到线性算法(日志里能看到「方向与步长不同」然后「按默认线性算法请求焦点」)。

做法:把滚动容器标成焦点组,并把首个子项设为组内默认焦点,就得到了「上下换行、左右换卡」的 Android TV 走焦模型。海报网格不需要这条——网格是二维的,上下键本来就进得去。

视觉:焦点反馈自己会出事

四、卡片获焦放大,被容器裁成了两条竖线

症状:卡片获焦后不是「变大了」,而是只剩左右两条描边竖线。

原因:获焦放大到 1.1 倍之后卡片超出了行边界,而列表默认会裁切超出部分——上下两截被裁掉,只剩下描边的两侧还在行内。

做法:横滚行关掉裁切,同时行高要按放大倍率留余量(海报高 + 标题高) × 放大倍率。只关裁切不加行高,放大的卡片会压到下一行上。

五、「全部」入口挡在第一行海报前面

症状:从顶部导航栏按下键,第一个撞上的是行标题右侧那个「全部 ›」,再按下键又到了第二行的「全部」——海报一张都碰不到

原因:十英尺规范要求下键从导航栏落到「第一行里最靠近的那张卡片」,而标题行的「全部」在垂直方向上正好横在海报上方,它就是最靠近的那个可聚焦元素。手机上这个位置完全没问题——手指是直接点的,不存在「路过」。

做法:把「全部」挪到行末,当这一行的最后一张卡。横向走焦到尽头自然会撞上它,上下键完全碰不到。这也是 Android TV 和 Netflix 的做法,属于那种「看一眼别人的实现就明白为什么」的设计。

六、走焦到行末,焦点被甩出这一行,页面跟着换了

症状:媒体库筛选行最左边按左键,跳去了「首页」;最右边按右键,跳去了「文件」。用户的位置和页面一起丢了。

原因:两件事叠在一起。第一,横向走焦到头时 ArkUI 找不到同方向的目标,会回退到线性算法,把焦点甩到「按节点顺序的下一个」;在 Tab 容器内的页面上,甩出去的落点就是顶部导航栏。第二,顶部页签是「焦点移过去即切页」——这是 Tabs 在自定义页签栏下的内置行为,也是十英尺规范推荐的模型。两条各自都合理,撞在一起就是「按一下左键换了个页面」。

做法:每一行的行首吃掉左键、行尾吃掉右键,只在 TV 上生效。试过的两条捷径都不行:焦点组拦不住它(首页最后一张卡按右键照样甩出去);把「方向键不许走出组」整个关掉,又会连上下键也走不出这一行。只能逐行拦按键。目前覆盖了媒体库的三行筛选、设置里的外观三档、文件页的「添加源」、首页所有横滚行以及行末那张「全部」卡。二级页面不在 Tab 容器里,甩出去只是跳到相邻元素、不会换页,优先级低;海报网格是二维的,ArkUI 内置处理,没见过这个问题。

布局:TV 不是把手机界面放大

七、顶栏加大标题,吃掉了首屏近三成高

症状:第一行海报只露出上半截。

原因:1280×720 的屏上,顶栏加一个 40 号的页面大标题就占掉了将近三成的首屏高度。手机上这套「大标题 + 内容」的纵向节奏很舒服,因为手机屏是竖的,纵向空间富裕。

做法:三件事。第一,五个页签的页面大标题在 TV 上一律不渲染——页签栏上就写着同一个词,重复一遍换不来任何信息。第二,页签本身改成图标与文字横排,把顶栏高度收下来。第三,首页向下滚动时顶栏收起(Leanback 那套模型)。

第三条有两个反直觉的前提,都是真机上炸出来的:

八、详情页上出现了四条不同的左边界

症状:把手机详情页直接铺到 16:9 上,海报、标题、按钮、简介各自有一条左边界,视线在四条线之间来回找;简介横跨 1152vp,一行读不完,右侧却空着一大片;剧照只占上半屏,底下压着一条硬边,海报还骑在那条骑缝上。

原因:手机详情页是竖屏的「上图下文」纵向流。纵向流横过来就会散——这不是数值没调好,是排版结构不对。

做法:详情页为 TV 单独排一套:剧照铺满首屏,用一层从左到右的渐变托住文字,信息收进左半屏一个固定宽度里,并且全部对齐安全区那一条基线,简介限三行。手机保持原样。

可以直接拿去用的判断标准:同一屏里出现两条以上左边界,或者一行文字横跨半屏以上,就该为 TV 单独排

配套的还有一条:列表型页面(设置、文件)在 TV 上要限宽居中。这类页面是「一行一项、左标题右取值」,铺满 1280vp 时「字幕」和它右端的取值「chi」隔着大半个屏幕,三米外根本对不上是同一行。做法是根容器保持铺满(背景要满),用内边距把内容收窄居中。海报墙不适用这条——网格本来就该铺满,二维扫视没有长行问题。

常见问题

遥控器的 OK 键,直接绑点击事件就行了吧?

不行。ArkUI 的点击事件只认 KEYCODE_ENTER(2054) 和空格,不认 KEYCODE_DPAD_CENTER(2016)——发 2016 时日志显示按键被吃掉、界面什么也没发生。而设备遥控器的 OK 键发哪个码不一定。所以可点元素要另外把 2016 也映射成点击,不能只依赖点击事件。

同理,手势只认指针事件,遥控器驱动不了。手机上用长按承载的操作(删源、删合集、重新匹配元数据),TV 上必须配一个「OK 键长按」当替代入口,否则那些功能在电视上就没有入口了。

为什么不用系统内置的页签样式?

因为它给不了「当前页」一个够醒目的标识。系统在获焦项上画的那圈胶囊跟随系统主题,浅色模式下是一圈近白的线,压在同样近白的页面底色上几乎看不见。自绘之后当前页是强调色加粗文字、其余压暗,深浅两色下都读得出来。

两条踩过的坑一并写下来。第一,那圈焦点线的颜色改不掉:焦点框属性挂在页签栏内容里的按钮上不生效、去掉按钮壳线还在、把主题色板里六个交互相关的色值一次全设成品牌橙也纹丝不动——它是焦点框的硬编码样式。第二,不要给当前页画底色:实心、淡色、中性淡底三版都试过,根因躲不开——系统那圈焦点框是胶囊形、带外边距,而自绘的底只能画在内容里、尺寸永远比它小一圈,两个同心不同大的圆角块叠着,怎么调都是「框套块」。让系统那圈线独自表示焦点,选中与否全交给文字层次(tvOS 与 Infuse 是同款处理)。

还有一条容易白写代码的:自定义页签栏那个构建函数里拿不到焦点。挂在里面按钮上的获焦/失焦回调一次都不触发(加日志验证过,全空),因此焦点样式和写在按钮根节点上的边框、背景、缩放统统不生效,视觉必须画在内层容器上、且底色要用实心(半透明盖不住系统那圈胶囊)。

「焦点移过去即切页」要自己实现吗?

不用。它是 Tabs 在自定义页签栏下的内置行为,开箱即成立,也没法自己挂回调去实现。但要注意:用内置的底部页签样式时反而不成立(焦点在页签间移动,内容和选中态都不动,必须按 OK)。两种页签栏的走焦模型不同,别互相套结论。

用户反馈某个元素选不中,怎么定位?

八成是第二条——那个元素的宿主是布局容器,没被内置可交互组件包住。真机上打开焦点日志过滤,连着几行「按自定义焦点算法请求焦点失败」最后 Return 0,基本就锁定了。这类问题欢迎直接反馈:带页面截图发到支持页的邮箱,很具体,也很好修。

这些经验能用在别的 ArkUI 应用上吗?

第一到第六条是 ArkUI 走焦机制本身的行为,与业务无关,任何要上智慧屏的应用都会撞上。第七、第八条是布局判断,换个领域也成立——判断标准就那一句:同一屏两条以上左边界,或一行文字横跨半屏以上。

相关阅读:智慧屏怎么看 NAS 和网盘里的电影(面向用户的接入步骤)、智慧屏观影常见问题手机挑片、电视接着看鸿蒙视频播放器怎么挑