在ArkTS中管理配色,很多开发者习惯用resource文件定义颜色变量,再通过$r('app.color.xxx')引用。这种方案直接、可控,但换品牌色或适配深色模式时,需要全局搜索替换或维护多套资源文件,颜色变量也容易膨胀。本文结合笔者从Flutter到ArkTS的迁移经验,分享鸿蒙下如何用ArkTS实现类似ColorScheme的配色系统,以及resource方案的优化技巧。
一、resource方案的痛点
鸿蒙的resource颜色管理,在resources/base/element/color.json中定义颜色值,深色模式则放在resources/dark/element/color.json中。组件通过@Styles引用资源变量,例如:- @Styles
- function myButtonStyle() {
- .backgroundColor($r('app.color.primary_color'))
- .fontColor($r('app.color.on_primary_color'))
- }
复制代码 这种方式的优点是设计师直接给色值,开发按图索骥,准确度高。但缺点也很明显:
1. 换品牌色需要修改所有资源文件,没有自动推导能力。
2. 颜色变量数量容易膨胀,每个页面可能维护一套颜色。
3. @Styles不支持动态变量替换,每个组件仍需手动绑定样式参数。
二、模拟ColorScheme的尝试
笔者曾尝试用@Consume和全局状态变量模拟Flutter的ColorScheme。思路是在一个共享对象中存储一组颜色值,组件通过@Consume获取,并用状态变量动态切换。但实际效果不尽如人意——@Styles无法直接引用动态变量,组件仍需要逐个属性的绑定。例如:- @Component
- struct MyButton {
- @Consume colorScheme: ColorScheme;
- build() {
- Button('点击')
- .backgroundColor(this.colorScheme.primary)
- .fontColor(this.colorScheme.onPrimary)
- }
- }
复制代码 虽然能工作,但相比Flutter中FilledButton自动从theme获取primary,ArkTS需要显式绑定每个颜色属性,代码冗余且容易遗漏。最终笔者放弃了这种“伪ColorScheme”模式,回归resource多套资源方案。
三、优化resource方案的建议
1. 层级分离:将颜色变量按用途分组,如primary、secondary、surface、error等,类似Material Design的语义。在color.json中定义基础色,深色模式只覆盖亮度相关的变量,主色保持不变。- // base/element/color.json
- {
- "color": [
- {"name": "primary_color", "value": "#1A73E8"},
- {"name": "on_primary_color", "value": "#FFFFFF"},
- {"name": "surface_color", "value": "#FFFFFF"},
- {"name": "on_surface_color", "value": "#1C1B1F"}
- ]
- }
- // dark/element/color.json
- {
- "color": [
- {"name": "surface_color", "value": "#1C1B1F"},
- {"name": "on_surface_color", "value": "#E6E1E5"}
- ]
- }
复制代码 这样深色模式仅需覆盖surface和onSurface,primary保持不变,减少冗余。
2. 使用@Styles + 传参:将颜色变量作为参数传入@Styles,实现一定程度的复用。虽然仍不支持动态属性,但至少减少重复代码。- @Styles
- function applySurfaceStyle(bgColor: Resource, textColor: Resource) {
- .backgroundColor(bgColor)
- .fontColor(textColor)
- }
- @Component
- struct MyCard {
- build() {
- Row() {
- Text('Title')
- }
- .applySurfaceStyle(
- $r('app.color.surface_color'),
- $r('app.color.on_surface_color')
- )
- }
- }
复制代码
3. 换肤工具:如果项目需要动态换色,建议在开发阶段用css-like的变量处理器,编译时生成多套资源文件。ArkTS目前不支持运行时代色,但可通过纯代码层封装一个颜色管理类,组件在运行时机读取颜色值(需注意性能)。
四、与Flutter ColorScheme的对比思考
Flutter的ColorScheme.fromSeed通过一个种子颜色自动推导整套色板,适合品牌色驱动的工作流。鸿蒙的resource方案更适合设计师全量定义色板,两者各有利弊。如果你的项目品牌色固定且不需要动态换肤,resource方案更直接稳定;如果需要快速原型或动态换肤,不妨在鸿蒙端探索用代码层管理颜色(暂不支持官方自动推导)。
五、踩坑记录
- 深色模式下Chip背景色偏灰:鸿蒙Chip组件未提供统一背景色语义,需手动设置backgroundColor,建议用primaryContainer色值。
- 亮度影响:resource方案中,深色模式的主色不会自动变亮,需设计师额外给出暗色主色。笔者曾因为忘记覆盖dark的primary,导致深色模式下按钮文字无法辨识。
总结:鸿蒙的颜色管理没有Flutter那么自动化,但通过合理的资源分层和@Styles封装,也能实现可维护的配色系统。如果你正从Flutter转到ArkTS,建议先理解resource的思路,再考虑是否引入代码层的颜色管理方案。
验证环境:HarmonyOS 6.0 · DevEco Studio 5.0 · nova12u真机 |