鸿蒙-深色模式适配

前言

在移动应用设计与开发领域,深色模式已从可选功能升级为用户体验的核心标配。它不仅能适配夜间使用场景、降低屏幕功耗与视觉疲劳,更能彰显应用的设计质感与人性化考量,成为衡量产品成熟度的重要指标。 本文聚焦手机应用开发中的深色模式适配实践,从设计原则、色彩体系构建、代码实现逻辑等维度展开解析,结合实际开发中的常见问题与优化方案,为开发者提供一套可落地的适配思路与技术参考,助力打造兼顾视觉体验与用户需求的高品质应用。

粗暴不适配

最粗暴的方法就是不适配,强制写死为亮色(浅色)模式. 在Ability 的 onCreate 方法中

typescript 复制代码
this.context
  .getApplicationContext()
  .setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);

这样,即使我们引用了一些系统资源,也不会在用户开启深色模式后随着改变。

适配

颜色适配

需要将之前硬编码在组件中的色值提取到 color.json文件中。

  1. base/element/color.json定义浅色模式颜色
  2. dark/element/color.json定义深色模式同名颜色
  3. 通过$r('app.color.resource_name')引用资源

这样在切换深色模式时,系统会根据当前模式自动匹配对应目录下的颜色值。 比如,在base/element/color.json文件中

json 复制代码
{
  "color": [
    {
      "name": "page_background_color",
      "value": "#ffffff"
    },
    {
      "name": "text_desc_color",
      "value": "#999999"
    },
    {
      "name": "text_subtitle_color",
      "value": "#666666"
    },
    {
      "name": "text_title_color",
      "value": "#333333"
    }
  ]
}

dark/element/color.json文件中

json 复制代码
{
  "color": [
    {
      "name": "page_background_color",
      "value": "#000000"
    },
    {
      "name": "text_desc_color",
      "value": "#666666"
    },
    {
      "name": "text_subtitle_color",
      "value": "#999999"
    },
    {
      "name": "text_title_color",
      "value": "#cccccc"
    }
  ]
}

然后在代码引用

typescript 复制代码
Text(
  '在 resource 文件夹下新建 dark/element/color.json文件,同时在该文件中配置和 base/element/color.json文件中相同的颜色名称和不同的颜色值',
)
  .fontSize(14)
  .fontColor($r('app.color.text_desc_color'));
Text("在页面中应用配置文件中的色值,例如$r('app.color.text_title_color')")
  .fontSize(14)
  .fontColor($r('app.color.text_desc_color'));
Text('在手机中切换颜色模式,再返回应用')
  .fontSize(14)
  .fontColor($r('app.color.text_desc_color'));

媒体图片资源适配

静态图片适配:在 base/media 和 dark/media 目录放置同名图片文件,深色模式下系统优先加载 dark 目录的图片。 对于 svg 格式的图片,我们还可以使用 Image 组件的fillColor属性根据当前的颜色模式填充不同的颜色已达到适配的目的,但对于 svg 图片来讲,这个属性不是太好用,还不如再设计一张深色模式的svg 图片来的方便。

typescript 复制代码
Row() {
  Image($r('app.media.color_mode_icon')).width('50%')
  Column() {
    Image($r('app.media.color_mode_icon_svg')).height('50%').objectFit(ImageFit.Contain)
    Image($r('app.media.color_mode_icon_svg'))
      .height('50%')
      .fillColor($r('app.color.text_subtitle_color'))
      .objectFit(ImageFit.Contain)
  }.height(px2vp(1024)).width('50%').justifyContent(FlexAlign.Start)
}.width('100%').alignItems(VerticalAlign.Top)

状态栏适配

在 Ability 的onConfigurationUpdate回调中判断当前颜色模式,设置不同的状态栏颜色.

typescript 复制代码
  onConfigurationUpdate(newConfig: Configuration): void {
    this.setColorMode(newConfig.colorMode == ConfigurationConstant.ColorMode.COLOR_MODE_DARK)
  }

    setColorMode(isDark: boolean) {
    if (isDark) {
      window.getLastWindow(this.context).then((win) => {
        console.error('设置状态栏为深色模式')
        win.setWindowSystemBarProperties({
          statusBarColor: "#ff0000",
          statusBarContentColor: "#000000",

        }).catch((error:BusinessError) => {
          console.error('设置状态栏为深色模式 出错 ' + error.message)
        })
      })
    } else {
      window.getLastWindow(this.context).then((win) => {
        console.error('设置状态栏为浅色模式')
        win.setWindowSystemBarProperties({
          statusBarColor: "#00ff00",
          statusBarContentColor: "#ffffff",

        }).catch((error:BusinessError) => {
          console.error('设置状态栏为浅色模式 出错 ' + error.message)
        })
      })
    }
  }

当然也可以在onWindowStageCreate回调的windowStage.loadContent方法中判断一下当前的颜色模式,来设置初始状态

typescript 复制代码
windowStage.loadContent('pages/Index', (err) => {
  this.setColorMode(
    this.context.config.colorMode ==
      ConfigurationConstant.ColorMode.COLOR_MODE_DARK,
  );
});

webview适配

Web组件设置:通过 Web 组件的 .darkMode(WebDarkMode.Auto) 使网页跟随系统模式,或手动设置 .darkMode(WebDarkMode.On/Off)2。 强制深色转换:使用 .forceDarkAccess(true) 对未适配深色的网页进行色值算法转换(需注意部分颜色可能不符合预期)。

设置颜色模式

我们也可以通过代码的方式指定当前 app 使用哪种颜色模式

typescript 复制代码
Button('切换深色模式').onClick((_) => {
  this.getUIContext()
    .getHostContext()
    ?.getApplicationContext()
    .setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
});
Button('切换浅色模式').onClick((_) => {
  this.getUIContext()
    .getHostContext()
    ?.getApplicationContext()
    .setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
});
Button('跟随系统').onClick((_) => {
  this.getUIContext()
    .getHostContext()
    ?.getApplicationContext()
    .setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
});

效果

源码

github: github.com/huangyuanlo...

gitcode: gitcode.com/huangyuan_x...

相关推荐
SummerKaze2 天前
为鸿蒙开发者写一个 nvm:hmvm 的设计与实现
harmonyos
在人间耕耘4 天前
HarmonyOS Vision Kit 视觉AI实战:把官方 Demo 改造成一套能长期复用的组件库
人工智能·深度学习·harmonyos
王码码20354 天前
Flutter for OpenHarmony:socket_io_client 实时通信的事实标准(Node.js 后端的最佳拍档) 深度解析与鸿蒙适配指南
android·flutter·ui·华为·node.js·harmonyos
HarmonyOS_SDK4 天前
【FAQ】HarmonyOS SDK 闭源开放能力 — Ads Kit
harmonyos
Swift社区4 天前
如何利用 ArkUI 框架优化鸿蒙应用的渲染性能
华为·harmonyos
特立独行的猫a4 天前
uni-app x跨平台开发实战:开发鸿蒙HarmonyOS影视票房榜组件完整实现过程
华为·uni-app·harmonyos·轮播图·uniapp-x
盐焗西兰花4 天前
鸿蒙学习实战之路-STG系列(5/11)-守护策略管理-添加与修改策略
服务器·学习·harmonyos
盐焗西兰花4 天前
鸿蒙学习实战之路-STG系列(4/11)-应用选择页功能详解
服务器·学习·harmonyos
lbb 小魔仙4 天前
鸿蒙跨平台项目实战篇03:React Native Bundle增量更新详解
react native·react.js·harmonyos