HarmonyOS 平板页面被拉扁:用断点切结构,而不是把手机布局拉宽
摘要:手机单列页面直接铺到平板,常见后果是卡片像横幅、文本行过长、右侧空白却没有信息。本文以课程首页为例,根据窗口宽度划分紧凑、中等和扩展三档;窄屏保留单列,宽屏切换列表—详情双栏,并把颜色、图片等视觉差异放入资源覆盖,让一套工程在不同窗口保留同一任务路径而非同一像素布局。
“把宽度改成 100%”不是一多适配。用户在平板上需要的是更高信息密度和更短的操作路径,不是放大的手机卡片。
先分清结构差异与资源差异
| 差异 | 放在哪里 | 示例 |
|---|---|---|
| 单列改双栏 | ArkTS 断点分支 | 课程列表与详情并排 |
| 图标、颜色、尺寸 | qualifier 资源 | 宽屏插图、深色资源 |
| 是否支持能力 | SysCap 与服务降级 | 无相机设备隐藏拍摄入口 |
| 操作方式 | 统一动作入口 | 点击、回车都调用打开详情 |
资源适合让系统自动选择;布局结构必须由页面依据窗口空间决定。把两者混用会导致目录里塞业务逻辑,代码里又硬编码图片差异。
用窗口宽度得到稳定的 size class
exporttypeWindowSizeClass='compact'|'medium'|'expanded'exportfunctionresolveSizeClass(widthVp:number):WindowSizeClass{if(widthVp<600)return'compact'if(widthVp<840)return'medium'return'expanded'}阈值是产品决策,不是魔法数字散落点。统一函数让所有页面对“宽屏”的理解一致,后续可按设计规范调整。
监听窗口变化,不只在首次进入判断
旋转、折叠和自由窗口拖拽都会改变可用宽度。页面应在窗口尺寸变化后刷新 size class,并保留当前选中项。
privateupdateLayout(widthVp:number):void{this.sizeClass=resolveSizeClass(widthVp)if(this.sizeClass==='compact'){this.selectedCourseId=undefined}}这里改变的是布局状态,不改变课程数据。用户从双栏缩到单列时,详情转为单独打开;从单列展开时,可把已选项放到右栏,任务不应丢失。
宽屏切换信息结构
@BuilderprivateCourseContent(){if(this.sizeClass==='expanded'){Row(){CourseList({onSelect:id=>this.selectedCourseId=id}).layoutWeight(4)CourseDetail({courseId:this.selectedCourseId}).layoutWeight(6)}}else{CourseList({onSelect:id=>this.openCourse(id)})}}expanded不是把一列拉得更宽,而是提供“浏览列表同时查看详情”的新结构。中等宽度是否双栏要由内容密度决定;不要为了填满屏幕强行拆栏。
资源覆盖只保留真正不同的资产
共享资源放resources/base;只在差异明显时添加 qualifier 目录。ArkTS 始终用$r引用,避免在页面里判断文件名。
resources/ base/media/home_empty_courses.png base/element/float.json dark/media/home_empty_courses.png颜色、插图、间距与文案适合资源覆盖;路由结构、列数、焦点策略则属于代码分支。这样深色模式和设备差异不必互相污染。
鼠标键盘与触摸调用同一业务动作
多端交互不该复制两套保存或打开逻辑。将动作收口,再由不同输入方式触发。
privateopenCourse(courseId:string):void{this.navPathStack.pushPathByName('CourseDetail',{courseId})}列表点击、键盘确认和鼠标双击都应调用openCourse。额外关注焦点可见性、可访问名称和触控目标,不要只在触屏设备上验证。
不要用一套布局硬扛所有设备
| 场景 | 建议 |
|---|---|
| 手机、折叠屏、平板且任务相近 | 同一 HAP + 响应式布局 |
| 设备能力不同但主流程相近 | 条件能力与降级入口 |
| 手表、车机等交互完全不同 | 评估独立产品层或 Entry HAP |
| 宽屏只是视觉差异 | 资源覆盖即可 |
一次开发多端部署的目标是任务连续和能力兼容,不是用一个页面强行覆盖所有屏幕形态。
验证清单
- 手机竖屏:单列、核心动作完整。
- 平板横屏:列表和详情不重叠,文本行宽合理。
- 拖动自由窗口穿越断点:结构变化但选中状态不丢失。
- 深色模式:资源、文字和图标对比度均可读。
- 键盘与鼠标:焦点可见、回车能完成主操作。
rg"resolveSizeClass|widthVp|resources/base|selectedCourseId"entry features common小结
适配的第一步是按窗口空间重组信息,而非缩放手机组件。断点负责结构,资源覆盖负责视觉差异,统一动作负责多输入路径。三者各守边界,平板页面才不会“被拉扁”。
内容宽度仍要有上限
双栏并不意味着每个区域都无限拉宽。阅读类详情尤其要限制正文行宽,让横屏平板上的段落仍易扫读;列表区域则可利用额外宽度显示进度、更新时间等辅助信息。
Text(this.courseDetail.introduction).constraintSize({maxWidth:720}).lineHeight(24).maxLines(20).textOverflow({overflow:TextOverflow.Ellipsis})宽屏不是“更多空白”的理由。先把核心内容放在舒服的阅读宽度内,再将额外空间用于上下文、预览或操作区,信息密度才真正提升。
折叠与旋转时先保住任务连续性
布局切换不该重置筛选条件、滚动位置或正在填写的内容。对于详情页,可把当前课程 ID 作为页面状态;对于复杂表单,应在切换前保留草稿,在新布局中继续复用它。
| 状态 | 紧凑到扩展 | 扩展到紧凑 |
|---|---|---|
| 当前选中项 | 在右栏打开详情 | 变成详情页路由参数 |
| 列表筛选 | 原样保留 | 原样保留 |
| 编辑草稿 | 继续在表单区域编辑 | 保存草稿后切回单页 |
| 焦点 | 移至等价控件 | 保证主操作仍可聚焦 |
这条规则能避免“旋转一次就像重新进了应用”的割裂体验。
先用最窄和最宽窗口验证边界
测试不要只选一台平板。至少覆盖窄手机、恰好跨过断点的窗口、最大平板横屏以及自由窗口缩放。重点看文字截断、右栏空状态、按钮触控范围和横竖屏切换后的返回路径。
当发现某种设备的任务路径已完全不同,例如手表的极短交互或车机的远距操作,应停止继续堆叠if,评估独立的产品层入口。一个页面不必承担所有设备形态。
| 验证窗口 | 重点观察 | 失败信号 |
|---|---|---|
| 360vp 左右 | 单列是否可点击、底部操作是否遮挡 | 文字截断、按钮被安全区覆盖 |
| 600vp 临界值 | 结构切换是否跳动 | 同一内容重复或选中项丢失 |
| 840vp 临界值 | 双栏比例与空详情 | 右栏空白没有引导 |
| 最大横屏 | 内容行宽、浮层位置与鼠标焦点 | 卡片无限拉宽、焦点不可见 |
测试记录应写清实际窗口宽度和方向。只写“平板已测”无法帮助下一次改断点时判断哪个场景回归。
能力差异也必须先降级再展示
平板、折叠屏和手机的传感器、相机形态不完全相同。页面在展示依赖某项能力的入口前,应先由服务层确认可用性;不可用时隐藏或改为替代路径,而不是点击后才出现崩溃。布局断点解决空间问题,能力检查解决设备差异,两者不可互相代替。
例如拍照入口在不支持目标相机模式时可保留相册选择,课程下载在空间不足时可展示离线提示。降级仍要让用户理解原因和下一步,不能只是禁用一个没有解释的按钮。
保持视觉 token,而非复制一份宽屏样式
宽屏资源覆盖不等于重写颜色体系。文字颜色、圆角、间距和阴影应来自同一组语义 token;仅当信息密度改变时覆盖尺寸值。这样新增深色模式或品牌调整时,不会出现手机、平板两套无关的视觉规则。
当一个宽屏页面需要大量特殊 token,往往意味着它已经是新的产品体验,应重新审视是否要拆产品层,而不是继续在资源目录里堆例外。
| token 类型 | base 策略 | 宽屏覆盖条件 |
|---|---|---|
| 文字颜色 | 所有设备共用语义色 | 对比度确有差异 |
| 圆角与阴影 | 保持组件家族一致 | 不因屏幕变宽任意改变 |
| 间距与列间距 | 使用设计 token | 信息密度改变时调整 |
| 图片尺寸 | 提供基础比例 | 宽屏需要不同构图时覆盖 |
资源策略可让视觉保持一致,而结构策略保证任务效率。二者一起验证,才能避免仅在某个分辨率“看起来刚好”。
最后,断点值必须跟随真实内容复审。课程标题、国际化文本、动态卡片数量变化后,原来的 600vp 或 840vp 可能不再合适。以临界窗口的真实内容截图复核,比只对照静态设计稿更能发现拥挤与留白问题。
不要把“支持平板”定义成不崩溃。验收应包括:用户能否一眼找到主列表、详情是否能在不跳页的情况下阅读、长标题是否保住关键信息、输入焦点是否在缩放后仍清晰、底部操作是否始终可达。每一项都对应具体任务完成度,而不是抽象的屏幕尺寸。若设计与实现对某个极端宽度没有共识,先确定该宽度的内容优先级,再决定隐藏、折叠还是增加侧栏;不要用压缩字体来掩盖信息架构问题。
把这些结果保留为截图和窗口尺寸记录,下一次调整组件时才能做回归对照。
这也是跨设备体验持续稳定的基础。