项目进展2026-09-24

MD 阅读 Android 版 · 系统栏切换与鸿蒙侧同步回归

Android 版补齐菜单第 3 项「隐藏系统栏 / 显示系统栏」(只切系统栏可见性、不切布局模式),真机量化验收位移精确等于状态栏高度;鸿蒙侧同步后完成编译与解包取证,并新增本地无头工具验证图形高度算法(9/9 贴合)。

日期:2026-09-24 版本:1.1.4(versionCode 1001004) 真机:Mate 30 Pro(LIO-AN00 / Android 12 / 1176×2400)


一、本轮两项交付

#事项状态
1菜单补「隐藏系统栏 / 显示系统栏」(对齐鸿蒙菜单第 3 项)✅ 实现并真机验收
2鸿蒙侧 graph.html 同步后的图形高度与全屏回归⚠️ 编译 + 解包 + 算法层已验证;真机回归未做(设备不在线)

二、菜单「隐藏系统栏 / 显示系统栏」

2.1 实现口径

对齐鸿蒙 toggleFullScreen() → win.setWindowSystemBarEnable([]):

val controller = WindowCompat.getInsetsController(win, view)
controller.systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
controller.hide(WindowInsetsCompat.Type.systemBars())   // 或 .show(...)

只切系统栏可见性,不切布局模式 —— 沉浸式布局始终不变。这一条很关键: 鸿蒙上早先的「双倍留白」正是来自「切布局模式 + 切系统栏」两个动作叠加,本次刻意避开。

菜单位置与鸿蒙逐项对齐(第 3 项):

源码/预览 → 【隐藏系统栏 / 显示系统栏】 → 打开文件 → 分享 Markdown → 语音朗读 → ─── → 设置 → 关于

2.2 真机验收(量化)

标题栏文本 demo.md 的 top 坐标(UI dump 实测):

状态标题栏 top菜单第 3 项文案
初始(系统栏可见)147隐藏系统栏
点「隐藏系统栏」后48显示系统栏
点「显示系统栏」后147隐藏系统栏
  • 位移 99px = 状态栏 33dp × 3.0(density) —— 精确等于状态栏高度,无多补、无少补、无双倍留白。
  • 反向切换精确回到 147,往返三次一致(147 → 48 → 147 → 48)。
  • 视觉:状态栏与底部导航条同时消失,标题栏顶到屏幕最上沿,内容铺满全屏。

2.3 边界用例

用例结果
隐藏态下切后台再回前台系统栏保持隐藏(EMUI 未擅自恢复),菜单文案与真实状态一致 ✅
隐藏态下打开图形全屏层全屏层蓝栏同步上移(top 147 → 48),图形仍居中 ✅
隐藏态下打开朗读面板面板正确贴底,无多余留白 ✅
全屏层 + 返回键被全屏层正确接住,未穿透到 Activity ✅
崩溃检查logcat crash buffer 为空 ✅

2.4 一处平台差异(已查清,非缺陷)

隐藏系统栏前后,朗读面板的 bounds 完全没变。用 dumpsys 查清原因:

显示态:ITYPE_STATUS_BAR frame=[0,0][1176,99] visible=true
        ITYPE_NAVIGATION_BAR frame=[0,0][0,0] visible=false
隐藏态:ITYPE_STATUS_BAR frame=[0,0][1176,99] visible=false
        ITYPE_NAVIGATION_BAR frame=[0,0][0,0] visible=false

本机(EMUI 12 / 手势导航)导航条 insets 恒为 0,所以面板底部避让本来就与系统栏显隐无关, 面板位置不变是正确行为。

这与鸿蒙「隐藏系统栏后避让区归零」最终效果一致(都是 0),只是到达路径不同: 鸿蒙是「有 → 归零」,Android 本机是「一直是 0」。三键导航 ROM 上是否归零需另测。


三、鸿蒙侧 graph.html 同步后的回归

⚠️ 前提说明:本轮鸿蒙测试机未接入(hdc list targets 为空;USB 上只有 Mate 30 Pro-Android 机)。 真机回归无法执行。以下是设备缺失下能做到的全部验证,不要当作真机通过。

3.1 编译验证 ✅

hvigorw assembleHap -p product=device -p buildMode=debug --no-daemon
→ BUILD SUCCESSFUL in 2 min 48 s
产物:entry/build/device/outputs/default/entry-default-signed.hap

3.2 解包取证 ✅(确认打进包里的就是新版)

从 HAP 里解出 resources/rawfile/graph.html(33,344 字节)与 Android 版逐行 diff:

  • 与 Android 版仅剩 htmlLabels 一处差异(鸿蒙 true 保留 HTML 富文本标签 / Android false 规避 foreignObject 不光栅化),加上各自的说明注释 —— 完全符合预期。
  • 新版特征命中:fitViewBoxToContent / contentBox 共 6 处。
  • 高度上报通道完好:ArkTSBridge.updateHeight(h) 仍在。
  • 鸿蒙调用侧接口(renderGraph(code, true) / renderSvg(code, true) / 轮询 getInlineHeight())与页面导出签名完全对齐。

3.3 高度算法本地验证 ✅(新增工具,见第四节)

用本地 Chrome 渲染同一份鸿蒙版 graph.html,逐个图形比对「上报高」与「图形实际需要的高」:

视口结果最大差值平均差值
400px(模拟真机 CSS 宽)9/9 PASS0.88px0.44px
320px(强制宽图缩放,覆盖另一分支)9/9 PASS1.00px0.56px
(对照)Android 版 @ 392px9/9 PASS0.84px0.48px

老板报过的两个问题点,现在是这个数:

  • 7.5 状态图:图形实际高 348.0,上报 364.0 → 差值 +0.02px,完整不裁 ✅
  • 7.8 时间线:图形实际高 204.1,上报 221.0 → 差值 +0.88px,无大块留白 ✅

3.4 仍然必须真机做的部分 ❌

  1. mermaid 在 ArkWeb 里的绝对渲染尺寸与字体度量(桌面 Chrome ≠ ArkWeb)
  2. 手势:双指缩放、双击放大、拖动平移
  3. 全屏层的几何与返回键行为
  4. 真机上的内联高度观感(数值贴合 ≠ 看起来舒服)

→ 需要老板把鸿蒙测试机接上 USB,我再跑一轮(约 10 分钟,走 harmonyos-device-verify 流程)。


四、新增工具 _tools/graph-height/

C:/bzm/harmony/_tools/graph-height/verify.mjs(零 npm 依赖,Node 22 内置 WebSocket 驱动 CDP)

它验的:getInlineHeight() 的上报值是否等于图形真正需要的高度。 为什么本地能验:该公式与浏览器 max-width:100% + height:auto 是数学等价的,只依赖 viewBox 与容器宽,与平台无关。 分工:本地验「算法自洽」,真机验「ArkWeb 实际渲染 + 交互」。本工具 FAIL 则真机必有问题,可省一轮装机。

灵敏度自检(证明它不是「永远 PASS」的工具):往 #container svg 注入 min-height:260px 制造「高度不够」, 结果 9 个图形 FAIL 6 个,最大差值 −187px、符号为负(= 裁切),方向正确。

已知局限:桌面 Chrome 字体度量 ≠ ArkWeb,故「等价关系」可移植,但绝对像素高两端会有差异。


五、待办 / 待批示

#事项说明
A1鸿蒙真机回归(本轮未做)需接入鸿蒙测试机;跑图形高度观感 + 全屏手势
A2Android 工程纳入 git上轮已提,仍未批示;C:\bzm\android\mdreader-lite 至今无版本控制
A3鸿蒙工程积压提交git 根在 c:/bzm/harmony/,当前 13 个已跟踪文件改动未提交(含本轮同步的 graph.html / MermaidView.ets / SvgView.ets),最近提交还停在 1.0.4 时代。建议尽快提交一次,否则回滚无锚点
← 返回文章列表