鸿蒙沉浸光感开发适配
鸿蒙沉浸光感开发适配
引入:界面材质的一次「从视觉层到感知层」升级
你有没有注意过,一些新系统应用的标题栏和底部导航像是「毛玻璃」——底层内容能隐约透过来,按压时还有一圈从指尖扩散开的光晕?这就是 HarmonyOS 新引入的沉浸光感(Immersive Light Sense)。
它不是简单的半透明背景色。沉浸光感系统化地模拟光线的折射、反射与漫射,把界面元素从「实色填充的平面图层」变成「具备光学特性的数字介质」,再配合交互动效,让弹窗、菜单这些常规操作也带上空间感。从 API 版本看:ArkUI 侧自 API 26 起引入沉浸光感能力;HDS 组件侧自 HDS 6.1.0(23) 起支持。整套能力由两块组成:
- 沉浸系统材质:给组件叠加材质滤镜、折射、高光、阴影等多层效果,让底层内容自然透过材质层,建立清晰的视觉层级;
- 沉浸空间动效:为弹窗、菜单的弹出过程提供非线性形变、边缘流光、粒子动画等动态表现。
原理速览:系统底层是怎么实现「光感」的
抛开 API,沉浸光感在底层就是一套系统级的实时玻璃渲染管线,三句话就能讲清:
- 玻璃是「算」出来的:组件背后的画面每帧被送进离屏渲染管线,经过高斯模糊(毛玻璃底)、折射扭曲、高光与阴影多层叠加后,再作为组件背板画回来——底层内容在动,材质每帧重新采样,这就是「透光」感的来源;
- 材质画在系统层,不归应用画布:应用组件画在自己的画布上,而沉浸材质由窗口合成层(系统侧)绘制并统一管理——这也解释了为什么普通组件的材质只在 Navigation 标题栏、底部 TabBar 这些系统托管区域生效;
- 档位控制的是「算多细」:EXQUISITE/GENTLE/SMOOTH 决定叠加几层效果、模糊算多精细,系统按设备算力与用户设置把档位映射成渲染参数,应用只声明样式、不参与计算。
理解了第 2 点,很多「为什么这里不生效」的问题就有了答案:材质的渲染权在系统手里,应用只能「申请」,不能「硬画」。
对开发者来说好消息是:大多数适配只需要一个属性,档位、深浅色模式、设备算力差异都由系统自动处理。下面按「全局开关 → 组件级材质 → HDS 组件 → 空间动效 → 避坑」的顺序展开。
效果演示
以下动图与截图均为真机实测效果:

▲ 效果一:上下滑动时,标题栏在「透明 ↔ 渐变模糊」之间平滑过渡;Slider 联动的渐变卡片(角度/高度实时变化)从标题栏下穿过

▲ 效果二:彩色卡片滚动穿过标题栏与悬浮底栏,毛玻璃材质的透光与模糊层次随内容实时变化

▲ 效果三:systemMaterial(ULTRA_THICK) 显式材质的玻璃弹窗——半透明背板 + 高光描边,背后卡片清晰透出;下方悬浮胶囊 TabBar 同为毛玻璃材质
一、第一步:在模块配置里开启沉浸光感
沉浸光感有全局开关状态(DEFAULT / ENABLE / DISABLE)。在 entry 模块的 module.json5 中配置 metadata 即可开启:
{
"module": {
"type": "entry",
"metadata": [
{
"name": "ohos.arkui.UIMaterial.state",
"value": "enable"
}
]
}
}
注意该配置只在 entry 类型的模块生效。开启后,代码里可以随时查询当前状态:
import { uiMaterial } from '@kit.ArkUI';
const info: uiMaterial.MaterialInfo = uiMaterial.getMaterialInfo();
// info.state === uiMaterial.MaterialState.ENABLE 时,
// 才可以通过 systemMaterial 属性主动设置材质
DEFAULT 和 ENABLE 模式下都允许主动设置;DISABLE 模式下全局禁用,主动设置不生效——所以依赖材质的界面最好先判断 MaterialState。
二、组件级材质:systemMaterial 一个属性搞定
开启后,给任意支持的组件加 .systemMaterial() 属性即可获得沉浸材质:
import { uiMaterial } from '@kit.ArkUI';
@Entry
@Component
struct SystemMaterialPage {
build() {
Stack() {
Image($r('app.media.bg')) // 背景图,用来衬托材质的透光感
.width('100%').height('100%')
Column() {
Text('ULTRA_THIN 超薄:悬浮工具栏')
.systemMaterial(new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.ULTRA_THIN
}))
Text('REGULAR 常规:通用场景')
.systemMaterial(new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.REGULAR
}))
Text('ULTRA_THICK 超厚:强模糊弹窗')
.systemMaterial(new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.ULTRA_THICK
}))
}
}
}
}
材质样式共五档,按材质层厚度(模糊强度)递增:
| 样式 | 特点 | 适用场景 |
|---|---|---|
| ULTRA_THIN | 高透明度材质层 | 悬浮工具栏等强通透背景 |
| THIN | 较透明 | 搜索框等较强透亮场景 |
| REGULAR | 常规厚度(默认) | 一般场景 |
| THICK | 较强模糊 | 菜单等需要模糊背景的场景 |
| ULTRA_THICK | 极强模糊 | 弹窗等完全模糊背景的场景 |
材质层的背景、边框、阴影在开启后统一由系统材质管理,并自动跟随系统深浅色模式切换,无需写两套样式。
三、ImmersiveMaterial 的可调参数
构造参数(ImmersiveOptions)远不止 style 一个:
.systemMaterial(new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.REGULAR, // 材质样式
materialColor: Color.Transparent, // 材质层着色
colorInvert: false, // 是否自动反色
applyShadow: true, // 是否使用材质自带阴影
interactive: true, // 是否启用交互响应(按压光效等)
}))
两个容易踩的参数:
- applyShadow:材质默认自带阴影且优先于通用
shadow属性——你给组件设置的 shadow 不会生效。需要自定义阴影(如品牌色光晕)时,先把applyShadow置 false; - colorInvert(智能反色):自动识别底层内容颜色、动态调整前景色保障可读性,深浅色内容混合的场景建议开启。
另外,对个别不想带材质的组件(例如跟随全局开启后想「退回去」的),可以用空材质关闭:
Select([{ value: '选项1' }, { value: '选项2' }])
.systemMaterial(uiMaterial.Material.empty) // 关闭本体材质
.menuSystemMaterial(uiMaterial.Material.empty) // 关闭下拉菜单材质
弹窗场景也值得单独一提:系统弹窗默认是普通白盒,AlertDialog 的空间动效又依赖设备能力,想要稳定的玻璃背板,就给 CustomDialog 的内容显式设置材质——弹窗类组件不受「标题栏/TabBar 区域」限制,效果稳定可复现:
@CustomDialog
struct GlassDialog {
controller?: CustomDialogController;
build() {
// 外层描边环:材质开启后,组件自身的边框与阴影会被材质接管,
// 直接 .border 不生效,需要用外层容器画一圈高光描边并补投影
Column() {
Column() {
// ……弹窗内容……
}
.width('100%')
.padding(24)
.borderRadius(23)
.systemMaterial(new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.ULTRA_THICK, // 强模糊,弹窗标准档
interactive: true
}))
}
.width('80%')
.padding(1.5)
.borderRadius(24.5)
.border({ width: 1.5, color: '#99FFFFFF' }) // 半透明白高光描边
.shadow({ radius: 32, color: '#33000000', offsetY: 10 })
}
}
双层结构的用意:内层是玻璃本体,外层不受材质管辖,负责描边和投影——玻璃面板的「杯沿感」就靠这一圈。
四、HDS 组件:一行配置获得官方调校的沉浸光感
如果用的是 HDS 组件库(@kit.UIDesignKit),适配更省事——在 HdsNavigation 标题栏和 HdsTabs 悬浮底栏上设置 systemMaterialEffect,这是效果最直观、也最推荐的接入方式:
import { HdsNavigation, HdsNavigationTitleMode, HdsTabs,
HdsTabsController, ScrollEffectType, hdsMaterial } from '@kit.UIDesignKit';
HdsNavigation() {
HdsTabs({ controller: this.controller }) {
// …… TabContent 与 tabBar ……
}
.barOverlap(true)
.vertical(false)
.barPosition(BarPosition.End)
.barFloatingStyle({
barBottomMargin: 28,
// 悬浮底栏:ADAPTIVE = 材质类型与档位均由系统按设备算力自动决定
systemMaterialEffect: {
materialType: hdsMaterial.MaterialType.ADAPTIVE,
materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE
}
})
}
.mode(NavigationMode.Stack)
.titleBar({
content: { title: { mainTitle: '页面标题' } },
style: {
scrollEffectOpts: {
enableScrollEffect: true,
// 标题栏随滚动在 透明 ↔ 渐变模糊 之间平滑过渡
scrollEffectType: ScrollEffectType.GRADIENT_BLUR
},
systemMaterialEffect: {
materialType: hdsMaterial.MaterialType.ADAPTIVE,
materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE
}
},
avoidLayoutSafeArea: false,
enableComponentSafeArea: false
})
// 绑定滚动器,渐变模糊跟随内容滚动生效
.bindToScrollable([this.scrollerForScroll])
.titleMode(HdsNavigationTitleMode.MINI)
// 内容延伸进状态栏/导航条,形成沉浸底色
.ignoreLayoutSafeArea([LayoutSafeAreaType.SYSTEM],
[LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM])
三个配套点缺一不可:bindToScrollable 把页面的 Scroller 绑给标题栏,渐变模糊才会跟随滚动;ignoreLayoutSafeArea 让内容延伸进安全区形成沉浸底色;材质透光要有内容穿过才看得见——滚动到顶时标题栏后面是空白色,看起来就像「没效果」,这是正常现象。
推荐绝大多数业务直接选 ADAPTIVE 类型 + ADAPTIVE 档位:系统会按当前设备算力动态选择材质档位,在高性能机上呈现完整光效,在低算力机上自动降级保流畅,一份代码全设备通用。
五、沉浸空间动效:不用写代码的「光感彩蛋」
沉浸光感的另一半是空间动效,凝结为三类:
| 动效类型 | 表现 | 支持组件 |
|---|---|---|
| 非线性形变 | 光影形态动态变换,打破规则边界 | AlertDialog、CustomDialog、ActionSheet、Menu |
| 边缘流光 | 光流勾勒面板轮廓,引导视线 | 同上 |
| 粒子动画 | 粒子光点表达信息变化 | Slider |
这类动效根据设备算力和用户系统设置自动适配,不需要额外代码——弹窗和菜单弹出时的「破界形变 + 轮廓流光」开箱即得。开发者要做的只是在设计弹窗内容时留出流光勾勒的边距空间。
六、档位体系与用户设置:一次定义,全局映射
沉浸光感有两套「档位」,别混淆:
- 设备材质档位:EXQUISITE(精致,全光效,高性能设备)、GENTLE(均衡,默认)、SMOOTH(轻量,仅基础效果,低算力设备)、ADAPTIVE(自适应,系统自动识别算力选档,业务首选);
- 用户系统设置三档(强/均衡默认/弱):本质是对透明度、反色率、折射强度的精细调控。
关键在于:用户的三档偏好由系统底层自动映射到渲染参数,应用只需一次定义材质,界面就会随用户设置平滑过渡,完全不需要针对三档分别写适配。
七、适配避坑清单
结合官方文档与实践,以下是容易出问题的点:
- 生效范围有限:除弹窗、Slider、Toggle 外,普通组件的沉浸材质只在 Navigation/NavDestination 标题栏、横向 Tabs(barPosition 为 End)的底部 TabBar 区域生效;弹窗系列组件不受该区域约束。给页面中间随机一个 Row 设置材质可能毫无反应,先确认位置;
- 渲染区域要和可视区域一致:用 width、height、borderRadius 控制组件可视区域,材质渲染区域才会贴合;圆角组件记得设置 borderRadius,否则材质会溢出直角边界;
- Text 组件的材质作用于组件区域而非文本内容,想给文字本身加材质是做不到的;
- Web 同层渲染兼容:API 23 及更早版本的 Web 同层渲染场景,内嵌 ArkUI 控件开启沉浸光感会出现异常透明——要么关光感,要么关同层渲染;
- 功耗管控:材质光效消耗 GPU 资源,列表、直播间等高频滚动页面建议用 ADAPTIVE/SMOOTH 档位,遵循「内容优先」原则——光感是增强,不能牺牲操作效率;
- 亮色模式注意:EXQUISITE 档位在亮色模式下可能覆盖白色叠层,底色为非纯白的场景建议切到 GENTLE;
- AlertDialog 的空间动效会静默降级(实测踩坑):弹窗形变、边缘流光完全由系统按设备能力渲染,不支持的设备上弹窗直接退化成普通白盒,没有任何报错或日志提示。想要稳定可复现的玻璃弹窗,用 CustomDialog 显式设置材质(写法见第二节),实测在支持的设备上效果稳定;
- 材质没渲染 ≠ 代码写错了(实测踩坑):排查顺序建议——① 用
uiMaterial.getMaterialInfo()确认状态不是 DISABLE;② 确认真的机系统版本支持 API 26 运行时(版本过旧时一切静默无效,模拟器也不渲染光感材质);③ 确认系统设置中沉浸光感档位不是关闭/弱档;④ ADAPTIVE 档位在低算力设备上只保留基础效果,属正常降级; - 沉浸标题栏与内容重叠(实测踩坑):
avoidLayoutSafeArea: false做沉浸布局时,滚动到顶的内容会顶到状态栏/标题栏底下;若此时标题栏材质恰好未生效(如空白底色区域),视觉上像「文字卡死在标题上」——内容顶部预留标题栏高度的 padding,或保证标题栏后面始终有可模糊的内容。
小结
- 沉浸光感 = 沉浸系统材质 + 沉浸空间动效,ArkUI 自 API 26 引入、HDS 组件自 6.1.0(23) 支持;
- 接入三步走:module.json5 开关 → 查询
uiMaterial.getMaterialInfo()确认 ENABLE → 组件加.systemMaterial(new uiMaterial.ImmersiveMaterial({...})); - 五档材质样式按模糊厚度从 ULTRA_THIN 到 ULTRA_THICK,HDS 组件用
systemMaterialEffect+ ADAPTIVE 一步到位; - 空间动效(非线性形变/边缘流光/粒子)开箱即得,无需适配代码;但要注意其渲染依赖设备能力,追求稳定可复现的效果时,显式
systemMaterial比依赖系统动效更可靠; - 设备算力档位与用户三档偏好均由系统自动映射,开发遵循「内容优先 + ADAPTIVE 优先」即可在多设备上获得一致体验。
更多推荐


所有评论(0)