HarmonyOS鸿蒙Next中Ability如何响应系统深色模式切换而不重启?
HarmonyOS鸿蒙Next中Ability如何响应系统深色模式切换而不重启? 用户在设置中切换主题,我的 App 页面重建了,导致正在编辑的内容丢失。能不能只换颜色不重建页面?
开发者你好,
可尝试以下深色模式切换,编辑内容不会丢失,如果不能满足,可提供具体复现demo,以便分析。
【背景知识】
- ComponentContent:ComponentContent表示组件内容的实体封装,其对象支持在非UI组件中创建与传递,便于开发者对弹窗类组件进行解耦封装。ComponentContent底层使用了BuilderNode,相关使用规格参考BuilderNode。
- updateConfiguration:传递系统环境变化事件,触发节点的全量更新。
【解决方案】
- 使用ApplicationContext.setColorMode()方法存储当前颜色模式;
- 通过@Watch监听onColorModeChange()方法中的深浅模式的切换;
- 调用updateConfiguration()方法触发节点更新;
- 最后执行onConfigurationUpdate()方法更新存储中的当前颜色模式。
详情请参考如下代码:
// Index.ets
import { ComponentContent, window } from '@kit.ArkUI';
import { customDialogBuilder } from './TestView';
import { ConfigurationConstant } from '@kit.AbilityKit';
const componentContentMap: Array<ComponentContent<[Object]>> = new Array(); // 初始化组件内容映射数组
@Entry
@Component
struct Index {
@StorageProp('currentColorMode') [@Watch](/user/Watch)('onColorModeChange') currentMode: number =
ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT; // 监听当前颜色模式并初始化为LIGHT模式
// 监听颜色模式变化
onColorModeChange(): void {
componentContentMap.forEach((value, index) => {
// 更新每个组件内容的配置
value.updateConfiguration();
});
}
build() {
Row() {
Column({ space: 20 }) {
Button('打开自定义弹窗')
.fontSize(20)
.onClick(async () => {
const lastWindow = await window.getLastWindow(getHostContext());
const uiContext = lastWindow.getUIContext();
// 创建一个新的组件内容对象
const componentContent = new ComponentContent(
uiContext,
wrapBuilder(customDialogBuilder)
);
// 将新的组件内容添加到映射数组中
componentContentMap.push(componentContent);
uiContext.getPromptAction().openCustomDialog(componentContent);
});
}
.width('100%')
}
.height('100%')
}
}
// EntryAbility.ets
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
// 设置存储中的当前颜色模式
AppStorage.setOrCreate('currentColorMode', this.context.config.colorMode);
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onConfigurationUpdate(newConfig: Configuration): void {
// 更新存储中的当前颜色模式
AppStorage.setOrCreate('currentColorMode', newConfig.colorMode);
hilog.info(0x0000, 'testTag', 'the newConfig.colorMode is %{public}s',
JSON.stringify(AppStorage.get('currentColorMode')) ?? '');
}
// TestView.ets
@Builder
export function customDialogBuilder() {
customDialogComponent()
}
@Component
struct customDialogComponent {
build() {
Column() {
Text('深浅模式测试')
.fontSize(30)
.fontColor($r('app.color.fontColor'))
}
.height(200)
.padding(5)
.justifyContent(FlexAlign.SpaceBetween)
.backgroundColor($r('app.color.backColor'))
}
}
更多关于HarmonyOS鸿蒙Next中Ability如何响应系统深色模式切换而不重启?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
占
在HarmonyOS Next中,Ability可通过监听Configuration变化来响应深色模式切换。在onConfigurationUpdate(config: Configuration)回调中,检测colorMode属性变化。当colorMode为ConfigurationConstant.ColorMode.COLOR_MODE_DARK时表示深色模式,COLOR_MODE_LIGHT为浅色模式。在此回调中更新UI资源即可实现动态切换,无需重启Ability。
在HarmonyOS Next中,Ability(特别是UIAbility)默认会在系统主题(如深色/浅色模式)切换时重建,这是系统为保证资源正确加载而设计的机制。要避免页面重建导致的数据丢失,关键在于将UI与数据分离,并利用状态管理和资源动态加载。
核心方案如下:
- 使用UI状态与数据持久化:将页面的临时数据(如输入框内容)通过
AppStorage或LocalStorage等状态管理工具进行持久化存储。当Ability因主题切换重建时,UI可以从这些存储中恢复数据,而不是丢失。 - 监听系统主题变化并动态应用:在UI代码中,通过
window.getLastWindow(ctx)获取窗口对象,并监听'colorSchemeChange'事件。当系统主题切换时,此事件会触发,你可以在事件回调中动态更新UI的颜色资源,而无需重建页面。- 示例:在
aboutToAppear生命周期中订阅事件,在aboutToDisappear中取消订阅。 - 在事件回调中,使用
ResourceManager重新获取当前主题下的颜色值,并更新到UI组件的状态变量中,驱动UI刷新。
- 示例:在
- 使用资源引用和动态颜色:在布局中,使用资源引用(如
$r('app.color.my_text_color'))或绑定到状态变量,而不是硬编码颜色值。当主题切换时,系统会自动为资源引用加载对应的颜色值,或通过你更新的状态变量触发UI重新渲染。
简要步骤示例(ArkTS):
// 1. 使用AppStorage存储临时数据(如输入内容)
AppStorage.SetOrCreate('inputText', '');
// 2. 在UI组件中监听主题变化
import window from '@ohos.window';
@Entry
@Component
struct MyPage {
@State currentColor: Resource = $r('app.color.my_color'); // 绑定颜色资源
private windowObj: window.Window | null = null;
aboutToAppear() {
// 获取窗口并监听主题切换
window.getLastWindow(this.context).then((win) => {
this.windowObj = win;
this.windowObj.on('colorSchemeChange', () => {
// 主题切换时,重新加载颜色资源并更新状态
this.currentColor = $r('app.color.my_color'); // 重新获取资源
// 其他UI状态更新...
});
});
}
aboutToDisappear() {
if (this.windowObj) {
this.windowObj.off('colorSchemeChange'); // 取消监听
}
}
build() {
Column() {
// 使用动态颜色
Text('Hello').fontColor(this.currentColor)
// 输入框绑定到AppStorage中的数据
TextInput({ text: AppStorage.Get('inputText') })
.onChange((value) => {
AppStorage.Set('inputText', value);
})
}
}
}
总结:通过状态持久化保存数据,结合监听系统主题事件并动态更新UI资源,即可实现Ability在深色/浅色模式切换时仅更新颜色而不重建页面,避免数据丢失。注意,UIAbility本身可能仍会经历生命周期,但页面状态和数据可以完全恢复。

