【听见课堂 HarmonyOS NEXT 实战系列 30】同一套实时课堂,如何同时适配手机沉浸页和 2in1 工作区
【听见课堂 HarmonyOS NEXT 实战系列 30】同一套实时课堂,如何同时适配手机沉浸页和 2in1 工作区
多设备适配最危险的做法,是给手机和大屏复制两份完整页面,然后分别维护状态、权限和业务逻辑。短期看起来容易,后续很快会出现手机修了保存门禁、大屏仍显示假成功;大屏增加权限恢复,手机却没有入口。
听见课堂让实时课堂共享 LiveTranscriptionService、liveCaptions、Scroller 与控制动作,只在 ArkUI Builder 层拆分 liveClassCompactPage() 和 liveClassLargePage()。本文结合 840vp 断点、手机沉浸路由、大屏侧栏外壳与实时字幕组件,说明“一套业务,两种工作区”的实现边界。

一、先确定什么必须共享
手机和 2in1 形态都需要同一组事实:
- 当前课程、字幕数组、计时与运行新增计数;
- 麦克风权限与 8 状态会话机;
- 暂停、继续、结束和保存门禁;
- “没听清”、重点、拍照和手语入口;
- 自动滚动开关与“回到最新”;
- 深色、高对比和字幕字号偏好。
这些属于业务与交互契约,不应因为窗口变宽就复制一份。
二、真正变化的是空间组织
手机实时课堂强调沉浸、单列和底部拇指操作;大屏工作区可以同时展示字幕与板书证据,并把导航常驻在侧边。
因此适配目标不是“把所有组件按比例放大”,而是重新分配信息密度:手机一次突出一个任务,大屏让字幕阅读、课堂状态和证据管理并行可见。
三、断点来自真实窗口宽度
项目在根布局监听面积变化:
.onAreaChange((oldValue, newValue) => {
const width = Number(newValue.width);
this.isLarge = width >= AppSizes.LARGE_BREAKPOINT;
})
主题层把断点集中为:
static readonly LARGE_BREAKPOINT: number = 840;
这里判断的是当前可用窗口宽度,不是设备型号。2in1 分屏后可能回落到紧凑布局,手机横屏也不应仅凭“横屏”自动获得大屏工作区。
四、根外壳先决定导航形态
build() 中,大屏使用 Row:左侧 sideNavigation(),右侧是顶部栏和可滚动内容;普通手机使用 Column:顶部栏、内容区和底部导航。
if (this.isLarge) {
Row() {
this.sideNavigation();
// topBar + content
}
} else {
Column() {
// topBar + content
this.bottomNavigation();
}
}
路由 key 没有改变,改变的是承载路由的导航外壳。
五、实时课堂在手机上采用沉浸分支
实时课堂属于 isImmersivePhonePage(),手机不会再套常规顶部栏和底部导航,而是直接渲染 liveClassPage()。这样能把有限高度留给字幕和操作区,也避免系统导航与课堂控制争夺空间。
页面自己的返回按钮会调用 handleLiveBack();监听中、暂停中或启动中不会直接离开,而是先打开结束确认。沉浸不是隐藏所有导航,而是让返回行为与实时资源生命周期一致。
六、liveClassPage 只做布局分派
中间层非常简单:
private liveClassPage() {
if (this.isLarge) {
this.liveClassLargePage();
} else {
this.liveClassCompactPage();
}
}
它不重新获取数据,也不创建第二个 Service。窗口跨过断点时,Builder 变化,但 @Local 状态和 Service 实例仍是同一套。
七、大屏工作区为什么使用双栏
liveClassLargePage() 把主体拆成两个区域:左侧实时转写列表占更大权重,右侧证据与课堂状态面板展示板书数量、最近证据、结束确认和拍照入口。
Row({ space: 14 }) {
Column() { /* 实时转写 */ }.layoutWeight(64)
this.liveEvidenceLargePanel() // layoutWeight(36)
}
64:36 不是简单美术比例,而是任务优先级:字幕持续变化,需要主要阅读空间;证据面板支持辅助操作,但不能挤压正文。
八、手机为什么保持单列
liveClassCompactPage() 按顺序组织标题、状态、计时、反馈、滚动控制、字幕列表、结束确认、板书入口和底部控制区。字幕列表使用 layoutWeight(1) 占据剩余高度。
手机不强行并排板书面板,而是用“已关联 N 张板书”入口跳转。这样在窄屏和大字号下仍能保住核心字幕宽度,也避免五个底部按钮被进一步压缩。

九、共享组件防止行为漂移
两端都复用:
liveCaptionRow(item):字幕、不确定、重点和当前行样式;liveCaptionScrollControls():自动滚动与回到最新;liveControlButton():开始/暂停、没听清、重点、拍照、手语;toggleLiveCapture()、confirmEndClass():资源与保存动作。
布局 Builder 可以不同,核心交互 Builder 和方法尽量共享。这样一个保存门禁修复可以同时作用于两端。
十、共享 Scroller 需要关注断点切换
手机和大屏列表都绑定 liveCaptionScroller。这有利于统一“回到最新”,但跨断点重建列表时,旧位置能否稳定保留必须实测。
项目大纲要求做 1100vp→835vp→1100vp 往返测试,正是为了发现 Builder 重建后位置、焦点、选中态或自动跟随丢失。代码共享并不能替代动态窗口验证。
十一、尺寸适配不能只放大字体
实时字幕基准字号根据 isLarge 选择 22 或 18,再乘用户 captionFontScale;卡片最小高度、内边距、圆角和控制按钮高度也会随布局变化。
大屏的目标是增加阅读距离和信息密度,不是让所有元素等比例膨胀。侧栏、双栏权重、证据面板和行高必须一起调整,才能形成真正的工作区。
十二、五个底部动作保持相同顺序
手机和大屏都按“开始/暂停、没听清、重点、拍照、手语”排列。位置一致能降低用户换设备或窗口形态时的重新学习成本。
按钮仍需满足项目统一的 48vp 触达基线,并提供可理解的无障碍文本。大屏支持鼠标与键盘后,还要验证焦点顺序和 Enter 激活,而不只是触控点击。
十三、适配过程中不能复制权限逻辑
权限申请与恢复都在 toggleLiveCapture()、recoverLiveMicrophonePermission() 和 Service 中完成。两个布局只调用这些动作,不直接访问 AtManager。
如果大屏 Builder 自己写一套权限分支,未来系统 API 变化或错误文案调整就需要维护两份。能力治理应留在 Service,页面只显示状态与入口。
十四、840vp 断点也有局限
当前项目使用单一断点把界面分为 compact/large,足以形成清晰两态,但不代表所有窗口都得到最佳布局。841vp 与 1400vp 同属大屏分支,右栏最小宽度、长课程名、系统大字号和窗口高度仍可能带来不同压力。
后续可在不改变路由和业务状态的前提下,引入内容最大宽度、面板最小宽度或高度策略;不能为了追求多个断点复制更多业务页面。
十五、真正的多设备验收矩阵
至少要验证:
| 场景 | 重点检查 |
|---|---|
| 手机竖屏 | 沉浸页、字幕高度、底部五按钮、安全区 |
| 手机横屏 | 长文本、控制区遮挡、返回与结束确认 |
| 2in1 全屏 | 侧栏、64:36 双栏、键鼠焦点、滚动 |
| 1100→835vp | 切换为紧凑布局,状态与字幕不丢失 |
| 835→1100vp | 恢复大屏工作区,列表和控制仍可用 |
| 深色+大字号 | 两端可读、按钮不截断、证据面板可滚动 |
截图可以证明某一瞬间的外观,不能证明往返切换、焦点和滚动恢复。
十六、项目证据与未验证项
当前源码已经实现 840vp 窗口断点、手机沉浸分支、大屏侧栏外壳、实时课堂两套布局和共享 Service/状态/控件。真实 2in1 键鼠焦点、窗口自由缩放、断点往返中的滚动位置,以及物理设备安全区仍需专项验证。
本文把“代码存在的响应式结构”与“已通过真机多设备验收”分开描述,不用单张截图证明所有设备都已适配。
十七、总结
同一套实时课堂适配手机与 2in1,关键不是复制页面,而是划清共享与变化:状态、能力、保存门禁和操作语义共享;导航外壳、信息密度和空间布局随真实窗口宽度变化。听见课堂用两套 Builder 承担布局差异,用同一 Service 和状态流保持行为一致。
下一篇进入新的能力链:从 CameraPicker 拍照开始,拆解权限、相机调用、resultUri 与 OCR 页面之间的可恢复流程。
参考:项目当前 Index.ets、AppTheme.ets、LiveTranscriptionService.ets 与集中路由实现;多设备行为最终以目标 HarmonyOS 设备和动态窗口实测为准。
更多推荐

所有评论(0)