前言

应用上架之前,如果你未考虑到深色模式,大概率会审核不通过,问题原因为:应用存在应用未适配深色模式显示问题,不符合鸿蒙应用UX设计规范。

当然了,如果你实在不想适配,也有一个取巧的办法,那就是暂不适配,统一设置为浅色模式。

 // 设置应用为浅色模式
    let applicationContext = this.context.getApplicationContext()
    applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT)

以上的代码设置之后,应用就不会跟随系统模式切换而切换了,但是,取巧终归是取巧,也许现在官方没有严格要求,但是不代表日后不会,所以,为了日后应用的上架,还有深色模式下能给用户带来不一样的体验,建议还是该适配就适配。

对于原生的页面,适配非常的简单,这个在之前的文章中也有过概述,两种方式,一种是资源的方式,一种是代码的方式。

资源方式

对于资源方式,我们可以在resources中新建dark,创建和浅色对应的颜色和图片资源即可,如下图所示:

比如,可以在color.json中定义同名配色并赋予不同的色值。

浅色模式:base/element/color.json文件:

{
  "color": [
    {
      "name": "app_title_color",
      "value": "#000000"
    }
  ]
}

深色模式:dark/element/color.json文件:

{
  "color": [
    {
      "name": "app_title_color",
      "value": "#FFFFFF"
    }
  ]
}

当然了,图片也是类似的,这里就不一一举例了。

代码方式

代码方式就需要监听系统模式的切换了,根据不同的模式,手动设置相应的颜色,基本操作如下,当然了,并不是唯一的方式。

在UIAbility的onConfigurationUpdate进行监听模式改变,这里可以通过事件分发或者通过应用级变量的状态管理AppStorage保存当前colorMode值。 

import { Configuration, UIAbility } from '@kit.AbilityKit';


export default class EntryAbility extends UIAbility {


  onConfigurationUpdate(newConfig: Configuration): void {
    AppStorage.setOrCreate('colorMode', newConfig.colorMode);
  }
}

在其他的页面就可以通过@StorageLink装饰器监听colorMode字段的变化,根据不同的状态设置对应的资源即可。

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


@StorageLink('colorMode') @Watch('colorModeChange') colorMode: ConfigurationConstant.ColorMode =
  ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET;


/**
 * 系统深色模式变化,可以重新设置主题
 */
colorModeChange() {
  if (this.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
    this.readerSetting.nightMode = true;
    this.readerSetting.fontColor = '#ffffff';
    this.readerSetting.themeColor = '#202224';
  } else {
    this.readerSetting.nightMode = false;
    this.readerSetting.fontColor = '#000000';
    this.readerSetting.themeColor = '#FFFFFF';
  }
  this.readerComponentController.setPageConfig(this.readerSetting);
}

以上的方式呢,都是原生的方式,很多的应用,除了原生渲染之外,还有着H5的渲染,针对H5页面,我们该如何动态切换深色和浅色模式呢?

方式一:加载不同模式的web页面

这种方式,说白了就是提供两个web页面,一个是浅色模式,一个是深色模式,我们检测到系统模式变化之后,动态的切换对应模式的页面即可,目前官方在某些功能里,也在使用这种方式,比如官方的一键登录功能,我们就可以发现,针对《认证协议》,就提供了一个浅色页面和一个深色页面。

基本代码如下:

  controller?: WebviewController = new webview.WebviewController()

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


@StorageLink('colorMode') @Watch('colorModeChange') colorMode: ConfigurationConstant.ColorMode =
  ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET;


/**
 * 系统深色模式变化,可以重新设置主题
 */
colorModeChange() {
  if (this.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
      this.controller?.loadUrl("深色页面")
  } else {
      this.controller?.loadUrl("浅色页面")
  }
  this.readerComponentController.setPageConfig(this.readerSetting);
}

方式二:CSS样式适配

方式一,由于是不同的页面,在模式切换的时候,web组件会重新加载,会有一定的延时,不会立马模式转换,并且,在有多个不同的web页面的情况下,会占用服务器资源,当然也会给web前端同学增加一定工作量。

如何实现在本来的页面中进行模式的立马切换?这里就要说到CSS样式了,它可以让web页面根据系统模式进行快速切换,做到0延时,这也是在开发中推荐的,当然了,web前端同学的工作量该做还得做,这是少不了的。

web前端设置

在网页开发过程中,web前端同学可以使用color-scheme和prefers-color-scheme属性进行深色模式适配。

首先,在head标签中添加如下信息,这里的color-scheme是一个CSS属性,用于表示网页支持的配色方案,可以影响表单、滚动条和CSS系统颜色。CSS系统颜色指Web组件内置的颜色,是部分元素未定义样式时应用的默认颜色。

<meta name="color-scheme" content="light dark">

声明了meta之后,剩下的就是,深色和浅色的资源设置了,一般情况下我们只设置默认样式和深色样式即可,当然了你也可以使用浅色模式覆盖深色模式,样式的适配代码如下,只需要在不同模式下设置对应的资源即可。

<style>
  /* 默认样式 */
  body { background-color: White; }
  /* 浅色样式,Web关闭深色模式时覆盖默认样式 */
  @media (prefers-color-scheme: light) {
    body { background-color: Gray; }
  }
  /* 深色样式,Web开启深色模式时覆盖默认样式 */
  @media (prefers-color-scheme: dark) {
    body { background-color: Black; }
  }
</style>

prefers-color-scheme是CSS中的一个媒体查询功能,可以检测系统的主题颜色。web前端同学可以通过该特性,为不同的系统主题颜色定义不同的网页CSS样式,以适应用户的主题偏好。

Web深色模式设置

web前端同学在设置好对应模式资源之后,我们需要给web组件的适配模式打开,方可生效,也就是通过darkMode()配置Web深色模式,因为默认状态下为关闭,我们可以设置为WebDarkMode.Auto,让它跟随系统模式进行动态切换。

还有一个注意事项时,那就是web组件的背景颜色,也需要根据模式动态的切换,否则就会出现,深色模式下先白后改变的状态,简单案例如下:

import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  @State isDark: boolean = false;
  build() {
    Column() {
      Web({ src: $rawfile('index.html'), controller: this.controller })
        .darkMode(WebDarkMode.Auto)
        .backgroundColor(this.isDark ? Color.Black : Color.White)
    }
  }
}

以上的代码设置之后,便可实现了web页面动态的模式切换。

相关总结

web前端页除了css设置之外,还可以通过js代码来监听模式的改变,进行动态的资源设置。

 // 监听颜色方案变化事件
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
            let isDark = e.matches;//是否是深色模式
          
        });

对于深色模式,建议提前去做,因为到后面再想起来适配,需要全方位的资源替换,还要进行系统的测试验证,比较耗费时间和精力,所以,项目一开始,我们尽量把深色模式考虑进去。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐