fix(harmony): ★★ 顶部文案用 windowDecor 判 2in1 ⇒ 平板上浮在系统状态栏上(真机实测)
用户:「不是没显示,而是顶部与三键和状态栏重合,我觉得只应该在 2in1」。
## 根因:一个**假信号**
顶部那行文案(一言 + 签名,`TopbarStore`)的渲染条件写的是
if (this.topbarTexts().length > 0 && this.windowInsets.windowDecor > 0)
本意"有装饰带才显示",在模拟器(真 2in1)上一直成立。**真机平板把它证伪了**:
实测 insets: statusBar=38.588235 navIndicator=27.764706 windowDecor=37
param get const.product.devicetype = tablet
`getWindowDecorHeight()` 在平板上**照样返回 37vp** —— 官方给的是"全屏悬浮态
固定 37vp"这个下限值,它衡量的是"系统浮层厚度",**不是"有没有三键区"**。
平板没有三键区,但 windowDecor 恒为 37 ⇒ 条件成立 ⇒ 文案渲染出来,
位置又按"三键在右边"算(`.height(this.windowInsets.windowDecor)`),
于是整行浮在**系统状态栏**上,与时钟/电量重叠。
## 改法
条件换成形态真值:
if (this.topbarTexts().length > 0 && deviceInfo.deviceType === '2in1')
`deviceInfo` 取自 `@kit.BasicServicesKit`,与 `EntryAbility.ets:310` 判 2in1
用的是同一个来源 —— 形态判据全仓只此一处口径,不让两处各判一套。
`.height(this.windowInsets.windowDecor)` 保留不动:2in1 上它是对的,
非 2in1 上整块不渲染、根本走不到(`harmony-2in1` 那条仍钉着它)。
## 判据
`harmony-2in1.test.mjs` 新增一条:顶部文案必须挂在 `deviceType === '2in1'` 上,
且**不许再出现 `windowInsets.windowDecor` 与 0 的比较**(那是假信号)。
红绿已验:退回 `windowDecor > 0` ⇒ 红;恢复 ⇒ 绿。
★ 这条判据第一版也犯了同类错:用 `prose`(含注释)会把**我自己写进注释里的**
旧写法 `windowDecor > 0` 判红。改用 `lib/read.mjs` 的 `code()`(读时剥注释)。
与上一条(`harmony-window` 判据 10)同形——同一天犯两次,已成惯例性陷阱。
## 环境
`devecocli` 的 npm 包在本会话中途被卸载(`/usr/bin/devecocli` 成断链),
hvigor 直跑缺它注入的 SDK 环境 ⇒ 三个 SDK 路径都报 "SDK component missing"。
已 `npm i -g @deveco/deveco-cli` 装回(6s,252 包),`devecocli build` 恢复可用。
## 真机验证
装 `entry-default-signed.hap`(26.0.0 Beta2,debug 签名)后截图:
顶部只剩系统状态栏(18:34 / 浏览器 / 信号 / 电量),其下是干净的壁纸带,
再下方才是页签条「收件箱 20 / 发件箱 / 授权1」—— 重叠消失。
## 回归
`run-all.mjs`:files=35 checks=584 pass=580 fail=2 skip=2 red=4。
与本改动前的基线(checks=583 fail=2 red=3)比,**fail/red 未增加**:
那 2 个 fail 是设备判据并行争用(单独跑全绿),3 个 red 是「静态判据到期」
的既有债务(5 个文件在真机出现后被判到期,本轮未处理)。
This commit is contained in:
@ -785,3 +785,43 @@ test('2in1|一言与签名要在客户端缓存(账号级),离线也能
|
||||
assert.match(STORE, /'\/me\/topbar'/,
|
||||
'要打服务端那个端点(/me/topbar)');
|
||||
});
|
||||
|
||||
/*
|
||||
* ★★ 2026-10-01 真机实测抓到的假判据(MatePad Pro / MRDI-W00,HarmonyOS NEXT API 26)。
|
||||
*
|
||||
* 顶部那行文案(一言 + 签名,`TopbarStore`)的渲染条件原来写的是
|
||||
* `this.windowInsets.windowDecor > 0`
|
||||
* 本意"有装饰带才显示",在模拟器(真 2in1)上一直成立。
|
||||
*
|
||||
* ★ 真机平板把它证伪了 —— 实测日志:
|
||||
* `insets: statusBar=38.588235 navIndicator=27.764706 windowDecor=37`
|
||||
* `param get const.product.devicetype` = **tablet**
|
||||
*
|
||||
* `getWindowDecorHeight()` 在平板上**照样返回 37vp**(官方给的是"全屏悬浮态
|
||||
* 固定 37vp"这个下限值),但平板**根本没有三键区** ⇒ 条件成立、文案渲染,
|
||||
* 位置却按"三键在右边"算,于是浮在**系统状态栏**上(用户:与时钟/电量重叠)。
|
||||
*
|
||||
* ⇒ `windowDecor > 0` 在平板上是个**恒为真的假信号**,不能当形态判据用。
|
||||
* 形态的真值是 `deviceInfo.deviceType === '2in1'`。
|
||||
*
|
||||
* 本条钉的就是这个:**不许再用 windowDecor 的高度/正负当"是不是 2in1"。**
|
||||
*/
|
||||
test('★★ 形态判据必须用 deviceInfo.deviceType,不许拿 windowDecor 当 2in1 的信号', () => {
|
||||
// ★ 用 `code()`(读时剥注释)而不是 `prose`:判据的锚要落在**代码**上,
|
||||
// 不是落在代码对自己的描述上 —— 否则我写进注释里的旧写法会被自己判红。
|
||||
const code_ = code(join(HERE, '..', '..', 'harmony', 'entry', 'src', 'main', 'ets', 'pages', 'MainPage.ets'));
|
||||
|
||||
// 那行文案必须挂在 2in1 判据上。
|
||||
const guard = /if \(this\.topbarTexts\(\)\.length > 0 && deviceInfo\.deviceType === '2in1'\)/.test(code_);
|
||||
assert.ok(guard,
|
||||
'顶部文案必须只在 2in1 出现:`if (topbarTexts().length > 0 && deviceInfo.deviceType === \'2in1\')`\n' +
|
||||
'真机实测(MatePad Pro,API 26):windowDecor=37(**非 0**)但 devicetype=tablet,\n' +
|
||||
'旧条件 windowDecor > 0 在平板上恒成立 ⇒ 文案浮在系统状态栏上。');
|
||||
|
||||
// 反向:条件里不得再用 windowDecor 的正负/高度判形态。
|
||||
const bad = /windowInsets\.windowDecor\s*(>|!=|===|!==|==)\s*0/.exec(code_);
|
||||
assert.equal(bad, null,
|
||||
`别再用 ${bad ? bad[0] : 'windowDecor 与 0 比较'} 判「是不是 2in1」——\n` +
|
||||
'真机平板上它恒为 37(官方"全屏悬浮态固定值"),不代表有三键区。\n' +
|
||||
'用 deviceInfo.deviceType === \'2in1\'(与 EntryAbility 同一来源)。');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user