HarmonyOS鸿蒙Next中bindSheet中$r引用的dark颜色资源不会随系统深浅模式变化

HarmonyOS鸿蒙Next中bindSheet中$r引用的dark颜色资源不会随系统深浅模式变化 模特框中引入$r颜色,系统深浅色发生变化,弹窗中颜色不会发生变化,需要关闭再打开才能生效,请问有谁知道是什么问题吗

9 回复

openBindSheet中的内容须传入自定义节点ComponentContent,该节点内容刷新须自行管理,以避免频繁刷新带来的性能开销。从而导致引用颜色资源不随系统深浅色模式变化的现象。解决方案如下:

import { FrameNode, ComponentContent } from '@kit.ArkUI';
import { Configuration, EnvironmentCallback, ConfigurationConstant } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { resourceManager } from '@kit.LocalizationKit';

class Params {
  text: string = '';
  colorMode: resourceManager.ColorMode = resourceManager.ColorMode.LIGHT;

  constructor(text: string, colorMode: resourceManager.ColorMode) {
    this.text = text;
    this.colorMode = colorMode;
  }
}

@Builder
function buildText(params: Params) {
  Column() {
    Text(params.text)
      .fontSize(50)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 36 })
      .fontColor($r('app.color.fontcolor'))
  }
}

@Entry
@Component
struct Index {
  @State message: string = 'hello';
  contentNode: ComponentContent<Params> | null = null;
  @State callbackId: number | undefined = 0;

  build() {
    Row() {
      Column() {
        Button("click me")
          .onClick(() => {
            let uiContext = this.getUIContext();
            let uniqueId = this.getUniqueId();
            let frameNode: FrameNode | null = uiContext.getFrameNodeByUniqueId(uniqueId);
            let targetId = frameNode?.getFirstChild()?.getUniqueId();
            if (this.contentNode == null && uiContext.getHostContext() != undefined) {
              this.contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), new Params(this.message,
                uiContext.getHostContext()!!.getApplicationContext()
                  .getApplicationContext()
                  .resourceManager
                  .getConfigurationSync()
                  .colorMode
              ));
            }
            if (this.contentNode == null) {
              return;
            }
            uiContext.openBindSheet(this.contentNode, {
              height: SheetSize.MEDIUM,
              title: { title: 'Title', subtitle: 'subtitle' }
            }, targetId)
              .then(() => {
                console.info('openBindSheet success');
              })
              .catch((err: BusinessError) => {
                console.error('openBindSheet error: ' + err.code + ' ' + err.message);
              });
          })
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
  }

  aboutToAppear(): void {
    let environmentCallback: EnvironmentCallback = {
      onMemoryLevel: (): void => {
        console.log('onMemoryLevel');
      },
      onConfigurationUpdated: (config: Configuration): void => {
        console.log('onConfigurationUpdated ' + JSON.stringify(config));
        let uiContext = this.getUIContext();
        uiContext.getHostContext()?.getApplicationContext()
          .getApplicationContext()
          .resourceManager.getConfiguration((err, config) => {
          // 调用ComponentContent的update更新里面信息
          this.contentNode?.update(new Params(this.message, config.colorMode));
          setTimeout(() => {
            // 调用ComponentContent的updateConfiguration,触发节点的全量更新。
            this.contentNode?.updateConfiguration();
          }, 1000);
        });
      }
    };
    // 注册监听回调
    this.callbackId =
      this.getUIContext().getHostContext()?.getApplicationContext().on('environment', environmentCallback);
    // 设置应用深浅色跟随系统
    this.getUIContext()
      .getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
  }

  aboutToDisappear(): void {
    // 解注册监听environment的回调
    this.getUIContext().getHostContext()?.getApplicationContext().off('environment', this.callbackId);
    this.contentNode?.dispose();
  }
}

更多关于HarmonyOS鸿蒙Next中bindSheet中$r引用的dark颜色资源不会随系统深浅模式变化的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


问题:你用的并不是bindSheet,而是openBindSheet,这个是全局弹框的封装

分析:针对全局封装的弹框,系统深浅色切换,确实不会更新弹框里面的颜色

解决方案:根据openBindSheet的定义,需要通过ComponentContent对象的update方法更新

openBindSheet<T extends Object>(bindSheetContent: ComponentContent<T>, sheetOptions?: SheetOptions, targetId?: number): Promise<void>

详细步骤:

1.定义弹窗内容对象

  compSheet:ComponentContent<Params> = new ComponentContent(this.getUIContext(),wrapBuilder(MyBuilder),new Params("#000000"));

2.定义更新数据的中间类:

class Params{
  color:string;

  constructor(color: string) {
    this.color = color;
  }
}

3.一个简单的弹框布局:

@Builder
function MyBuilder(param:Params){
  Column(){
    Text("哈哈哈哈").fontSize(30).fontColor(param.color)
  }
}

4.注册监听事件,监听深浅色模式切换

aboutToAppear(): void {
    emitter.on("DarkChange",(value)=>{
      if (value.data) {
        const data = value.data["dark"] as ColorMode
        if (data == ColorMode.LIGHT) {
         this.compSheet.update(new Params("#ffffff"))
        }else{
          this.compSheet.update(new Params("#000000"))
        }
      }
    })
  }

5.监听系统的深浅色切换:需要在entryAbility的生命周期函数中监听:

onConfigurationUpdate(newConfig: Configuration): void {
    emitter.emit("DarkChange", {
      data: {
        "dark": newConfig.colorMode
      }
    })
  }

6.点击打开弹窗:

build() {
    Column({ space: 20 }) {
      Button("打开弹窗").onClick((event: ClickEvent) => {
        this.getUIContext().openBindSheet(this.compSheet,{height:300})
      })
    }.width("100%").bindSheet($$this.isShow,this.myBuilder(),{height:300})
  }

这样,切换深浅色模式颜色就会跟随系统发生变化。

总结,关于全局弹窗的封装,修改内容都是通过ComponentContent的update方法进行的,这一点要注意!

希望能帮到你,望采纳!

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

开发者您好,这边通过如下demo并没有复现您的问题,真机版本是API 17。

示例代码如下:

@Entry
@Component
struct Index {
  @State isShow: boolean = false;
  @State sheetHeight: number = 300;

  @Builder
  myBuilder() {
    Column() {
      Text("change height")
        .margin(10)
        .fontSize(20)
        .fontColor($r('app.color.fontcolor')) // 在dark/element/color.json文件中,配置了其他颜色
        .onClick(() => {
          this.sheetHeight = 500;
        })

      Text("Set Illegal height")
        .margin(10)
        .fontSize(20)
        .fontColor($r('app.color.fontcolor'))
        .onClick(() => {
          this.sheetHeight = -1;
        })

      Text("close modal 1")
        .margin(10)
        .fontSize(20)
        .fontColor($r('app.color.fontcolor'))
        .onClick(() => {
          this.isShow = false;
        })
    }
    .width('100%')
    .height('100%')
  }

  build() {
    Column() {
      Text("transition modal 1")
        .onClick(() => {
          this.isShow = true;
        })
        .fontSize(20)
        .margin(10)
        .bindSheet($$this.isShow, this.myBuilder(), {
          height: this.sheetHeight,
          backgroundColor: $r("app.color.start_window_background"),
          onWillAppear: () => {
            console.log("BindSheet onWillAppear.");
          },
          onAppear: () => {
            console.log("BindSheet onAppear.");
          },
          onWillDisappear: () => {
            console.log("BindSheet onWillDisappear.");
          },
          onDisappear: () => {
            console.log("BindSheet onDisappear.");
          }
        })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

为了快速解决您的问题,麻烦您提供如下信息吧:

1.复现代码(如最小复现demo);

2.版本信息(如:开发工具、手机系统版本信息);

需要使用接口openBindSheet,

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

开发者您好,已在3楼答复~,

在HarmonyOS Next中,bindSheet使用$r引用的dark颜色资源未响应系统深浅模式变化,是因为$r默认绑定静态资源路径,缺乏动态适配机制。系统深浅模式切换依赖ColorManager等动态资源管理接口,而$r直接引用无法建立实时关联。需改用动态资源获取方式,例如通过ResourceManager的getColorStateList方法,并监听configuration变化来更新颜色值。

在HarmonyOS Next中,bindSheet弹窗内容默认不会实时响应系统深浅模式变化,这是因为弹窗在首次渲染时静态绑定了初始颜色值。当系统主题切换时,已打开的弹窗不会自动触发UI更新。

建议通过以下方式解决:

  1. 使用@ohos.app.ability.Configuration模块监听系统主题变化
  2. 在主题变更回调中手动更新bindSheet的颜色资源
  3. 或考虑在弹窗显示时动态获取当前系统主题对应的颜色值

示例代码框架:

import configuration from '@ohos.app.ability.Configuration';

// 注册配置变更监听
configuration.on('configurationChange', (config) => {
  // 触发弹窗颜色更新逻辑
  updateSheetColors();
});

这种设计符合动态主题管理的标准实践,需要开发者显式处理主题切换时的界面更新。

回到顶部