Harmonyos之深浅模式适配

Harmonyos之换肤功能

概述

深色模式(Dark Mode)又称之为暗色模式,是与日常应用使用过程中的浅色模式(Light Mode)相对应的一种UI主题。

换肤功能应该是现在APP常见的一个功能, 现在我们来了解下载Harmonyos上app是如何实现换肤功能的。

实现原理

当系统切换到深色模式后,应用内可能会出现部分内容切换到深色主题的情况,例如状态栏、弹窗背景色、系统控件等,会导致应用内页面效果错乱。

为应对上述情况,需要对应用进行深色模式下的内容适配,目前该适配主要依靠资源目录。当系统对应的设置项发生变化后(如系统语言、深浅色模式等),应用会自动加载对应资源目录下的资源文件。

创建的项目默认是支持浅色模式的, 资源一般都放在src/main/resources/base目录下的,如下图:

但是系统为深色模式预留了dark目录,该目录在应用创建时默认不存在,在进行深色模式适配时,需要开发者在src/main/resources中手动地创建出dark目录,将深色模式所需的资源放置到该目录下。

说明

在进行资源定义时,需要在base目录与dark目录中定义同名的资源。例如在base/element/color.json文件中定义text_color为黑色,在dark/element/color.json文件中定义text_color为白色,那么当深浅色切换时,应用内使用了$('app.color.text_color ')作为颜色值的元素会自动切换到对应的颜色,而无需使用其他逻辑判断进行控制。

颜色适配

颜色资源配置

对于颜色资源的适配, 目前有两种方式:

  • 使用系统资源, 当系统切换模式时, 使用受支持的系统资源会自动适配深浅模式。开发人员可以查看支持的系统资源
  • 使用自定义的主题,那么就需要配置不同主题的颜色资源。

这里以配置自定义主题来适配颜色:

配置浅色模式的颜色资源, 配置目录src/main/resources/base/element/color.json

javascript 复制代码
{
  "color": [
  // 浅色主题的颜色
    {
      "name": "test_skin",
      "value": "#008000"
    }
  ]
}

配置深色模式, 配置目录src/main/resources/dark/element/color.json

javascript 复制代码
{
  "color": [
   // 深色主题颜色
    {
      "name": "test_skin",
      "value": "#FFFF00"
    }
  ]
}

工具类编写

AppSkinManager工具类的编写:

typescript 复制代码
import { appPreferences } from './AppPreferences'
import { ConfigurationConstant } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@ohos.base';
import { JSON } from '@kit.ArkTS';

const TAG = "AppSkinManager"
export enum AppSkinMode {
  // 未设置  跟随系统
  NOT_SET,

  // 白色
  LIGHT,

  // 黑色
  DARK
}

export class AppSkinManager {
  // 当前皮肤色, 默认没有设置
  skinMode: AppSkinMode = AppSkinMode.NOT_SET;
  private SKIN_KEY: string = 'skinMode'

  // 判断当前是否是黑板
  static isDartMode(mode: AppSkinMode) {
    return mode === AppSkinMode.DARK;
  }

  // 初始化方法
  public init() {
    // 初始化黑白版
    this.skinMode = appPreferences.getSync(this.SKIN_KEY, AppSkinMode.NOT_SET) as number;
    console.log(`shinMode get from file is ${this.skinMode}`);
  }

  // 更换皮肤
  public changeSkin(context: Context, mode: AppSkinMode) {
    if (this.skinMode !== mode) {
      this.skinMode = mode;
      appPreferences.putSync(this.SKIN_KEY, mode.valueOf());
    }
    console.log(`skin save to PersistentStorage ${appPreferences.getSync('skinMode', AppSkinMode.NOT_SET)}`);

    if (AppSkinManager.isDartMode(mode)) {
      // 设置应用的颜色模式为 深色
      context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK)
    } else {
      context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
    }

    // 改变系统导航栏、状态栏的颜色
    this.changeSystemBar(context, mode)
  }

  changeSystemBar(context: Context, mode: AppSkinMode) {
    let statusBarColor = AppSkinManager.getSystemBarColorByMode(mode)
    let statusBarTextColor = AppSkinManager.getSystemBarTextColorByMode(mode)
    this.setSystemBarColor(context, statusBarColor, statusBarTextColor)
  }

  // 根据当前的颜色模式,获取当前系统bar的颜色
  static getSystemBarColorByMode(mode: AppSkinMode) {
    if (AppSkinManager.isDartMode(mode)) {
      return '#000000';
    }
    return '#FFFFFF';
  }

  // 根据当前的颜色模式, 获取当前系统bar文本的颜色
  static getSystemBarTextColorByMode(mode: AppSkinMode) {
    if (AppSkinManager.isDartMode(mode)) {
      return '#FFFFFF';
    }
    return '#000000';
  }

  // 设置主窗口全屏模式时窗口内导航栏、状态栏的属性
  setSystemBarColor(context: Context, statusBarColor: string, statusBarTextColor: string) {
    try {
      // 首先是获取应用的主窗口
      let windowsClass: window.Window | null = null;
      // 获取当前应用内最上层的子窗口,若无应用子窗口,则返回应用主窗口
      window.getLastWindow(context, (err, data) => {
        if (err.code) {
          return
        }
        windowsClass = data

        //创建属性
        let systemBarProperties: window.SystemBarProperties = {
          statusBarColor: statusBarColor,
          statusBarContentColor: statusBarTextColor,
          navigationBarColor: statusBarColor
        }
        // 设置窗口的属性
        windowsClass.setWindowSystemBarProperties(systemBarProperties, (err: BusinessError) => {
          if (err.code) {
            return;
          }
        })
      })
    } catch (exception) {
      console.error(TAG, "setSystemBarColor:" + JSON.stringify(exception))
    }
  }
}

界面代码编写

typescript 复制代码
//Index.ets主页面代码 
@Entry
@Component
struct Index {
  build() {
    Column(){
      ChangeSkinView()
        .width('100%')
        .height('50%')
        .margin({ top: 100})
      Text("验证换肤功能是否正常")
        .fontSize(50)
        .fontColor($r('app.color.test_skin'))
    }
  }
}

//切换换肤的组件
@Component
export struct ChangeSkinView {
  build() {
    Column(){
      Button("简约白").onClick((event: ClickEvent) => {
        // 切换到白班
        changeSkin(AppSkinMode.LIGHT)
      })
      Button("尊贵黑").onClick((event: ClickEvent) => {
        // 切换到黑板
        changeSkin(AppSkinMode.DARK)
      })
    }
  }
}

适配效果

浅色效果:

深色效果:

除了上述的颜色资源适配外, 还有媒体资源适配和web页面适配, 开发人员可以参考官方文档。

官方文档:https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-dark-mode-adaptation-V5#section128661451172714

相关推荐
Hello__77774 小时前
开源鸿蒙 Flutter 实战|消息通知功能完整实现
flutter·开源·harmonyos
敲代码的鱼哇6 小时前
发送短信/拨打电话/获取联系人能力 UTS 插件(cz-sms)
android·前端·ios·uni-app·安卓·harmonyos·鸿蒙
Hello__77776 小时前
开源鸿蒙 Flutter 实战|仓库评论与点赞功能完整实现
flutter·开源·harmonyos
代码飞天7 小时前
harmonyOS开发之页面跳转
华为·harmonyos
ancktion7 小时前
鸿蒙开发环境配置搭建
华为·harmonyos
nashane7 小时前
HarmonyOS 6学习:加密一致性与安全存储——AES GCM排查与SaveButton实践
学习·安全·harmonyos·harmony app
liulian091610 小时前
【Flutter for OpenHarmony第三方库】Flutter for OpenHarmony 音频播放功能适配与实现指南
flutter·华为·音视频·学习方法·harmonyos
KIHU快狐10 小时前
快狐KIHU|86寸落地触控一体机G+G电容屏HarmonyOS鸿蒙酒吧查询终端
python·华为·harmonyos
SuperHeroWu710 小时前
【小艺Claw】鸿蒙龙虾是什么?如何接入和使用?
华为·harmonyos·鸿蒙·jiuwenclaw·小艺claw
Lanren的编程日记10 小时前
Flutter 鸿蒙应用机器学习功能集成实战:TFLite兼容框架+模拟推理引擎,打造端侧智能体验
flutter·华为·harmonyos·推荐算法