HarmonyOS 鸿蒙Next深色模式案例
HarmonyOS 鸿蒙Next深色模式案例
<markdown _ngcontent-wfw-c149="" class="markdownPreContainer">
HarmonyOS Next应用开发案例(持续更新中……)
本案例完整代码,请访问:https://gitee.com/harmonyos-cases/cases/tree/master/CommonAppDevelopment/feature/fitfordarkmode
介绍
本示例介绍在开发应用以适应深色模式时,对于深色和浅色模式的适配方案,采取了多种策略如下:
- 固定属性适配:对于部分组件的颜色属性,如背景色或字体颜色,若保持不变,可直接设定固定色值或引用固定的资源文件。
- 双资源目录适配:在resources目录下新增dark子目录,用于存放深色模式下的特定颜色配置(color.json文件)和图片资源(media文件)。在深色模式下,系统会自动加载此目录中的颜色及图片资源,确保与浅色模式下的UI元素色彩差异性。
- 利用系统分层参数:对于支持深色模式切换的系统层级颜色资源,我们可以直接引用这些具有分层特性的参数,使得当切换设备主题时,相关组件的颜色能根据系统当前颜色模式自动更新。
- 监听当前颜色模式变化:通过注册AbilityStage.onConfigurationUpdate事件监听器,实时捕捉到设备深浅颜色模式的变化,并据此动态调整UI布局结构或逻辑处理,以适应不同模式下的最佳视觉体验。
效果图预览
使用说明
- 返回主页,进入系统设置切换深浅颜色模式,再点击深色模式适配进入切换后的颜色模式试图。应用启动并加载至首页时,用户点击深色模式适配按钮后,系统将根据当前设备的颜色模式展示相应的视图效果。
- 用户在返回主页后,再进入系统设置界面调整颜色模式(切换为深色或浅色模式),完成切换后再次点击首页的深色模式适配按钮,应用程序响应更改后的颜色模式对应的视图界面。
实现思路
- 当UI组件的颜色属性被设置为固定颜色值时,其在深色模式和浅色模式下的显示颜色将保持不变。
// 将Text直接设置成'#000000'固定色值 Text("精品好礼") .opacity(0.6) .fontColor($r('app.color.black_font_color')) .margin({ left: $r('app.integer.text_margin_left') })
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button> - 为了实现深色模式下的颜色适配,可以在resources目录下新建'dark/element'的子目录,并在此目录中创建color.json文件。为深色模式下的各个UI组件指定相应的颜色值,务必确保与浅色模式下同名颜色资源名称一致,以确保系统能够正确识别并切换。
// 用资源ID方式设置Column背景色。(浅色模式色值为'#FA5A3C'、深色模式色值为'#000000') .backgroundColor($r('app.color.column_bg_color'))
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button> - 若UI组件的颜色属性引用的是系统提供的具有层级参数的颜色资源,则当设备在深色模式和浅色模式间切换时,这些颜色会自动调整至对应模式下的预设色值。
// 用系统提供的分层参数颜色资源方式设置色值 Text(item.price) .fontSize($r('app.integer.goods_font')) .offset({ x: -3 })// 因为¥是中文字符,上面的是中文字符,占的宽度不一样,所以需要对齐,添加offset .fontColor($r('sys.color.ohos_id_color_foreground'))
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button> - 对于PNG、WEBP或JPEG格式的图片资源,若需支持深色模式,应在resources目录下新增一个'dark/media'子目录,将深色模式下对应的图片放入此目录,并确保图片文件名与浅色模式下的图片相同,以便系统根据当前模式加载合适的图片资源。
// SVG格式图片fillColor颜色资源ID方式设置(浅色模式色值为'#000000'、深色模式色值为'#FFFFFF') Image($r('app.media.view')) .fillColor($r('app.color.view_fill_color')) .width($r('app.integer.view_image_width')) .aspectRatio(1) .objectFit(ImageFit.Contain)
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button> - 在存在深浅两种模式下布局结构或逻辑处理有所差异的情况时,开发者应当利用AbilityStage.onConfigurationUpdate监听接口来实时感知系统主题的变化,并据此做出相应的布局调整或逻辑处理,从而确保应用能够在不同模式下呈现出理想的界面效果及功能体验。
- 第一步保存全局参数,并通过onConfigurationUpdate刷新状态栏
// 获取当前的颜色模式并保存并在onConfigurationUpdate
AppStorage.setOrCreate('currentColorMode', this.context.config.colorMode);
// 保存windowStage供fitfordarkmode的har包中FitForDarkPage.ets中setStatusBar方法修改状态栏颜色。
AppStorage.setOrCreate('windowStage', windowStage);
// 检测当前的深浅模式是否发生变化,刷新状态栏
onConfigurationUpdate(config: Configuration) {
// 获取最新的变更颜色并更新到AppStorage
AppStorage.setOrCreate(‘currentColorMode’, config.colorMode);
logger.info(onConfigurationUpdate, config: ${<span class="hljs-built_in">JSON</span>.stringify(config)}
);
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
- 第二步在FitForDarKMode.ets中获取并监听当前颜色模式
// [@StorageProp](/user/StorageProp) + [@Watch](/user/Watch) 获取并监听当前颜色模式
[@StorageProp](/user/StorageProp)('currentColorMode') [@Watch](/user/Watch)('onColorModeChange') currentMode: number = 0;
// [@Watch](/user/Watch)回调函数,监听颜色模式刷新状态变量
onColorModeChange(): void {
if (this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
this.banner = $r("app.media.dark_mode_banner");
} else {
this.banner = $r("app.media.light_mode_banner");
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
- 第三步在FitForDarKMode.ets生命周期aboutToAppear中根据当前颜色模式刷新banner状态变量,切换不同的图片。
// 在自定义组件生命周期aboutToAppear中,根据当前颜色模式刷新banner状态变量,切换不同的图片。
aboutToAppear(): void {
if (this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
this.banner = $r("app.media.dark_mode_banner");
} else {
this.banner = $r("app.media.light_mode_banner");
// 在当前为浅色模式中,确保界面美观且颜色统一,设置导航栏的背景色。
setStatusBar(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
- 第四步在FitForDarKMode.ets生命周期aboutToDisappear中,重置导航栏的背景色避免影响其它页面的导航栏为红色。
// 在自定义组件生命周期aboutToDisappear中,重置导航栏的背景色避免影响其它页面的导航栏为红色。
aboutToDisappear(): void {
setStatusBar(this.currentMode)
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
- 第五步在FitForDarKMode.ets生命周期aboutToDisappear中,重置导航栏的背景色避免影响其它页面的导航栏为红色。
// 调用setWindowSystemBarProperties()设置状态栏及导航栏的颜色
windowClass.setWindowSystemBarProperties(sysBarProps, (err) => {
if (err.code) {
logger.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err));
return;
}
logger.info('Succeeded in setting the system bar properties.');
});
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
高性能知识点
不涉及
工程结构&模块类型
fitfordarkmode // har类型
|---mock
| |---GoodsMock.ets // 商品列表数据
|---mode
| |---GoodsModel.ets // 商品数据类型定义
|---view
| |---FitForDarkMode.ets // 深色模式适配主页面
| |---GoodsList.ets // 商品列表自定义组件
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
模块依赖
本实例依赖common模块来实现资源的调用以及公共组件FunctionDescription的引用。 还需要依赖EntryAbility.ets模块。
参考资料
@ohos.app.ability.ConfigurationConstant (ConfigurationConstant)
</markdown>我在使用 双资源目录适配 时,创建了dark文件夹,设置了相应颜色资源,为何切换系统颜色模式改为深色后读取的还是浅色资源,
而且 onConfigurationUpdate 没有回调,更改任何系统配置都不能收到回调
可能版本太低了,建议使用最新的ide版本试一下。https://developer.huawei.com/consumer/cn/doc/harmonyos-tools/download-0000001822993593
没有next权限
// 在自定义组件生命周期aboutToAppear中,根据当前颜色模式刷新banner状态变量,切换不同的图片。
aboutToAppear(): void {
let applicationContext = getContext(this).getApplicationContext();
applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
this.banner = setBanner(this.currentMode);
}
// 在自定义组件生命周期aboutToDisappear中,重置导航栏的背景色避免影响其它页面的导航栏为红色。
aboutToDisappear(): void {
let applicationContext = getContext(this).getApplicationContext();
applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
setStatusBar(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
这里面的
applicationContext.setColorMode()方法是报错的;
// 1.获取应用主窗口。
let windowClass: window.Window;
let windowStage: window.WindowStage = AppStorage.get(‘windowStage’) as window.WindowStage;
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
提示 没有 AppStorage.get方法
是的,Next版本才有
双资源目录适配 的方案成本比较低,但有一个问题需要请教。
假如应用中的日夜间模式有3个开关,1. 强制亮色 2. 强制暗色 3. 跟随系统
跟随系统使用 “双资源目录适配”是完全没问题的,那 强制亮色 和 强制暗色,这两种不跟随系统的该如何低成本的实现呢?
在 EntryAblility.ets中可以强制设置单色模式 // 全局设置为浅色模式 let applicationContext = this.context.getApplicationContext(); applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
我在EntryAblility.ets使用了你的建议,用的是DARK,模拟器显示用的资源依然是base文件夹的,不是dark文件夹的。IDE版本5.0.3.403,运行时17.0.10,SDK NEXT Beta1
今天终于搞懂了。必须要使用模拟器或者真机才生效,我一直用的Preview,所以一直不行。用了模拟器,一切OK了。
// 全局设置为浅色模式
let applicationContext = this.context.getApplicationContext(); applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
// 将状态栏和导航栏的背景色设置为跟应用窗口相同的颜色
await windowClass.setWindowSystemBarProperties({
navigationBarColor: "#00FF00",
statusBarColor: "#00FF00",
navigationBarContentColor: "#00FF00",
statusBarContentColor: "#00FF00"
})
以上函数都不支持跨平台, 有没有其他方法实现?
作为IT专家,对于HarmonyOS鸿蒙Next的深色模式案例,以下是一些专业解答:
HarmonyOS鸿蒙Next深色模式的设置相对简单,用户可以通过系统设置菜单进入“显示和亮度”,然后选择“深色模式”,并可选择“定时开启”或“全天开启”。此外,用户还可以选择哪些应用开启深色模式。
在开发应用以适应深色模式时,采取了多种策略。例如固定属性适配,对于部分组件的颜色属性,如背景色或字体颜色,若保持不变,可直接设定固定色值或引用固定的资源文件。还有双资源目录适配,在resources目录下新增dark子目录,用于存放深色模式下的特定颜色配置和图片资源,系统会自动加载此目录中的资源,确保与浅色模式下的UI元素色彩有差异性。
同时,利用系统分层参数也是关键。对于支持深浅模式切换的系统层级颜色资源,可以直接引用这些具有分层特性的参数,使得当切换设备主题时,相关组件的颜色能根据系统当前颜色模式自动更新。
此外,通过监听当前颜色模式变化,开发者可以实时捕捉到设备深浅颜色模式的变化,并据此动态调整UI布局结构或逻辑处理,以适应不同模式下的最佳视觉体验。
总之,HarmonyOS鸿蒙Next深色模式的实现涉及多方面的技术和策略。如需深入了解或遇到具体问题,请查阅相关开发文档或资源。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。