HarmonyOS鸿蒙Next中自定义弹窗修改系统深浅颜色,V2装饰器

HarmonyOS鸿蒙Next中自定义弹窗修改系统深浅颜色,V2装饰器 使用V2装饰器如何实现修改通过自定义弹窗修改系统深浅颜色并且持久化,目前是使用V1才能双向绑定不报错

import { hilog } from '@kit.PerformanceAnalysisKit';
import { ConfigurationConstant } from '@kit.AbilityKit';

@Entry
@ComponentV2
export struct Index {
  @Local selectedTheme: string = 'light';
  dialogController: CustomDialogController | null = new CustomDialogController({
    builder: ThemeSelectDialog({
      selectedTheme: $selectedTheme
    }),
    cancel: () => {
      hilog.info(0x0002, '主题弹窗', '点击空白处取消');
    },
    autoCancel: true,
    onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
      console.info(`reason= ${dismissDialogAction.reason}`);
      console.info('dialog onWillDismiss')
      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
        dismissDialogAction.dismiss();
      }
      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
        dismissDialogAction.dismiss();
      }
    },
    alignment: DialogAlignment.Center,
    offset: { dx: 0, dy: -20 },
    customStyle: false,
    cornerRadius: 20,
    width: 300,
    height: 200,
    borderWidth: 1,
    borderStyle: BorderStyle.Dashed,// 使用borderStyle属性,需要和borderWidth属性一起使用
    borderColor: Color.Blue,// 使用borderColor属性,需要和borderWidth属性一起使用
    backgroundColor: Color.White,
    shadow: ({ radius: 20, color: Color.Grey, offsetX: 50, offsetY: 0}),
  })

  aboutToDisappear() {
    this.dialogController = null;
  }

  build() {
    Column() {
      Column() {
        Column() {
          HelpCenterComp({
            onThemeClick: () => {
              if (this.dialogController != null) {
                this.dialogController.open();
              }
            }
          })
        }
        .padding({
          left: 16,
          right: 16
        })
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor("#f4f4f4")
  }
}

@ComponentV2
export struct HelpCenterComp {
  @Param breakpoint: string = ''
  @Param onThemeClick: () => void = () => {}
  @Local callTelSheet: boolean = false

  build() {
    Column() {
      List() {
        ListItem() {
          Row() {
            Row() {
              SymbolGlyph($r('sys.symbol.info_circle'))
                .fontSize(24)
                .fontColor([$r('sys.color.icon_primary'), '#000000'])
            }
            SymbolGlyph($r('sys.symbol.chevron_right')).fontSize(24).fontColor([$r('sys.color.icon_fourth'), '#000000'])
          }
          .width('100%')
          .padding({ top: 16, bottom: 16 })
          .justifyContent(FlexAlign.SpaceBetween)
          .onClick(() => {
            this.onThemeClick();
          })
        }
      }
      .padding({
        left: 12,
        right: 12,
        top: 4,
        bottom: 4,
      })
      .margin({ top: 8 })
      .width('100%')
      .backgroundColor($r('sys.color.comp_background_list_card'))
      .borderRadius(20)
      .divider({ strokeWidth: 1, startMargin: 40 })
      .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true })
      .enableScrollInteraction(false)
    }.margin({ top: 24 }).alignItems(HorizontalAlign.Start)
  }
}

@CustomDialog
struct ThemeSelectDialog {
  controller?: CustomDialogController;
  @Link selectedTheme: string;

  build() {
    Column({ space: 12 }) {
      Text('选择主题模式')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 8 })
        .alignSelf(ItemAlign.Center);

      List() {
        ListItem({ style: ListItemStyle.CARD }) {
          Row() {
            Column() {
              Text('浅色(默认)')
                .fontSize(16)
                .fontColor(Color.Black);
            }
            .layoutWeight(1);

            Column() {
              Radio({ value: 'light', group: 'colorModeRadioGroup' })
                .checked(this.selectedTheme === 'light')
                .onChange((isChecked: boolean) => {
                  if (isChecked) {
                    this.selectedTheme = 'light';
                    hilog.info(0x0002, '主题切换', '选中浅色模式');
                    this.switchColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
                  }
                });
            };
          }
          .padding({ top: 12, bottom: 12, left: 16, right: 16 });
        }
        .width('100%')
        .backgroundColor(Color.White)
        .borderRadius(12);

        ListItem({ style: ListItemStyle.CARD }) {
          Row() {
            Column() {
              Text('深色')
                .fontSize(16)
                .fontColor(Color.Black);
            }
            .layoutWeight(1);

            Column() {
              Radio({ value: 'dark', group: 'colorModeRadioGroup' })
                .checked(this.selectedTheme === 'dark')
                .onChange((isChecked: boolean) => {
                  if (isChecked) {
                    this.selectedTheme = 'dark';
                    this.switchColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
                  }
                });
            };
          }
          .padding({ top: 12, bottom: 12, left: 16, right: 16 });
        }
        .width('100%')
        .backgroundColor(Color.White)
        .borderRadius(12)
        .margin({ top: 8 });

        ListItem({ style: ListItemStyle.CARD }) {
          Row() {
            Column() {
              Text('跟随系统')
                .fontSize(16)
                .fontColor(Color.Black);
            }
            .layoutWeight(1);

            Column() {
              Radio({ value: 'system', group: 'colorModeRadioGroup' })
                .checked(this.selectedTheme === 'system')
                .onChange((isChecked: boolean) => {
                  if (isChecked) {
                    this.selectedTheme = 'system';
                    hilog.info(0x0002, '主题切换', '选中跟随系统');
                    this.switchColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
                  }
                });
            };
          }
          .padding({ top: 12, bottom: 12, left: 16, right: 16 });
        }
        .width('100%')
        .backgroundColor(Color.White)
        .borderRadius(12)
        .margin({ top: 8 });
      }
      .width('100%')
      .height(240);

      Row({ space: 16 }) {
        Button('取消')
          .width('40%')
          .backgroundColor(Color.Grey)
          .fontColor(Color.White)
          .onClick(() => {
            this.controller?.close();
          });

        Button('确定')
          .width('40%')
          .backgroundColor('#0A59F7')
          .fontColor(Color.White)
          .onClick(() => {
            this.controller?.close();
            hilog.info(0x0002, '主题切换', '确认选择:%{public}s', this.selectedTheme);
          });
      }
      .margin({ top: 8 })
      .width('100%')
      .justifyContent(FlexAlign.Center);
    }
    .width(300)
    .padding({ top: 16, bottom: 16 });
  }

  private switchColorMode(mode: ConfigurationConstant.ColorMode) {
    this.getUIContext()
      .getHostContext()?.getApplicationContext()
      .setColorMode(mode);
  }
}

更多关于HarmonyOS鸿蒙Next中自定义弹窗修改系统深浅颜色,V2装饰器的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

更多关于HarmonyOS鸿蒙Next中自定义弹窗修改系统深浅颜色,V2装饰器的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,使用@CustomDialog装饰器创建自定义弹窗。通过系统API window.getLastWindow(this.context)获取窗口实例,调用setWindowSystemBarEnable方法可控制状态栏和导航栏的显示。系统深浅色模式由系统主题决定,弹窗默认跟随系统主题。弹窗内部UI可通过资源引用系统主题变量(如$color('sys.color.ohos_id_color_foreground'))或条件渲染实现深浅色适配。

在HarmonyOS Next中使用V2装饰器实现自定义弹窗修改系统深浅颜色并持久化,关键在于正确处理状态管理和数据传递。从你的代码看,主要问题在于V2装饰器下状态绑定的方式与V1不同。

核心解决方案:

  1. 状态管理调整:V2装饰器推荐使用@State@Local配合,避免直接使用@Link进行跨组件双向绑定。在弹窗组件中,可以通过回调函数或事件的方式将选择结果传递回父组件。

  2. 修改弹窗组件:将ThemeSelectDialog中的@Link selectedTheme: string改为通过参数传递初始值,并通过事件回调传递修改:

    @CustomDialog
    struct ThemeSelectDialog {
      controller?: CustomDialogController;
      @Param selectedTheme: string; // 改为@Param接收初始值
      @Consume themeChangeCallback?: (theme: string) => void; // 回调函数
    
      // 在Radio的onChange中调用回调
      .onChange((isChecked: boolean) => {
        if (isChecked) {
          const newTheme = 'dark'; // 根据实际情况设置
          this.themeChangeCallback?.(newTheme);
          this.switchColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
        }
      })
    }
    
  3. 持久化存储:使用@StorageLink@StorageProp配合PersistentStorage实现颜色主题的持久化:

    import { PersistentStorage } from '@kit.ArkData';
    
    // 定义持久化键值
    PersistentStorage.persistProp('appTheme', 'light');
    
    @Entry
    @ComponentV2
    export struct Index {
      @StorageLink('appTheme') selectedTheme: string = 'light';
      
      // 在回调中更新持久化值
      handleThemeChange = (theme: string) => {
        this.selectedTheme = theme;
      }
    }
    
  4. 系统颜色模式设置:你现有的switchColorMode方法是正确的,通过getUIContext()获取上下文并设置颜色模式。

代码调整要点:

  • 将弹窗中的双向绑定改为单向数据流+事件回调
  • 使用@StorageLink实现状态持久化
  • 确保弹窗关闭时能正确触发主题更新和持久化保存

这样既符合V2装饰器的状态管理规范,又能实现主题切换的持久化功能。注意在弹窗关闭时,通过回调函数更新父组件的状态并触发持久化存储。

回到顶部