灶台菜谱设计手记 01|HarmonyOS 7.0 空间化:材料配置矩阵【鸿蒙心迹】

1. 前言
做番茄炖牛腩时,查菜谱通常是一连串很短的动作:打开列表,进入详情,确认牛腩和番茄的用量,再返回当前步骤。手机放在灶台旁,界面需要让人迅速分清哪里是内容,哪里可以操作。
“灶台菜谱”围绕这个过程组织页面。详情保留“备菜、烹饪、笔记”三个页签,使用本地菜谱和固定菜图,步骤由用户手动推进。我们希望材质帮助操作区域建立层次,同时让食材正文保持稳定的阅读背景。
把目标版本升级到API 26后,一个值得检查的场景是:打开“切换菜谱”菜单时,菜单可能已经采用新的材质;在正文食材卡片上设置类似属性,却看不到预期变化。如果将这两种呈现直接比较,很容易得出“卡片参数没有调对”的判断。
这个判断跳过了一步:两个位置是否遵守相同的生效规则?
菜单、标题栏中的组件和正文卡片并不是等价对象。“没有效果”只是现象,背后至少有三个不同的问题:没有开启、超出作用区域,以及材质被已有样式遮挡。继续增加模糊或调整颜色,未必能回答其中任何一个。
本文先把这三个问题拆开,再用同一控件的配置矩阵将它们联系起来。我们的假设是:在认定设备不支持之前,应该先排除配置、作用域和样式覆盖。

图1:三帧保持同一条菜谱和同一任务。菜单是观察差异的入口,食材卡片是正文内容,不能因为二者出现在同一屏幕,就认为它们应有相同的材质行为。
2. 方案
同一任务,两种做法
应用级开启适合建立整体基线。它集中声明应用的材质策略,让受支持组件按照相应规则呈现。组件级配置则把意图放到具体位置,适合表达局部选择,也便于定位差异。
| 比较项 | 方案A:应用级批量开启 | 方案B:局部显式配置 |
|---|---|---|
| 配置入口 | entry模块的metadata | 组件属性或专属接口 |
| 主要用途 | 观察整体默认呈现 | 控制与检查具体组件 |
| 需要核对 | 支持清单、原有样式 | 应用状态、组件位置 |
| 共同约束 | 遵守组件作用域 | 遵守组件作用域 |
两者可以共存。选择方案B时,应用级状态仍然存在;如果忽略它,“这段组件代码有效”便缺少一个必要前提。
我倾向于先明确记录应用的default状态,再检查局部配置。这样,每次差异都能对应到一个具体改动。等局部行为清楚后,再将enable和disable纳入对照。
为了检查位置,我们在独立的材质检查页中复用同一个Column背板,内部只放“番茄炖牛腩”文字。它分别进入Navigation或NavDestination标题栏、横向Tabs的底部TabBar,以及普通正文区域。三个副本保持尺寸、文字、背景素材与材质参数一致,并记录父容器的样式。
这里的“底部”有明确含义:横向Tabs,且barPosition为BarPosition.End。把一个Column通过布局推到屏幕下沿,不会自动让它成为TabBar的一部分。

图2:三位置对照以组件树为依据。相同的外观参数用于排除样式差异,区域名称用于说明生效条件;控件靠近屏幕边缘本身不是判据。
这个检查页不改变菜谱的信息结构。正式页面中的食材清单继续留在正文,三个页签继续承担原来的导航职责。将食材卡片搬进标题栏,虽然可能改变材质的适用条件,却同时破坏了原本的设计问题。
先判断材质在什么条件下呈现。文字是否清楚、触摸反馈是否合适,需要建立在这个判断之上。
3. 实现
让设计落到组件
先确认版本。开启沉浸光感指南要求应用的targetSDKVersion不低于26.0.0。目标SDK、构建所用SDK和运行系统应分别记录;系统名称不能替代工程配置。需要兼容更低版本时,还要按对应SDK的兼容性规则保护API调用。
应用开关写在entry类型模块的module.json5中。将下面的条目合并到现有metadata数组,保留工程已有字段:
{
"name": "ohos.arkui.UIMaterial.state",
"value": "enable"
}
它有default、enable和disable三种取值。省略该条目属于default。default采用组件默认规则,enable用于批量开启支持组件,disable用于全局禁用。这里的关键词始终是“支持组件”,不能将应用开关理解成覆盖整个页面的玻璃滤镜。
在组件侧,同样需要区分三种意图:
| 组件配置 | 表达的意图 |
|---|---|
| undefined | 恢复组件默认行为 |
| 显式材质对象 | 请求指定的材质配置 |
| uiMaterial.Material.empty | 关闭材质效果 |
“恢复默认”和“关闭”尤其容易混淆。如果默认规则已经开启材质,移除显式配置后,效果仍然可能存在。
下面是检查背板的局部构建片段。uiMaterial对象沿用官方示例中的接口形式;相同片段分别放入三个待检查区域,外围容器决定它是否处于允许范围。
Column() {
Text('番茄炖牛腩')
}
.width(160)
.height(48)
.borderRadius(16)
.justifyContent(FlexAlign.Center)
.systemMaterial(new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.REGULAR
}))
比较配置状态时,只替换最后一个属性,其他部分保持不变:
// 恢复默认
.systemMaterial(undefined)
// 关闭效果
.systemMaterial(uiMaterial.Material.empty)
这两行是互斥的替换项,不应依次串接在同一组件上。检查的重点是每种配置的语义,而不是调用次数。
通用systemMaterial也不是所有对象的唯一入口。有的组件通过options配置,有的提供专属接口。例如Select的按钮材质与下拉菜单材质分别由systemMaterial和menuSystemMaterial控制。菜单触发控件发生变化,不能证明菜单背板也收到了同一配置。
作用域的边界同样来自组件分类。指南列出的指定弹窗类和接口,以及Slider、Toggle、Select,可以在全页面生效;其他组件受标题栏和指定底部TabBar区域限制。因此,我们用Column检查区域差异,而不拿一个可在全页面生效的Select来证明正文区域普遍支持材质。
确认位置之后,再检查样式。这里应区分两种机制:某些原有样式会影响默认开启条件;某些颜色则会遮挡已经配置的材质。例如默认模式下,Dialog、Toast等组件的背景、模糊和阴影设置会影响默认开启。不能将这个规则不加区分地推广到所有组件。
materialColor的透明度则是另一个问题。[常见问题][faq]说明,它会向材质混入颜色。不透明颜色可能遮住滤镜呈现。在允许区域内,可以保持其他参数不变,单独比较这两个对象:
// 不透明混入色
new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.REGULAR,
materialColor: '#FFFF0000'
})
// 带透明度的混入色
new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.REGULAR,
materialColor: '#80FF0000'
})
这组比较用于解释透明度,不是菜谱的最终配色。还应检查backgroundColor、backgroundBlurStyle及通用属性的设置顺序。官方FAQ建议将通用systemMaterial放在其他样式属性之后;通过options配置时,不应机械套用这条顺序规则。

图3:先确认是否请求了材质,再核对区域,最后检查样式。背景问题应在支持区域中验证;在正文里移除背景后仍无效果,不能据此断定设备不支持。
还有一个命名相近却必须分开的接口:hdsMaterial。它及getSystemMaterialTypes起始于6.1.0(23),属于HDS配套能力,不能写成HarmonyOS 7才首次提供。[接口文档][hds]说明,查询结果是材质类型数组。检查IMMERSIVE支持时,要检查具体枚举:
import { hdsMaterial } from '@kit.UIDesignKit';
import { BusinessError } from '@kit.BasicServicesKit';
try {
const types = hdsMaterial.getSystemMaterialTypes();
const supportsImmersive =
types.includes(hdsMaterial.MaterialType.IMMERSIVE);
console.info('HDS IMMERSIVE: ' + supportsImmersive);
} catch (error) {
const e = error as BusinessError;
console.error('HDS query failed: ' + e.code + ', ' + e.message);
}
数组非空只说明返回了某种类型;查询失败也应独立记录,不能直接归类为“不支持”。更不能用HDS查询结果证明普通组件所在区域合法。uiMaterial的样式厚薄与hdsMaterial的档位是不同维度,本篇的27格矩阵只针对前者。
检查页可以按下面的职责组织,避免每个位置各维护一套组件:
entry/src/main/
├── module.json5
└── ets/
├── pages/MaterialScopePage.ets
├── components/MaterialProbe.ets
└── model/RecipeData.ets
验证记录/
├── matrix.csv
├── screenshots/
└── logs/
MaterialProbe保存共用背板,MaterialScopePage负责位置与配置对照,RecipeData保持同一菜谱数据。检查页不接管烹饪步骤,也不因切换材质而改变当前进度。
4. 检验
让反例挑战方案
现在可以建立矩阵:三种应用开关、三种组件配置、三个位置,共27个组合。先移除额外冲突样式,将背景遮挡留作后续单变量检查。否则,一个格子的差异可能同时来自位置与颜色,无法归因。
每个位置各使用一张九格表:
| 应用开关 | undefined | 显式材质 | Material.empty |
|---|---|---|---|
| default | 记录默认行为 | 记录显式配置 | 核对关闭效果 |
| enable | 记录批量开启行为 | 记录显式配置 | 核对关闭效果 |
| disable | 核对全局关闭 | 优先级待验证 | 核对关闭效果 |
表中写的是检查任务。执行时要另外填写文档预期、实际呈现和证据编号,不能用一句预期替代运行记录。

图4:每格保留预期、观察值和运行编号。disable与显式材质的组合单独标记,避免用其他组合的表现推导其结果。
这个特殊组合值得多花一点注意。应用开关变化还需要进入相应构建并重新运行。页面上的切换按钮可以改变组件状态,却不能据此声称安装包的metadata已经变化。每次运行先确认配置,再进入同一菜谱与检查页,保存截图和日志,最后恢复基线。
记录至少包含这些信息:
| 字段 | 用途 |
|---|---|
| 运行编号、工程版本 | 定位构建与改动 |
| 目标SDK、构建SDK、系统、机型 | 限定结论适用范围 |
| 主题、系统光感设置、固定菜图 | 保持视觉条件可比较 |
| 组件类型、位置、材质与背景参数 | 还原具体配置 |
| 文档预期、视觉观察、日志 | 区分规则与表现 |
| 截图路径、功能检查结果 | 复核画面与操作 |
静态矩阵之外,再做两项状态核对:省略metadata条目与显式default是否一致;从显式材质切回undefined是否恢复默认。后者尤其容易暴露将“没有配置”误当“关闭”的问题。
接着选一个确认生效的允许区域,每轮只添加一种背景或模糊配置,再恢复原状。不在正文反例上同时叠加样式问题。若要解释“遮挡”,首先要有同一位置、同一配置下可比较的基线。

图5:记录围绕一次运行组织。前后对照只改变一个条件,截图保留位置和必要背景,日志与配置使用相同编号,便于回到原始条件复核。
官方FAQ提供了作用域排查日志:
Material inactive: out of scope. Use component in navigation title bar or Tabbar.
这是查找方向,实际记录应保留设备输出。没有搜索到这行日志,不能反过来证明区域合法;还要检查组件树、组件类别和配置入口。
最后回到用户任务:从列表进入番茄炖牛腩,打开切换菜单,在三个页签之间移动,查看食材与当前步骤。材质变化不应推进或重置步骤。手机和平板分别保留环境记录,某台设备呈现较弱,也不能直接归类为配置失败。配置是否生效与呈现是否相同,是两个判断。
5. 结尾
留下可复用的规则
“没有效果”太宽泛,无法直接指导修改。把它展开后,下一步就具体了:核对版本与配置,确认组件作用域,在允许区域内排除背景遮挡,再复核实际呈现和功能。

图6:每个检查点对应一种动作。区域不支持时调整承载位置或保持常规背景;样式冲突时逐项移除;文档存在歧义时保留配置和运行证据,不跳过核验。
这张排查卡与配置矩阵、检查页目录放在一起,构成一套可以重复使用的工作方法。undefined表示恢复默认,Material.empty表达关闭;显式设置仍受作用域约束;HDS能力查询也不能替代普通组件的位置检查。
对灶台菜谱而言,设计取舍因此更清楚:食材清单留在正文,操作区域在支持条件内采用材质,步骤状态由应用管理。材质的职责是帮助用户辨认层次,内容的位置仍由做菜任务决定。
下一篇沿用同一菜谱与三个页签,从经过配置矩阵确认的底栏继续:当不同菜图经过它的背后,“下一步”和当前步骤文字能否保持清楚。生效条件确定以后,才有稳定的基础讨论可读性。
更多推荐



所有评论(0)