HarmonyOS新特性-沉浸光感在叠叠消小游戏中的落地实践
HarmonyOS新特性-沉浸光感在叠叠消小游戏中的落地实践
沉浸光感在叠叠消小游戏中的落地实践:标题栏、底部栏与弹窗的毛玻璃改造
前言
前段时间我用 ArkTS + ArkUI 开发了一款消除类小游戏「叠叠消」,核心玩法是叠层图案消除,目标平台为 HarmonyOS NEXT(API 26),涵盖手机、折叠屏和平板。游戏跑起来 60fps 很稳,但 UI 层面总觉得"平"——所有界面元素都是纯色背景,各自为政,没有统一的视觉质感。
恰好 HarmonyOS NEXT 提供了「沉浸光感(Immersive Light Sensing)」这套系统级材质渲染能力,官方描述是"通过模拟真实物理光照模型,在 UI 组件内部产生毛玻璃模糊、按压弹性光效、滑动透明度渐变等效果"。说白了就是系统帮你渲染毛玻璃。
我在三个核心场景做了落地:标题栏、底部操作栏、弹窗体系。本文记录具体的改造过程和踩坑经验,希望对同样在适配沉浸光感的开发者有帮助。
适用读者:有 ArkTS/ArkUI 基础、正在做鸿蒙应用适配或性能优化的开发者。
一、沉浸光感简介
在开始改造之前,先简单梳理一下沉浸光感涉及的 API 和概念。
1.1 涉及的 SDK 包
@kit.ArkUI下的uiMaterial.ImmersiveMaterial—— 底层材质渲染能力@kit.UIDesignKit下的hdsMaterial—— HDS 组件的高级封装
1.2 核心 API
组件的 systemMaterial() 属性,设了就开,不设就关:
// 开启
Button('撤回').systemMaterial(new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.ULTRA_THIN,
interactive: true,
lightEffect: { color: undefined }
}))
// 关闭
Button('撤回').systemMaterial(undefined)
1.3 材质档位
| 档位 | 枚举值 | 说明 |
|---|---|---|
| 强 | MaterialLevel.EXQUISITE |
完整效果,含毛玻璃 + 光晕 + 反射 |
| 均衡(默认) | MaterialLevel.GENTLE |
适度效果,平衡性能与视觉 |
| 弱 | MaterialLevel.SMOOTH |
轻量级,仅保留核心视觉特性 |
| 系统自适应 | MaterialLevel.ADAPTIVE |
系统根据设备性能自动选档 |
实际开发中,大多数场景直接用 ADAPTIVE 最省心。
二、改造一:游戏页标题栏(渐变模糊 + 动态显隐)
2.1 改造前
游戏页(GamePage)标题栏使用 NavDestination,纯色背景(暖紫 #7C3AED),固定不动的标题文字。在游戏画面向上滑动时,标题栏始终占据顶部空间,没有利用价值。
2.2 改造方案
参考官方的 Spatialization-master 参考实现,使用 HDS 组件的 HdsNavDestination + titleBar 属性配置。
// WaterFlowDetailView.ets
import { hdsMaterial, HdsNavigation, HideMode, ScrollEffectType } from '@kit.UIDesignKit';
HdsNavigation() {
WaterFlowView({
currentTabIndex: this.currentIndex,
pageKey: PageKeyEnum.IMMERSIVE_LIGHT,
handleTabBarAnimation: (yOffset: number) => {
this.handleTabBarAnimation?.(yOffset);
}
})
}
.mode(NavigationMode.Stack)
.hideBackButton(false)
.titleMode(HdsNavigationTitleMode.MINI)
.dynamicHideTitleBar({
hideTitleArea: true,
hideStatusBar: true,
mode: HideMode.SCROLL_UP_TO,
})
.titleBar({
content: {
title: { mainTitle: $r('app.string.sample_3_title') },
backIcon: {
action: () => { this.handleBackBtnAction(); }
},
menu: this.menus,
},
style: {
scrollEffectOpts: {
enableScrollEffect: true,
scrollEffectType: ScrollEffectType.GRADIENT_BLUR,
blurEffectiveEndOffset: LengthMetrics.vp(this.globalInfoModel.statusBarHeight + 56)
},
systemMaterialEffect: {
materialType: hdsMaterial.MaterialType.ADAPTIVE,
materialLevel: this.customMaterialLevel.level,
},
},
avoidLayoutSafeArea: true,
enableComponentSafeArea: false,
})
.bindToScrollable([this.scroller])
.ignoreLayoutSafeArea(
[LayoutSafeAreaType.SYSTEM],
[LayoutSafeAreaEdge.TOP, LayoutSafeAreaEdge.BOTTOM]
)
2.3 关键属性说明
| 属性 | 值 | 作用 |
|---|---|---|
scrollEffectType |
GRADIENT_BLUR |
标题栏随滑动从透明渐变为毛模糊 |
materialType |
ADAPTIVE |
自适应材质类型 |
materialLevel |
this.customMaterialLevel.level |
可动态切换的材质强度 |
dynamicHideTitleBar.hideTitleArea |
true |
允许标题栏滑动隐藏 |
dynamicHideTitleBar.hideStatusBar |
true |
允许状态栏联动隐藏 |
mode |
SCROLL_UP_TO |
上滑到底后才隐藏,不是一滑就藏 |
2.4 效果描述
页面初始状态:标题栏完全透明,游戏画面铺满全屏。向上滑动时:标题栏逐步浮现毛玻璃效果,不是"闪现"出来。继续上滑到一定位置:标题栏和状态栏整体隐藏,释放更多可视面积。向下滑动时反向过渡,毛玻璃渐隐消失。
2.5 代码量变化
- 改造前:标题栏配置约 5 行
- 改造后:配置约 25 行
- 净增约 20 行,没有改动游戏逻辑代码
三、改造二:底部操作栏(悬浮胶囊 + 左右手自适应)
3.1 改造前
底部操作栏使用 Row 容器 + 深紫色背景(#2D1B69),固定在屏幕底部。视觉效果上是"贴"在屏幕上的一个色块,游戏画面被一条实色条切断。
3.2 改造方案
叠叠消虽然没有多 Tab 切换的需求,但 HDS 的 HdsTabs 悬浮栏模式(barFloatingStyle)恰好提供了所需的「悬浮毛玻璃胶囊」效果,可以直接复用。
// 参考 AdaptiveTabView.ets
HdsTabs({ controller: this.controller }) {
TabContent() {
WaterFlowView({
currentTabIndex: repeatItem.index,
pageKey: PageKeyEnum.ADAPTIVE_TAB
})
}
.tabBar(repeatItem.item)
}
.barOverlap(true)
.vertical(false)
.barPosition(BarPosition.End)
.barFloatingStyle({
barBottomMargin: this.globalInfoModel.naviIndicatorHeight > 0
? this.globalInfoModel.naviIndicatorHeight
: $r('sys.float.padding_level8'),
systemMaterialEffect: {
materialType: hdsMaterial.MaterialType.IMMERSIVE,
materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE
},
miniBar: {
miniBarBuilder: () => this.miniBarBuilder(),
onBarStyleChange: (miniBarStyle: HdsBarStyle) => {
this.isMiniBar = miniBarStyle === HdsBarStyle.COLLAPSE;
}
}
})
3.3 配合智感握姿
adaptToHandedness 属性设为 true 后,底部栏在宽屏设备上会靠向握持手一侧。叠叠消复用了之前智感握姿场景的传感器代码:
// 参考 SmartReachView.ets
import { motion } from '@kit.MultimodalAwarenessKit';
aboutToAppear(): void {
try {
if (canIUse('SystemCapability.MultimodalAwareness.Motion')) {
motion.on('holdingHandChanged', this.handleHoldingHandChange);
}
} catch (error) {
Logger.error(TAG, `Failed on holdingHandChanged. cause: ${error.message}`);
}
}
handleHoldingHandChange = (status: motion.HoldingHandStatus) => {
this.getUIContext().animateTo(
{ curve: curves.interpolatingSpring(0, 1, 288, 30) },
() => {
// barFloatingStyle 已设 adaptToHandedness,无需手动控制偏移
}
);
}
3.4 效果
底部操作栏变成悬浮在游戏画面之上的圆角胶囊,图案堆最下层的图案可以从胶囊底部透出来。adaptToHandedness 在平板和折叠屏展开态下效果明显,手机上屏幕较窄,左右差异不大。
四、改造三:弹窗体系(毛玻璃背景 + 版本兼容)
4.1 改造前
叠叠消的弹窗种类不少:通关结算、失败救场、商城购买、道具确认、设置面板等。使用 CustomDialogController 实现,白底 + 阴影,弹出时游戏画面完全被遮挡。
4.2 工具类封装
弹窗的改造不影响游戏逻辑,核心代码全部封装在 MaterialUtil.ets 中,同时做好 API 版本兼容:
// MaterialUtil.ets
import { uiMaterial } from '@kit.ArkUI';
import { deviceInfo } from '@kit.BasicServicesKit';
import { hdsMaterial } from '@kit.UIDesignKit';
export class MaterialUtil {
/**
* 给弹窗/菜单等组件添加沉浸材质
* 兼容 API 26 以下设备,自动降级
*/
public static getMaterialOptions<T>(option: T): MaterialOptions<T> | T {
if (deviceInfo.apiAvailable('26.0.0')
&& hdsMaterial.getSystemMaterialTypes().length > 0) {
const materialOptions = option as MaterialOptions<T>;
materialOptions.systemMaterial = new uiMaterial.ImmersiveMaterial({
style: uiMaterial.ImmersiveStyle.THICK,
interactive: true,
lightEffect: { color: undefined },
});
return materialOptions;
}
return option; // 不支持的设备直接返回原配置
}
/**
* 给按钮等通用组件添加沉浸材质
*/
public static getMaterialModifier(options: ModifierOptions): CommonModifier {
if (deviceInfo.apiAvailable('26.0.0')
&& hdsMaterial.getSystemMaterialTypes().length > 0) {
const materialOptions: uiMaterial.ImmersiveOptions = {
style: uiMaterial.ImmersiveStyle.ULTRA_THIN,
interactive: true,
lightEffect: { color: undefined }
};
if (options.materialColor) {
materialOptions.materialColor = options.materialColor;
}
options.modifier.systemMaterial(new uiMaterial.ImmersiveMaterial(materialOptions));
} else {
// 低版本降级方案
if (options.backgroundColor) {
options.modifier.backgroundColor(options.backgroundColor);
}
if (options.backgroundBlurStyle) {
options.modifier.backgroundBlurStyle(options.backgroundBlurStyle);
}
}
return options.modifier;
}
}
interface MaterialOptions<T> extends ThisType<T> {
systemMaterial?: SystemUiMaterial;
}
interface ModifierOptions {
modifier: CommonModifier;
style: CustomImmersiveStyle;
backgroundColor?: ResourceColor;
materialColor?: ResourceColor;
backgroundBlurStyle?: BlurStyle;
}
export enum CustomImmersiveStyle {
ULTRA_THIN = 0,
THIN = 1,
REGULAR = 2,
THICK = 3,
ULTRA_THICK = 4
}
4.3 弹窗调用
在通关结算弹窗中调用:
// 通关结算弹窗
try {
const uiContext = this.getUIContext();
const promptAction = uiContext.getPromptAction();
const contentNode = new ComponentContent(
uiContext,
wrapBuilder(victoryDialogBuilder)
);
promptAction.openMenu(
contentNode,
{ id: 'victoryDialog' },
MaterialUtil.getMaterialOptions<MenuOptions>({
mask: false,
backgroundBlurStyle: BlurStyle.COMPONENT_THICK,
}) as MenuOptions
);
} catch (error) {
Logger.error(TAG, `Show dialog failed: ${error.message}`);
}
4.4 效果
弹窗背景变为毛玻璃材质,背后的游戏画面(图案堆、撒花粒子)隐约可见。弹窗不再是阻断式遮罩,而是浮在游戏上的一层半透明玻璃板,游戏连贯感大幅提升。
五、多设备适配要点
叠叠消需要覆盖手机、折叠屏和平板,沉浸光感在不同设备上的表现和处理要点如下:
5.1 手机(竖屏 360-430vp)
标题栏毛玻璃效果最明显,屏幕窄、内容区滑动时标题栏的渐变过渡容易被注意到。底部悬浮胶囊的圆角在手机上比较协调。
5.2 折叠屏展开态(700-900vp)
折叠态切换时需要监听折叠状态并切换布局,但沉浸材质不需要重新配置:
import { display } from '@kit.ArkUI';
display.on('foldStatusChange', (status: display.FoldStatus) => {
if (status === display.FoldStatus.EXPANDED) {
// 切换双列布局(左侧图案堆,右侧收集槽)
// 沉浸材质不需要重新配置——ADAPTIVE 模式会自动适应新布局
} else if (status === display.FoldStatus.FOLDED) {
// 切回单列布局
}
});
5.3 平板(800-1200vp)
图案放大 30%,毛玻璃的透光效果在大屏上更强烈。底部悬浮栏可以通过 barBottomMargin 适当调大间距,增强悬浮感。
六、性能与降级策略
6.1 帧率影响
在 Mate 70 Pro(麒麟 9010)上的帧率测试数据:
| 场景 | 未开启 | EXQUISITE 开启 | 帧率变化 |
|---|---|---|---|
| 游戏静止(图案堆无操作) | 60fps | 60fps | 无感知 |
| 图案点击 + 飞入动画 | 60fps | 60fps | 无感知 |
| 收集槽消除 + 粒子特效 | 60fps | 58-60fps | 偶尔轻微掉帧 |
| 通关撒花 + 弹窗弹出 | 60fps | 55-60fps | 可感知但可接受 |
中端设备(Nova 系列)上使用 ADAPTIVE 模式后,系统自动降到了 GENTLE,帧率没有明显波动。
6.2 降级策略实现
function getMaterialLevel(): hdsMaterial.MaterialLevel {
if (!deviceInfo.apiAvailable('26.0.0')
|| hdsMaterial.getSystemMaterialTypes().length === 0) {
return hdsMaterial.MaterialLevel.SMOOTH; // 不支持 → 最低档
}
// 根据设备性能选择
if (isHighPerformanceDevice()) {
return hdsMaterial.MaterialLevel.EXQUISITE;
}
return hdsMaterial.MaterialLevel.ADAPTIVE;
}
6.3 降级对照表
| 设备等级 | 代表机型 | 标题栏 | 底部栏 | 弹窗 | 按钮 |
|---|---|---|---|---|---|
| 高性能 | Mate 70 Pro / 折叠屏 | EXQUISITE |
EXQUISITE |
EXQUISITE |
完整按压反馈 |
| 中性能 | Nova 系列 | GENTLE |
GENTLE |
THICK |
仅弹性缩放 |
| 低性能 | 畅享系列 | SMOOTH |
SMOOTH |
REGULAR |
关闭材质 |
| 不支持 | API < 26 或无能力 | 降级 backgroundColor + backgroundBlurStyle |
七、踩坑记录
7.1 同层渲染场景变透明
在 API 23 及以前版本中,同层渲染(Web 组件内嵌 ArkUI 控件)下设置沉浸光感可能导致控件背景变透明。叠叠消没有 Web 组件所以没触发,但做混合开发的同学需要注意:在 Web 内嵌的 ArkUI 控件上关闭材质。
// 同层渲染场景下关闭材质
component.systemMaterial(undefined);
7.2 HdsTabs 滚动事件处理
HdsTabs 的浮动栏需要通过 WaterFlow 的滚动回调通知 HdsTabsController 执行显示/隐藏动画。需要维护滚动方向状态,避免动画堆积:
handleTabBarAnimation(yOffset: number): void {
if (this.globalInfoModel.needDynamicHideBar) {
if (yOffset > 0 && !this.isScrollUp) {
this.isScrollUp = true;
this.controller.applyHideAnimation(HdsAnimationMode.SCROLL_ANIMATION);
} else if (yOffset < 0 && this.isScrollUp) {
this.isScrollUp = false;
this.controller.applyShowAnimation(HdsAnimationMode.SCROLL_ANIMATION);
}
}
}
7.3 亮色模式下的白色叠层
亮色模式下 EXQUISITE 材质可能覆盖白色叠层,导致按钮文字和背景颜色接近。解决方案:亮色模式自动降级到 GENTLE。
7.4 折叠屏切换时的材质闪烁
折叠屏展开/折叠切换时,布局结构变化导致底部栏材质短暂闪烁(约 200ms)。在切换动画执行前预置材质参数可以缓解:
// 折叠状态变化前预置材质
this.controller.setBarFloatingStyle({
systemMaterialEffect: {
materialType: hdsMaterial.MaterialType.ADAPTIVE,
materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE,
},
});
八、总结
沉浸光感在叠叠消中的落地总结如下:
| 维度 | 结论 |
|---|---|
| 改动范围 | 核心改动不到 80 行代码(工具类 50 行 + 页面配置约 30 行) |
| 影响范围 | 三个改造场景覆盖玩家 90% 的 UI 接触面 |
| 逻辑侵入 | 零——没有改动任何游戏逻辑代码 |
| 性能影响 | 高配设备无感知,中低配 ADAPTIVE 模式自动降级 |
对我个人来说,最大的感受是:系统级材质渲染和第三方实现的最大区别在于一致性。之前使用 backgroundBlurStyle 手动模拟毛玻璃,不同设备上效果参差不齐,折叠屏切换布局时还要手动重算。现在把材质定义交给系统,不用关心底层渲染实现,也不需要手动适配多设备。
唯一需要上心的是性能分级和降级策略。ADAPTIVE 模式在大多数场景下是最稳妥的选择,只有在高性能设备上可以放开到 EXQUISITE 档位。
参考资料
- 沉浸光感-技术创新 - 华为HarmonyOS开发者
- Spatialization-master(沉浸光感开发案例参考实现)
- UI Design Kit API 参考(@kit.UIDesignKit)
- @kit.ArkUI(uiMaterial.ImmersiveMaterial)
更多推荐



所有评论(0)