鸿蒙应用开发实战【03】— ArkUI 设计令牌体系构建(颜色/字体/动画)
鸿蒙应用开发实战【03】— ArkUI 设计令牌体系构建(颜色/字体/动画)
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
在多人协作的项目中,如果每个开发者随意使用颜色字面量('#4F7CFF')、字号(14)、动画时长(300),项目很快就会陷入"颜色一致性噩梦"。**设计令牌(Design Token)**就是解决这个问题的最佳实践——把设计决策集中存储为命名常量,让整个项目通过名字引用而非直接使用原始值。
本篇介绍号码助手项目中的设计令牌体系:AppColors、AppFonts、AppAnimations,以及 ArkUI 中一个极易踩坑的颜色格式问题。
本篇重点:
#AARRGGBB颜色格式、设计令牌封装规范、颜色语义化命名、ArkUI 字体常量、动画曲线封装。
一、为什么需要设计令牌
1.1 没有设计令牌时的问题
// ❌ 没有设计令牌时,颜色散落在各处
Text('号码助手').fontColor('#14141E') // 主文字色
Text('副标题').fontColor('#14141E80') // 副文字色,但哪个是哪个?
.backgroundColor('#B8FFFFFF') // 卡片背景色,什么含义?
.border({ color: '#14141E14' }) // 边框色,语义不明
维护困难:设计稿改了主色调,要逐文件搜索替换
1.2 使用设计令牌后
// ✅ 使用设计令牌后,语义清晰
Text('号码助手').fontColor(AppColors.TEXT)
Text('副标题').fontColor(AppColors.TEXT_2)
.backgroundColor(AppColors.CARD)
.border({ color: AppColors.LINE })
维护简单:改一处 AppColors.PRIMARY = '#3A5FD4',全项目生效
二、AppColors — 颜色设计令牌
2.1 完整颜色系统
号码助手使用的完整颜色令牌体系如下:
// AppColors.ets
export class AppColors {
// ── 主色调 ──────────────────────────────────
static readonly PRIMARY: string = '#4F7CFF' // 主色:蓝紫
static readonly PRIMARY_2: string = '#7C5CFF' // 辅色:紫
static readonly PRIMARY_BG: string = '#F0F3FF' // 主色浅背景
// ── 功能色 ──────────────────────────────────
static readonly DANGER: string = '#FF2E4D' // 危险/删除
static readonly DANGER_BG: string = '#FFF0F2' // 危险背景
static readonly WARN: string = '#FF7A1E' // 警告/待换绑
static readonly WARN_BG: string = '#FFF5EE' // 警告背景
static readonly CYAN: string = '#20C0CE' // 青色/强调
// ── 文字色 ──────────────────────────────────
static readonly TEXT: string = '#14141E' // 主文字(近黑)
static readonly TEXT_2: string = '#14141E80' // 副文字(半透明)
static readonly TEXT_3: string = '#14141E4D' // 占位文字
static readonly MUTED: string = '#999999' // 禁用文字
// ── 背景色 ──────────────────────────────────
static readonly BG: string = '#F5F7FF' // 页面背景
static readonly MUTED_BG: string = '#F2F2F7' // 灰色背景
// ── 卡片与边框(关键!使用 #AARRGGBB 格式)──
static readonly CARD: string = '#B8FFFFFF' // 毛玻璃卡片(72% 透明度白色)
static readonly CARD_B: string = '#E6FFFFFF' // 浅色卡片(90% 透明度白色)
static readonly LINE: string = '#14141E14' // 分割线/边框(8% 透明度黑色)
}
2.2 颜色分类对照表
| 类别 | 令牌名 | 十六进制值 | 用途 |
|---|---|---|---|
| 主色 | PRIMARY | #4F7CFF | 按钮、强调、主要链接 |
| 辅色 | PRIMARY_2 | #7C5CFF | 渐变终点、次要强调 |
| 危险 | DANGER | #FF2E4D | 删除按钮、错误提示 |
| 警告 | WARN | #FF7A1E | 待换绑状态、橙色提示 |
| 主文字 | TEXT | #14141E | 标题、正文 |
| 副文字 | TEXT_2 | #14141E80 | 说明文字(带 50% 透明度) |
| 页面背景 | BG | #F5F7FF | 所有页面的背景色 |
| 卡片 | CARD | #B8FFFFFF | 列表卡片(毛玻璃效果) |
三、ArkUI 颜色格式深度解析(重要踩坑)
3.1 问题现象
号码助手在开发初期,所有卡片都显示为淡黄色,而设计稿要求是半透明白色。
图1:左图为颜色格式错误时的黄色卡片,右图为修复后的正确半透明白色卡片
3.2 根本原因
ArkUI 的颜色格式与 CSS/Android 不同!
| 平台 | 颜色格式 | Alpha 位置 |
|---|---|---|
| CSS / Web | #RRGGBBAA |
最后 |
| Android XML | #AARRGGBB |
最前 |
| ArkUI | #AARRGGBB |
最前 |
以 72% 透明度的白色为例:
// ❌ 错误写法(CSS 格式,AA 在最后)
// #FFFFFF 后面加 B8 表示 72% 不透明度
static readonly CARD: string = '#FFFFFFB8'
// ArkUI 解析为:AA=0xFF(完全不透明), R=0xFF, G=0xFF, B=0xB8
// 结果:RGB(255, 255, 184) = 淡黄色!
// ✅ 正确写法(ArkUI 格式,AA 在最前)
// B8 在最前面表示 72% 不透明度
static readonly CARD: string = '#B8FFFFFF'
// ArkUI 解析为:AA=0xB8(72% 不透明), R=0xFF, G=0xFF, B=0xFF
// 结果:带透明度的白色(正确!)
3.3 Alpha 值换算表
| 不透明度 | 十六进制 AA 值 | 用途示例 |
|---|---|---|
| 100% | FF | 完全不透明 |
| 90% | E6 | CARD_B 卡片 |
| 80% | CC | 轻微透明 |
| 72% | B8 | CARD 毛玻璃卡片 |
| 50% | 80 | TEXT_2 副文字 |
| 30% | 4D | TEXT_3 占位文字 |
| 8% | 14 | LINE 分割线 |
| 0% | 00 | 完全透明 |
3.4 实际修复代码
// 修复前(错误):颜色格式错误,导致卡片变黄
// static readonly CARD: string = '#FFFFFFB8' // 错误!
// static readonly CARD_B: string = '#FFFFFFE6' // 错误!
// 修复后(正确):#AARRGGBB 格式
static readonly CARD: string = '#B8FFFFFF' // ✅ 72% 不透明白色
static readonly CARD_B: string = '#E6FFFFFF' // ✅ 90% 不透明白色
static readonly LINE: string = '#14141E14' // ✅ 8% 不透明深色(分割线)
static readonly TEXT_2: string = '#14141E80' // ✅ 50% 不透明深色(副文字)
记忆口诀:ArkUI 颜色格式 = A(透明度)在前,RGB 在后。与 CSS 的习惯正好相反!
四、AppFonts — 字体设计令牌
4.1 字体令牌定义
// AppFonts.ets
export class AppFonts {
// ── 字号(vp 单位)──────────────────────────
static readonly SIZE_DISPLAY: number = 28 // 大标题(欢迎语)
static readonly SIZE_TITLE: number = 20 // 页面标题
static readonly SIZE_SECTION: number = 16 // 分区标题
static readonly SIZE_BODY: number = 14 // 正文
static readonly SIZE_META: number = 11 // 元数据/说明文字
static readonly SIZE_MINI: number = 10 // 极小标签
// ── 字重 ──────────────────────────────────
static readonly WEIGHT_BOLD: number = 700 // 粗体(标题)
static readonly WEIGHT_SEMIBOLD: number = 600 // 半粗(强调)
static readonly WEIGHT_MEDIUM: number = 500 // 中等(副标题)
static readonly WEIGHT_REGULAR: number = 400 // 常规(正文)
}
4.2 字体令牌对照表
| 令牌名 | 字号值 | 字重值 | 典型用途 |
|---|---|---|---|
| SIZE_DISPLAY | 28vp | BOLD (700) | 首页欢迎语、数字大标 |
| SIZE_TITLE | 20vp | BOLD (700) | 页面顶部标题 |
| SIZE_SECTION | 16vp | SEMIBOLD (600) | 列表分区标题 |
| SIZE_BODY | 14vp | MEDIUM (500) | 卡片主要文字 |
| SIZE_META | 11vp | REGULAR (400) | 时间戳、卡号掩码 |
| SIZE_MINI | 10vp | REGULAR (400) | 分类标签、徽标文字 |
4.3 在 UI 中使用字体令牌
import { AppFonts } from '../common/theme/AppFonts'
import { AppColors } from '../common/theme/AppColors'
// 卡号管理页 — 卡号数字显示
Text('138****8888')
.fontSize(AppFonts.SIZE_SECTION) // 16vp
.fontWeight(AppFonts.WEIGHT_BOLD) // 700
.fontColor(AppColors.TEXT)
// 应用列表行 — 应用名
Text(appName)
.fontSize(AppFonts.SIZE_BODY) // 14vp
.fontWeight(AppFonts.WEIGHT_MEDIUM) // 500
.fontColor(AppColors.TEXT)
// 说明文字
Text('使用该号码注册的应用')
.fontSize(AppFonts.SIZE_META) // 11vp
.fontColor(AppColors.TEXT_2) // 50% 透明度
五、AppAnimations — 动画设计令牌
5.1 动画令牌定义
// AppAnimations.ets
import { curves } from '@kit.ArkUI'
export class AppAnimations {
// 标准过渡动画(按钮点击、状态切换)
static readonly STANDARD = curves.cubicBezierCurve(0.4, 0, 0.2, 1)
// 弹出动画(底部弹窗、卡片展开)
static readonly SPRING = curves.springMotion(0.35, 0.75)
// 时长(毫秒)
static readonly DURATION_FAST: number = 150 // 快速切换(图标/颜色)
static readonly DURATION_NORMAL: number = 300 // 标准过渡
static readonly DURATION_SLOW: number = 500 // 复杂动画
}
5.2 在组件中使用动画令牌
import { AppAnimations } from '../common/theme/AppAnimations'
// 按下效果
.onClick(() => {
animateTo({
duration: AppAnimations.DURATION_FAST,
curve: AppAnimations.STANDARD
}, () => {
this.selectedIndex = newIndex
})
})
// 弹出卡片动画(例如:添加卡号时的预览头像弹出)
.animation({
duration: AppAnimations.DURATION_NORMAL,
curve: AppAnimations.SPRING
})
六、设计令牌最佳实践
6.1 命名规范
- 语义化:用
TEXT_2(副文字)而不是GRAY_50(颜色本身) - 层级清晰:主色 → 变体(
PRIMARY→PRIMARY_2→PRIMARY_BG) - 功能分组:文字色、背景色、状态色、边框色分组命名
6.2 扩展方法
对于颜色枚举到 hex 的映射,使用独立方法而不是直接在令牌中硬编码:
// 在 AddAppPage.ets 中定义 CardColor → hex 的映射方法
private cardColorHex(c: CardColor): string {
switch (c) {
case 'blue': return AppColors.PRIMARY // '#4F7CFF'
case 'purple': return AppColors.PRIMARY_2 // '#7C5CFF'
case 'green': return '#3CC463'
case 'orange': return AppColors.WARN // '#FF7A1E'
case 'pink': return AppColors.DANGER // '#FF2E4D'
default: return AppColors.PRIMARY
}
}
6.3 避免魔法数字
// ❌ 魔法数字:14 是什么?为什么是 14?
Text(appName).fontSize(14)
// ✅ 使用令牌:一看就知道这是"正文"
Text(appName).fontSize(AppFonts.SIZE_BODY)
七、设计令牌与设计稿的对应关系
7.1 设计稿颜色变量映射
根据 design/index.html 设计稿,颜色变量与代码令牌的对应关系:
| 设计稿变量 | 代码令牌 | 十六进制值 |
|---|---|---|
--color-primary |
AppColors.PRIMARY |
#4F7CFF |
--color-text |
AppColors.TEXT |
#14141E |
--color-text-2 |
AppColors.TEXT_2 |
#14141E80 |
--card-bg |
AppColors.CARD |
#B8FFFFFF |
--card-bg-2 |
AppColors.CARD_B |
#E6FFFFFF |
--color-line |
AppColors.LINE |
#14141E14 |
7.2 字体规格对应
| 设计稿规格 | 代码令牌 | 典型应用 |
|---|---|---|
.card-num:15px Bold |
SIZE_SECTION + WEIGHT_BOLD | 卡号管理页卡号数字 |
.body:14px Medium |
SIZE_BODY + WEIGHT_MEDIUM | 应用列表 app 名 |
.meta:11px Regular |
SIZE_META + WEIGHT_REGULAR | 运营商、时间戳 |
八、本篇小结
通过本篇,你掌握了号码助手设计令牌体系的全貌:
- 颜色令牌(AppColors):语义化命名,避免魔法颜色值散落全项目
- ArkUI 颜色格式:
#AARRGGBB(Alpha 在前!)这是开发者极易踩坑的地方 - 字体令牌(AppFonts):统一字号和字重,保证全应用排版一致性
- 动画令牌(AppAnimations):封装
cubicBezierCurve和springMotion,统一动画风格
最重要的记忆点:ArkUI 颜色是
#AARRGGBB,不是 CSS 的#RRGGBBAA!
下一篇将介绍 应用配置详解:app.json5、module.json5 和路由表 main_pages.json 的每个字段含义。
九、参考资料
本系列相关文章:
官方文档:
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
更多推荐



所有评论(0)