跨端: 壁纸遮盖色改用页面底色系(mask 两套主题都深,浅色下方向与 WebUI 相反);模态遮罩保持 mask
pi 提了一个**方向性**疑问,让我先把值读出来再定 —— 读完确认**他是对的**,而且这是"机制上确定不同"。
## 实测(两张 SDK 表交叉验证,不靠记忆)
`ets/build-tools/ets-loader/sysResource.js` 给名字→id,`previewer/.../resources.txt` 给 id→值:
| 令牌 | 浅色主题 | 深色主题 |
|---|---|---|
| `ohos_id_color_mask_regular`(原 `Theme.overlay`) | `#99182431` **深蓝灰** | `#b2000000` 黑 |
| `ohos_id_color_background` | `#ffffffff` **白** | `#ff18181a` 近黑 |
⇒ mask 的 light/regular/thick 是**浓度档**(同一深色的三个 alpha),不是深浅两套值:
它在**两套主题下都是深色**(模态遮罩语义)。而 WebUI 的 `--bg-scrim` 浅色是**白**
(原话「浅色下用白把花哨的图案洗淡」)—— 壁纸遮盖用 mask 就是**反方向**:
浅色主题下把预设压暗,而 WebUI 是把它洗淡。
## 改法
- 新增 `Theme.wallpaperScrim = $r('sys.color.ohos_id_color_background')`(页面底色系:
浅色白、深色近黑,**自动换向**,与"朝底色淡化"同一意图);预设档与图片档的遮盖层都用它。
- `Theme.overlay`(mask)**只留给模态弹层**(那里语义确实是压暗背后)。
- 不复用 `pageBg` 的原因写进注释:页面底在背景开启时会被换成**透明**
(`bgActive ? Color.Transparent : Theme.pageBg`),而遮盖层**永远要一个真实颜色** ——
两个用途生命周期不同,共用一个名字迟早坏一头(这个仓库撞过四次的模式)。
## 判据(从 SDK 读真值再判,不写死结论)
断言「mask 两套主题都深」「页面底色系浅白深黑」「WebUI 的 `--bg-scrim` 浅色是白」,
再落到代码:两处遮盖层必须用 `wallpaperScrim`、弹层仍用 `overlay`、两个令牌不许混用。
**这样"令牌选错方向"以后不能靠记性避免。**
变异:遮盖退回 mask → 红 1 条;只改一层 → 红 2 条。
## 文档
§7.17b-2 记这次读数(表格 + 两张表怎么读 + 为什么不复用 pageBg + 变异结果);
§7.12 有意差异表加一行(遮盖色令牌:两个语义两个令牌,"不允许混用")。
## 验证
`hvigorw assembleHap` BUILD SUCCESSFUL;`npm test` 退出码 0
(12 个判据文件全绿 + vitest 258/258;harmony-appearance 23 → 24 条)。
This commit is contained in:
@ -380,7 +380,12 @@ test('★ 页面真的把背景画出来了(这一条是补漏:P4 第一版
|
||||
assert.match(main, /Image\(this\.wallpaperImage\)/, '图片档要真的把图渲染出来');
|
||||
assert.match(main, /\.objectFit\(ImageFit\.Cover\)/, '图片要铺满(不是拉伸变形或留白)');
|
||||
// 压暗用系统遮罩色 + 服务端浓度
|
||||
assert.match(main, /\.backgroundColor\(Theme\.overlay\)[\s\S]{0,80}?\.opacity\(this\.bgPlan\.scrim\)/, '压暗层要用系统遮罩色与算出来的浓度');
|
||||
/*
|
||||
* 遮盖层:用**页面底色系**的 `Theme.wallpaperScrim`(不是模态遮罩 mask)——
|
||||
* 浅色主题下 mask 是深色(#99182431),会把预设压暗,而 WebUI 是把预设洗淡(--bg-scrim 是白)。
|
||||
* 这一条与下面那条"遮盖色方向"是同一件事的两个面:这里钉"层在不在、浓度接没接上"。
|
||||
*/
|
||||
assert.match(main, /\.backgroundColor\(Theme\.wallpaperScrim\)[\s\S]{0,80}?\.opacity\(this\.bgPlan\.scrim\)/, '遮盖层要用页面底色系令牌与算出来的浓度');
|
||||
// 背景在主界面这一层:Tabs 之上不该再有不透明的底色把背景盖死
|
||||
assert.match(main, /Stack\(\) \{[\s\S]{0,120}?this\.WallpaperLayer\(\)/, '背景要铺在内容之下(Stack 的底层)');
|
||||
});
|
||||
@ -585,7 +590,7 @@ test('★ 预设档的遮盖:两档同一个浓度(WebUI 的 --bg-dim 不区
|
||||
assert.match(bgStore, /--bg-dim|setProperty\('--bg-dim'/, 'WebUI 要无条件写 --bg-dim(这是"两档都压"的依据)');
|
||||
const main = read('pages/MainPage.ets');
|
||||
// 两档各有一处遮盖层(都用系统遮罩色 + 算出来的浓度)
|
||||
const scrims = [...main.matchAll(/\.backgroundColor\(Theme\.overlay\)\s*\n\s*\.opacity\(this\.bgPlan\.scrim\)/g)];
|
||||
const scrims = [...main.matchAll(/\.backgroundColor\(Theme\.wallpaperScrim\)\s*\n\s*\.opacity\(this\.bgPlan\.scrim\)/g)];
|
||||
assert.ok(scrims.length >= 2, `预设档与图片档各要有一层遮盖(实际 ${scrims.length} 处)`);
|
||||
});
|
||||
|
||||
@ -647,3 +652,89 @@ test('★ 主题变化时**我们自己算的值**要跟着重算(pi 的规则
|
||||
const sdk = readFileSync(join(CLT, 'sdk/default/openharmony/ets/api/@ohos.app.ability.EnvironmentCallback.d.ts'), 'utf8');
|
||||
assert.match(sdk, /onConfigurationUpdated\(config: Configuration\): void/, 'SDK 里回调是 onConfigurationUpdated(别写错名字)');
|
||||
});
|
||||
|
||||
// ───────── 遮盖色方向:从 SDK 两张表读出真值再判(pi 2026-09-14 的方向性疑问) ─────────
|
||||
|
||||
/** 从 SDK 读出 `sys.color.ohos_id_color_*` 的真实值(名字→id 取编译器那张表,id→值取预览器那张) */
|
||||
function sdkSystemColors() {
|
||||
const sysRes = readFileSync(join(CLT, 'sdk/default/openharmony/ets/build-tools/ets-loader/sysResource.js'), 'utf8');
|
||||
const resTxt = readFileSync(join(CLT, 'sdk/default/openharmony/previewer/common/resources/entry/resources.txt'), 'utf8');
|
||||
const name2id = new Map();
|
||||
for (const m of sysRes.matchAll(/'?(ohos_id_color_[a-z_]+)'?:\s*(\d+)/g)) {
|
||||
if (!name2id.has(m[1])) name2id.set(m[1], Number(m[2]));
|
||||
}
|
||||
const id2val = new Map();
|
||||
for (const m of resTxt.matchAll(/id:(\d+),\s*'([^']*)'/g)) {
|
||||
const id = Number(m[1]);
|
||||
if (!id2val.has(id)) id2val.set(id, m[2]);
|
||||
}
|
||||
const out = {};
|
||||
for (const [name, id] of name2id) if (id2val.has(id)) out[name] = id2val.get(id);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** '#AARRGGBB' → 亮度(0=黑 1=白);只用于判"深还是浅" */
|
||||
function luminanceOf(argb) {
|
||||
const r = parseInt(argb.slice(3, 5), 16) / 255;
|
||||
const g = parseInt(argb.slice(5, 7), 16) / 255;
|
||||
const b = parseInt(argb.slice(7, 9), 16) / 255;
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
}
|
||||
|
||||
test('★ 遮盖色方向:`mask_*` 两套主题下都是**深色**(模态遮罩),壁纸遮盖必须用**页面底色系**', () => {
|
||||
/*
|
||||
* pi 的疑问原话:「系统那三个 mask —— 名字里的 light/regular/thick 是**浓度档**
|
||||
* (同一个色的三个 alpha),不是深浅主题的两套值。它们的用途是**模态遮罩**(弹层背后压暗),
|
||||
* 所以两套主题下通常都是深色。如果预设/图片的遮盖层用 mask 色,**浅色主题下会把预设压暗,
|
||||
* 而 WebUI 是把预设洗淡**:方向相反,而且这是"机制上确定不同",不是观感。」
|
||||
*
|
||||
* 他让我先把值读出来再定 —— 这里就是那次读数,做成判据(免得以后凭记忆选令牌)。
|
||||
*/
|
||||
let colors;
|
||||
try {
|
||||
colors = sdkSystemColors();
|
||||
} catch (e) {
|
||||
assert.fail(`读不到 SDK 的系统色表(这条判据无从判起):${e.message}`);
|
||||
}
|
||||
const maskRegular = colors['ohos_id_color_mask_regular'];
|
||||
const maskDark = colors['ohos_id_color_mask_regular_dark'];
|
||||
const bg = colors['ohos_id_color_background'];
|
||||
const bgDark = colors['ohos_id_color_background_dark'];
|
||||
assert.ok(maskRegular && maskDark && bg && bgDark, '系统色表里这几个令牌都要有值');
|
||||
|
||||
// 事实一:mask 在浅色主题下也是深色(#99182431)—— 所以它是模态遮罩语义
|
||||
assert.ok(luminanceOf(maskRegular) < 0.2,
|
||||
`mask_regular 在浅色主题下应当是深色(实测 ${maskRegular})—— 若是浅色,这条判据的前提要重写`);
|
||||
assert.ok(luminanceOf(maskDark) < 0.2, `mask 深色主题下也应当是深色(实测 ${maskDark})`);
|
||||
|
||||
// 事实二:页面底色系随主题换向(浅色白、深色近黑)—— 这才是"朝底色淡化"
|
||||
assert.ok(luminanceOf(bg) > 0.8, `ohos_id_color_background 浅色主题下应当是白(实测 ${bg})`);
|
||||
assert.ok(luminanceOf(bgDark) < 0.2, `ohos_id_color_background_dark 应当近黑(实测 ${bgDark})`);
|
||||
|
||||
// 事实三:WebUI 的遮罩方向是"朝底色淡化"(浅色白、深色黑)—— 与页面底色系同向、与 mask 反向
|
||||
const webCss = readFileSync(join(ROOT, 'client/electron/src/index.css'), 'utf8');
|
||||
const scrimLight = /--bg-scrim:\s*(\d+)\s+(\d+)\s+(\d+);/.exec(webCss);
|
||||
assert.ok(scrimLight, 'CSS 里要有 --bg-scrim');
|
||||
assert.deepEqual([scrimLight[1], scrimLight[2], scrimLight[3]], ['255', '255', '255'],
|
||||
'WebUI 浅色下的遮罩是**白**(把图案洗淡);这是"必须用页面底色系"的依据');
|
||||
|
||||
// 结论落到代码:壁纸遮盖用页面底色系令牌,且**不是** mask
|
||||
const theme = readFileSync(join(HARMONY_ETS, 'common/Theme.ets'), 'utf8');
|
||||
assert.match(theme, /static readonly wallpaperScrim: Resource = \$r\('sys\.color\.ohos_id_color_background'\)/,
|
||||
'壁纸遮盖色要用页面底色系(ohos_id_color_background)');
|
||||
assert.match(theme, /static readonly overlay: Resource = \$r\('sys\.color\.ohos_id_color_mask_regular'\)/,
|
||||
'overlay(模态遮罩)保持 mask');
|
||||
const main = read('pages/MainPage.ets');
|
||||
const scrims = [...main.matchAll(/\.backgroundColor\(Theme\.(\w+)\)\s*\n\s*\.opacity\(this\.bgPlan\.scrim\)/g)];
|
||||
assert.equal(scrims.length, 2, '预设档与图片档各一层遮盖');
|
||||
for (const s of scrims) {
|
||||
assert.equal(s[1], 'wallpaperScrim',
|
||||
'壁纸遮盖层的颜色必须用 wallpaperScrim(页面底色系)。用 mask 会在浅色主题下把预设压暗,与 WebUI 反向');
|
||||
}
|
||||
// 两个语义不许共用一个令牌(这个仓库撞过四次的那个模式)
|
||||
assert.notEqual('wallpaperScrim', 'overlay');
|
||||
// 模态弹层仍然用 mask(那里的语义确实是"压暗背后")
|
||||
const settings = read('pages/SettingsPage.ets');
|
||||
assert.match(settings, /Theme\.overlay/, '自绘弹层的遮罩仍然用 mask(那里的语义是压暗背后)');
|
||||
assert.ok(!/wallpaperScrim/.test(settings), '弹层不该用壁纸遮盖色(两个语义别混)');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user