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
:
{"color": [// 浅色主题的颜色{"name": "test_skin","value": "#008000"}]
}
配置深色模式, 配置目录src/main/resources/dark/element/color.json
:
{"color": [// 深色主题颜色{"name": "test_skin","value": "#FFFF00"}]
}
工具类编写
AppSkinManager工具类的编写:
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))}}
}
界面代码编写
//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
相关文章:

Harmonyos之深浅模式适配
Harmonyos之换肤功能 概述实现原理颜色适配颜色资源配置工具类编写界面代码编写适配效果 概述 深色模式(Dark Mode)又称之为暗色模式,是与日常应用使用过程中的浅色模式(Light Mode)相对应的一种UI主题。 换肤功能应…...
牛客网 SQL2查询多列
SQL2查询多列 select device_id,gender,age,university //查询哪些字段 from user_profile //从哪个表中查找 每日问题 C 中面向对象编程如何处理异常? 在C中,面向对象编程(OOP)处理异常主要通过异常处理机制来实现。C 提供了…...

Angular由一个bug说起之十二:网页页面持续占用CPU过高
随着网络日益发达,网页的内容也更加丰富,形式也更加多样化。而随之而来的性能问题也不容小觑。这篇文章我会根据我在实践中遇到的一个问题来总结,我在面对性能问题的一些解决步骤,希望能对大家有所启发。 查找问题原因 我接触的…...

【从零开始入门unity游戏开发之——C#篇05】转义字符、@处理多行文本或者不使用转义字符、随机数
文章目录 一、转义字符1、什么是转义字符?2、常见的转义字符3、总结 二、使用处理多行文本或者不使用转义字符1、多行字符串2、不使用转义字符 三、随机数1、Random.Next()生成随机整数示例:生成一个随机整数生成指定范围内的随机整数 2、Random.NextSin…...

我们来对接蓝凌OA --报文格式
题记 数智化办公专家、国家高新技术企业、知识管理国家标准制定者、信创供应商10强…等等,这些和咱们有关系吗!!不好意思,走错片场了,刚和项目经理在甲方那边吹牛B想想刚刚的大饼,看看支付宝余额ÿ…...

旅游系统旅游小程序PHP+Uniapp
旅游门票预订系统,支持景点门票、导游产品便捷预订、美食打卡、景点分享、旅游笔记分享等综合系统 更新日志 V1.3.0 1、修复富文本标签 2、新增景点入驻【高级版本】3、新增门票核销【高级版】4、新增门票端口【高级版】...

Pytest-Bdd-Playwright 系列教程(15):背景(Background)
Pytest-Bdd-Playwright 系列教程(15):背景(Background) 前言一、什么是背景(Background)二、特性文件三、测试脚本四、运行测试总结 前言 在测试的过程中,我们往往会遇到这样的问题&…...
ionic V6 安装ios所需
npm install capacitor/ios添加ios平台 ruby要求3.0以上 rvm use ruby-3.1.0 --default npx cap add ios打开xcode看看创建的项目 npx cap open ios没有capacitor指定的位置, 估计之前pod(cocoapods)安装搞得Ruby环境很乱了......cocoapods整的我麻了... App/App/capacitor…...
3d模型展示-初探
由于工作原因,近一年没怎么写代码,有朋友问你做过3D模型展示吗,之前都是做以vue为框架做定制业务,这次抽时间试试3d模型展示。 软件功能 使用ThreeJS框架实现加载GLB模型,并添加动画效果,实现3d展示模型。…...

OpenLinkSaas 2025年1月开发计划
先来看看OpenLinkSaas的大目标 在OpenLinkSaas的产品目标中,让开发人员更加方便的使用云资源是目标之一。通过各大云厂商的API,来可视化云上基础设施的数据是远远不够的。我们准备在2025年1月份增加方便管理和运营研发场景下服务器的能力。 这部分的功能…...
C# 用封装dll 调用c++ dll 使用winapi
这里用c net 封装winapi函数 pch.h // pch.h: 这是预编译标头文件。 // 下方列出的文件仅编译一次,提高了将来生成的生成性能。 // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 // 但是,如果此处列出的文件中的任何一个…...
XML基础学习
参考文章链接: XML基础学习 在w3school看到了XML的教程,想到以前工作学习中也接触到了XML,但只是简单搜索了解了下,没有认真去学习XML的基础,所以现在认真看下其基础部分,并写篇博客作为笔记记录下。 XML 简介 XML 被设计用来传输和存储数据。 什么是 XML? XML 指可…...

Jmeter直连数据库,jar包下载
运行报错信息:jmeter连接mysql异常:Cannot load JDBC driver class ‘com.mysql.jdbc.Driver‘ 1、下载地址: https://mvnrepository.com/artifact/mysql/mysql-connector-java/ 2、将下载好的jar包 (我的是:mysql-con…...

Unity读取、新建Excel表格
把dll资源解压后,全部导入到unity中的Plugins文件下面 资源放在标题下方,可以自行下载 使用教程 引入命名空间 using SimpleExcel;。这个命名空间下主要有两个类:WorkBook和Sheet。WorkBook用于对整个excel文件的操作,如创建、打开…...

智能高效的IDE GoLand v2024.3全新发布——支持最新Go语言
GoLand 使 Go 代码的阅读、编写和更改变得非常容易。即时错误检测和修复建议,通过一步撤消快速安全重构,智能代码完成,死代码检测和文档提示帮助所有 Go 开发人员,从新手到经验丰富的专业人士,创建快速、高效、和可靠的…...
OpenCV相机标定与3D重建(21)投影矩阵分解函数decomposeProjectionMatrix()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将投影矩阵分解为旋转矩阵和相机内参矩阵。 cv::decomposeProjectionMatrix 是 OpenCV 库中的一个函数,用于将投影矩阵(…...
Flink State面试题和参考答案-(下)
如何监控 Flink 作业的状态大小? 监控 Flink 作业的状态大小是确保作业性能和稳定性的重要方面。以下是一些监控状态大小的方法: 使用 Flink Web UI: Flink 提供了一个 Web 用户界面,可以展示作业的当前状态大小,包括每个操作符…...
111.【C语言】数据结构之二叉树的销毁函数
目录 1.知识回顾 2.分析 3.代码 后序遍历销毁(最简洁) 前序遍历销毁(不推荐) 中序遍历销毁(不推荐) 4.将函数嵌入main函数中执行 1.知识回顾 106.【C语言】数据结构之二叉树的三种递归遍历方式 2.分析 销毁二叉树需要按照一定的顺序去销毁,例如:先销毁根还是先销毁根…...

[论文阅读] |智能体长期记忆与反思
写在前面:10月份的时候,联发科天玑9400发布,搭载这款旗舰 5G 智能体 AI 芯片的荣耀MagicOS9.0实现了一句话让手机自动操作美团点咖啡。很快商场实体店里便能看到很多品牌手机已经升级为智能体语音助手。下一步,这些智能体或许便能…...
【Trouble Shooting】Oracle ADG hung,出现ORA-04021
异常问题: 突然收到告警,ADG实例状态异常。 环境: 版本:Oracle 11.2.0.4.201020 状态:Active Dataguard 问题: 查看Oracle实例alert日志,发现有异常报错: Thu Dec 12 22:15:23 …...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...