本文基于 HarmonyOS Next API 24+,深入「车辆保养手册」应用的可视化层。我们将从 Stack 双层进度条的渲染技巧入手,讲透信息可视化的视觉编码、分类色锚点的认知心理学、分类筛选的交互模型、可访问性与对比度、以及在 360vp 窄屏到 720vp 宽屏上的响应式取舍。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

一、信息可视化的视觉编码

1.1 从数字到视觉长度的转换

应用核心的信息可视化决策是把"5000 公里 / 6 个月"这种数字转换成视觉长度——进度条。这个决策的认知心理学基础是"前注意视觉编码":

人类视觉系统对长度差异的感知是前注意的——一眼能看出哪个长、哪个短,不需要逐个数字比对。而数字本身需要"逐个阅读 + 心算对比",认知开销大。

车主查保养手册的真实场景是"我这次保养该换哪些?"——需要快速横向对比 20 个项目的间隔长短,找出最该关注的几个。如果用数字表格,要逐个读"5000 公里、2 万公里、4 万公里…“心算对比;用进度条,一眼能看出"机油条最短、刹 delta车油条中等、刹 delta车盘条最长”。

1.2 双进度条的认知冲突

每张卡片有两条进度条——里程条(蓝)和时间条(橙)。这是双轴可视化的工程取舍:

方案 优点 缺点
单条(只显里程) 简洁 时间指标被遮蔽,错过"按时间保养"的项目
双条并排 里程与时间都显 视觉重量大,对比稍乱
双条堆叠 紧凑 视觉干扰大,难区分

本应用选双条并排——Row({ space: 6 }) 里两个 Column 各占一半宽度(.layoutWeight(1)),左显里程右显时间。

并排比堆叠好的理由:

  1. 视觉对齐:并排让两条进度条在同一垂直高度起跑,视觉对比直接
  2. 空间充裕:并排用横向空间,堆叠用纵向空间,本应用卡片横向空间充裕
  3. 认知分离:并排让里程与时间在视觉上"分离",避免堆叠的"哪个在上"的认知干扰

1.3 里程与时间的视觉编码

两条进度条用不同颜色编码:

  • 里程条:primary 色(蓝 #1F6FEB
  • 时间条:accent 色(橙 #FF8C1A

蓝橙对比是经典的互补色对比——色相轮上相距约 150°,对比度高,前注意可区分。同时这两个颜色也是色板的主色与强调色,复用让 UI 整体一致。

底部图例明示这个编码:

Row({ space: 16 }) {
  this.LegendDot($r('app.color.primary'), '里程指标')
  this.LegendDot($r('app.color.accent'), '时间指标')
}

图例是可视化设计的"自解释机制"——不依赖用户的颜色记忆,显式告诉"蓝是里程、橙是时间"。这对首次使用应用的用户尤其重要,避免误读。

二、Stack 双层进度条的渲染技巧

2.1 进度条的视觉构成

一条进度条由两层组成:

  • 背景层:满量程的灰色条,表示 100% 的位置
  • 前景层:实际值的彩色条,按百分比覆盖背景

本应用用 Stack 容器叠这两层:

Stack({ alignContent: Alignment.Start }) {
  Column()   // 背景层
    .width('100%')
    .height(6)
    .backgroundColor($r('app.color.divider'))
    .borderRadius(3)
  Column()   // 前景层
    .width(this.getBarWidth(item.intervalKm, 100000))
    .height(6)
    .backgroundColor($r('app.color.primary'))
    .borderRadius(3)
}
.width('100%')
.margin({ top: 2 })

2.2 Stack 的对齐参数

Stack({ alignContent: Alignment.Start })alignContent 决定子节点的对齐方式。Alignment.Start 让子节点靠左起对齐——前景层从左边开始覆盖背景层,符合进度条"从左向右填充"的直觉。

如果用 Alignment.Center,前景层会居中对齐,进度条变成"中间填充"的奇怪样式。所以 Alignment.Start 是进度条的必选对齐。

2.3 双 Column 的尺寸约束

背景层 .width('100%') 占满 Stack 的全宽,前景层 .width('50%')(举例)按百分比占。

关键在于 Stack 的尺寸:Stack 自己 .width('100%') 占满外层 Column 的全宽(外层 Column 用 .layoutWeight(1) 占满 Row 的一半)。这样进度条的实际宽度 = 卡片宽度的一半,与并排布局匹配。

高度 6vp 是进度条的固定高度——太细视觉重量不足、太粗抢注意力,6vp 是移动端进度条的常用值。

2.4 BorderRadius 3 的胶囊形

进度条两端 .borderRadius(3) 让它呈胶囊形——圆角半径 3vp 略大于高度 6vp 的一半(3vp),让两端是完整的半圆。

如果 borderRadius < height/2,两端会保留一段直边,视觉上变成"圆角矩形";如果 borderRadius ≥ height/2,两端是完整半圆,视觉上是"胶囊"。进度条用胶囊形更柔和,与卡片整体的 12vp 圆角风格一致。

2.5 Stack vs Column 的取舍

为什么用 Stack 而不是 Column?因为 Stack 默认让子节点叠层(Z 轴重叠),Column 默认让子节点垂直排列(Y 轴分隔)。

进度条需要"前景层覆盖背景层"——Z 轴重叠,所以用 Stack。如果用 Column,背景层和前景层会垂直堆叠,变成两条独立的条,而不是"前景覆盖背景"的进度条样式。

ArkUI 的 Stack 是 Z 轴叠层容器,Row 是 X 轴排列容器,Column 是 Y 轴堆叠容器。三个容器的轴是核心抽象,选错轴会导致布局完全错位。

三、分类色锚点的认知心理学

3.1 分类色的视觉锚点作用

const CATEGORY_COLORS: Record<string, string> = {
  '发动机': '#1F6FEB',
  '底盘': '#FF8C1A',
  '电气': '#16A34A',
  '车身': '#9333EA'
}

4 个分类各配一个色相。这个分类色在卡片里有两个用途:

  1. 左侧色条:4×40vp 的色条,作为分类的视觉锚点
  2. 副标签字色:分类名(“发动机”)的字色用分类色

3.2 色相轮的分布

4 个分类色的色相分布:

分类 hex RGB 色相 色相角
发动机 #1F6FEB (31, 111, 235) ~217°
底盘 #FF8C1A (255, 140, 26) ~28°
电气 #16A34A (22, 163, 74) 绿 ~134°
车身 #9333EA (147, 51, 234) ~271°

4 个色相角大致均匀分布在色相轮上(28° / 134° / 217° / 271°),相互间距 90° 左右。这种均匀分布让 4 个分类在视觉上"差异最大化"——同屏出现时一眼能区分。

如果色相集中(例如 4 个都是蓝色系),色弱用户和强光环境下就难以区分。这是数据可视化"分类色板"的基本要求——分类色要靠色相差异区分,不能只靠饱和度或亮度。

3.3 分类色与主色板的关系

注意分类色与主色板的重叠:

  • 发动机色 #1F6FEB = 主色板 primary#1F6FEB
  • 底盘色 #FF8C1A = 主色板 accent#FF8C1A
  • 电气色 #16A34A = 主色板新增的绿
  • 车身色 #9333EA = 主色板新增的紫

发动机色与里程进度条色相同(都是 #1F6FEB),这是有意的视觉关联——发动机是保养项目最多的分类(9 项),用主色让它成为视觉重心。

但这个重叠也有代价——进度条的蓝色与发动机的蓝色相同,在某些视觉场景下可能混淆。本应用里因为进度条只在卡片内出现、分类色条在卡片左侧,两者空间分离不会真正混淆。但更严谨的做法是分类色用独立色板,与主色完全分离。

3.4 分类色硬编码 vs 资源化

// 硬编码在代码里
const CATEGORY_COLORS: Record<string, string> = {
  '发动机': '#1F6FEB',
  ...
}

// 资源化方案
const CATEGORY_COLORS: Record<string, Resource> = {
  '发动机': $r('app.color.cat_engine'),
  ...
}

本应用用硬编码 hex,理由是:

  1. 深色模式不支持:本应用暂未适配深色模式,分类色硬编码无影响
  2. 阅读直观:代码里一眼能看出每个分类的颜色值
  3. 避免资源膨胀:4 个分类色都搬资源要加 4 个 color.json 条目

如果应用要支持深色模式,分类色必须资源化——深色模式下分类色可能要调整(例如降低饱和度避免在深色背景上刺眼)。资源化后才能用 dark/element/color.json override。

四、分类筛选的交互模型

4.1 单选 chip 列的交互逻辑

ForEach(this.categories, (cat: string) => {
  Text(cat)
    .fontColor(this.activeCategory === cat ? '#FFFFFF' : $r('app.color.text_secondary'))
    .backgroundColor(this.activeCategory === cat ? $r('app.color.primary') : $r('app.color.card_bg'))
    .borderWidth(1)
    .borderColor(this.activeCategory === cat ? $r('app.color.primary') : $r('app.color.card_border'))
    .onClick(() => {
      this.activeCategory = cat
    })
})

5 个 chip(全部、发动机、底盘、电气、车身)单选——activeCategory 同时只有一个值,点击 chip 把 activeCategory 设为对应分类。

单选的视觉反馈:

状态 字色 背景 边框
选中 #FFFFFF 主色蓝 primary 主色蓝 primary
未选中 副灰 text_secondary card_bg 浅灰 card_border

选中态用"实色填充"——蓝底白字蓝框,视觉重量大;未选中态用"线框"——白底深字浅灰框,视觉重量小。

4.2 全部分类的语义

'全部' 是个特殊的分类——它不是数据集里某个 category 值,而是"显示所有分类"的元选项。

private getFilteredMaintenance(): MaintenanceItem[] {
  if (this.activeCategory === '全部') {
    return MAINTENANCE_DATA   // 不过滤,返回全部
  }
  return MAINTENANCE_DATA.filter((item: MaintenanceItem) => item.category === this.activeCategory)
}

'全部' 在过滤方法里被特殊处理——直接返回原数组,不执行 filter。这是"元选项"的工程惯用法——把"显示全部"作为 chip 列的第一项,与其他分类平级显示,但语义上是"清空筛选"的快捷操作。

4.3 横向滚动 chip 列的响应性

Scroll() {
  Row({ space: 8 }) {
    ForEach(this.categories, ...)
  }
  .padding({ left: 16, right: 16, top: 12, bottom: 12 })
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('100%')

5 个 chip 在 360vp 窄屏上一字排开会显得挤——每个 chip 约 60-80vp 宽(含 padding),5 个 = 300-400vp,刚好接近屏幕宽度。横滚让 chip 列保持一行视觉连贯,超出部分可滚动查看。

scrollBar(BarState.Off) 隐藏滚动条——5 个 chip 的横滚距离很短,显示滚动条反而干扰视觉。这是"短距离滚动隐藏滚动条"的惯用法。

如果 chip 数量多到 10+ 个(例如未来扩展更多分类),横滚的滚动条可以考虑改 BarState.Auto,让用户感知到"还有更多没显示"。

4.4 chip 的 BorderRadius 14

.borderRadius(14)

14vp 的圆角值经过计算:chip 高度 = fontSize 13 + padding 6×2 = 25vp,要胶囊形 borderRadius ≥ 25/2 = 12.5vp。取 14vp 略大于 12.5,确保两端是完整半圆。

这是 ArkUI 圆角取值的心法——胶囊形 = borderRadius ≥ height/2。如果 borderRadius < height/2,两端保留直边,视觉上是"圆角矩形"而不是"胶囊"。

分类筛选 chip 用胶囊形与 Tab 栏的"圆角文字"形成视觉对比——chip 是按钮形态(胶囊)、Tab 是文字形态(无圆角),两种交互元素用不同形状区分。

五、可访问性与对比度

5.1 文字色与背景的对比度

应用色板里文字色与背景色的对比度都满足 WCAG 标准:

文字色 hex 背景色 hex 对比度 WCAG 等级
text_primary #1F2329 card_bg #FFFFFF ~14:1 AAA(≥ 7:1)
text_secondary #646A73 card_bg #FFFFFF ~5.8:1 AA(≥ 4.5:1)
text_hint #8F959E card_bg #FFFFFF ~3.2:1 AA Large(≥ 3:1)
text_primary #1F2329 page_bg #F5F6F8 ~13:1 AAA
text_secondary #646A73 page_bg #F5F6F8 ~5.4:1 AA
text_hint #8F959E page_bg #F5F6F8 ~3:1 AA Large

主文字(text_primary)满足 AAA 标准——这是应用最常显示的内容(卡片标题、应用名),无障碍覆盖最广。副文字(text_secondary)满足 AA——副文字承载备注信息,AA 足够。提示文字(text_hint)满足 AA Large——提示文字是辅助信息,AA Large(18pt 以上或 14pt 加粗)可接受。

5.2 选中态 chip 的对比度

选中态 chip 是白字蓝底:

  • 字色 #FFFFFF(白)
  • 背景色 #1F6FEB(蓝)
  • 对比度 ~4.6:1,满足 AA

这是选中态可读性的底线——如果选中态对比度不足,色弱用户在强光下无法辨认选中了哪个分类。

5.3 分类色字的可读性

卡片里的分类副标签用分类色作为字色:

Text(item.category)
  .fontSize(11)
  .fontColor(CATEGORY_COLORS[item.category])

4 个分类色在白色卡片背景上的对比度:

分类色 hex vs 白色对比度 WCAG
蓝(发动机) #1F6FEB ~4.6:1 AA
橙(底盘) #FF8C1A ~2.7:1 不达标
绿(电气) #16A34A ~3.4:1 AA Large
紫(车身) #9333EA ~5.4:1 AA

橙色的对比度 2.7:1 不满足任何 WCAG 等级。这意味着"底盘"分类名在白色卡片上对色弱用户和强光环境下不够清晰。

更严谨的做法是分类副标签用深色字(如 text_secondary),只在左侧色条用分类色。但本应用为了"分类色作为视觉锚点"的连贯性,接受了橙色对比度不足的代价——分类副标签是辅助信息(主标题是项目名),可读性要求低。

5.4 进度条的视觉重量

进度条高度 6vp,相对 15vp 的卡片标题文字是"细线"。这个视觉重量经过权衡:

  • 太细(3vp):进度条像分隔线,不显眼
  • 太粗(10vp):进度条抢注意力,与文字重量失衡
  • 6vp:进度条可见但不抢,是"辅助视觉"的合适重量

数据可视化的"视觉重量 hierarchy"应该是:

  1. 主文字(卡片标题):15vp Medium,最重
  2. 主数值(公里数):13vp Medium,次重
  3. 副文字(分类名、备注):11-12vp Normal,中
  4. 进度条:6vp 高度,轻
  5. 色条:4×40vp,轻但醒目(靠颜色锚点)

这个 hierarchy 让用户的视觉焦点自然落在"项目名 + 数值",进度条和色条作为辅助视觉提供横向对比和分类锚点。

六、响应式取舍:从 360vp 到 720vp

6.1 本应用的响应式策略

本应用没有显式的响应式断点——没有 if (screenWidth > 600) { ... } else { ... } 这种条件渲染。所有布局都用百分比和 layoutWeight,自然适应不同屏幕宽度。

这适合工具型应用——内容是固定的卡片列表,不需要"窄屏一列宽屏两列"的响应式重构。但仍有几个点值得分析:

6.2 卡片宽度的响应性

每张卡片 .width('100%') 占满列表容器的全宽。列表容器是 Scroll 内的 Column,宽度受 Scroll 的宽度约束,Scroll 又受外层 Column 约束到屏幕宽度。

因此卡片宽度 = 屏幕宽度 - 列表 padding(左右各 12vp)= 屏幕宽度 - 24vp。在 360vp 窄屏上是 336vp,在 720vp 宽屏上是 696vp。

卡片内部布局靠 Blank()layoutWeight 自适应:

  • 顶部 Row:左标题组 + Blank弹性 + 右数值组,两端对齐
  • 进度条 Row:两条 Column 各 layoutWeight(1),等分宽度
  • 底部备注 Row:标签 + layoutWeight(1) 的文字,文字占满剩余

这种"百分比 + layoutWeight + Blank"的三件套让卡片在任何宽度下都保持合理的内部比例,不会出现"窄屏挤、宽屏散"的问题。

6.3 进度条长度的响应性

进度条的长度 = 卡片宽度 × (卡片内进度条 Column 宽度比例) × (百分比)。

在 360vp 窄屏:

  • 卡片宽 336vp
  • 进度条 Column 宽 = (336 - 24 padding - 6 space) / 2 = 153vp
  • 100% 进度条 = 153vp,50% = 76.5vp

在 720vp 宽屏:

  • 卡片宽 696vp
  • 进度条 Column 宽 = (696 - 24 - 6) / 2 = 333vp
  • 100% 进度条 = 333vp,50% = 166.5vp

宽屏上进度条更长,视觉对比更明显;窄屏上进度条较短但仍可辨识。这是"用百分比而不是固定 vp"的响应式红利——进度条长度自然跟随屏幕宽度。

6.4 横滚 chip 列的响应性

5 个 chip 的总宽度约 300-400vp(含间距和 padding),在 360vp 窄屏上可能超出屏幕宽度,触发横滚;在 720vp 宽屏上一字排开有余裕,不滚动。

scrollBar(BarState.Off) 在两种屏幕上都隐藏滚动条——窄屏滚动时无滚动条提示(chip 列很短,用户左右滑能感知),宽屏不滚动时无残留滚动条。这是"短距离滚动隐藏滚动条"的统一处理。

如果 chip 数量增加到 10+ 个,宽屏也可能要滚动,那时 scrollBar(BarState.Auto) 更合适——让用户感知"还有更多没显示"。

6.5 顶部标题栏的响应性

顶部标题栏用 RowBlank() 把左右两段推开:

  • 左段:应用名 + 副标题,垂直堆叠,宽度自适应内容
  • 中段:Blank() 吃掉剩余宽度
  • 右段:项目计数 chip,宽度自适应内容

在 360vp 窄屏和 720vp 宽屏上,左段和右段宽度都由内容决定,Blank() 自动调整中段宽度让两端对齐。这是 Flexbox 经典的"两端对齐 + 中间弹性"模式,在 ArkUI 里用 Blank() 实现。

七、卡片视觉的层级设计

7.1 卡片的视觉分层

每张 MaintenanceCard 由四段视觉层构成:

  1. 顶部行:项目名 + 分类副标签 + 主数值 + 副数值,承载核心信息
  2. 进度条行:里程条 + 时间条,承载可视化
  3. 底部备注行:标签 + 备注文字,承载补充信息

四段的视觉重量递减:顶部最重(主标题 + 主数值)、进度条次重(可视化锚点)、备注最轻(补充说明)。这个 hierarchy 让用户的视觉焦点自然落在顶部,进度条作为辅助对比,备注作为深读时的补充。

7.2 卡片的色条锚点

每张卡片左侧有 4×40vp 的色条:

Column()
  .width(4)
  .height(40)
  .backgroundColor(CATEGORY_COLORS[item.category])
  .borderRadius(2)
  .margin({ right: 8 })

色条是分类的视觉锚点——4vp 宽度很细但颜色饱和,40vp 高度覆盖卡片标题区,让用户一眼能看出这张卡片属于哪个分类。

色条的 4vp 宽度是"细但可见"的取值——再细就难以辨识,再粗就抢注意力。40vp 高度与卡片标题行高度匹配(标题 fontSize 15 + 副标签 11 + 行间距 ≈ 40vp)。

7.3 卡片的圆角与边框

卡片整体 .borderRadius(12) + .borderWidth(1) + .borderColor($r('app.color.card_border'))

  • 12vp 圆角让卡片呈"柔和矩形",与 Material Design 的卡片风格一致
  • 1vp 浅灰边框让卡片在白色页面背景上有微弱的边界感

为什么不直接用阴影区分卡片?阴影在低端设备上渲染开销大,且 ArkUI 的阴影 API 在不同设备上的渲染效果差异较大。1vp 边框是更稳定可靠的卡片边界表达。

7.4 卡片内间距与留白

卡片内 padding 12vp:

  • 12vp 是 Material Design 推荐的"紧凑卡片"内间距
  • 太小(8vp):内容挤到边框,视觉局促
  • 太大(16vp):内容显得散,浪费空间

12vp 让卡片内容有舒适的留白,同时保持紧凑——20 张卡片在屏幕上能显示约 4-5 张(每张卡片高度约 140-160vp),适合滚动浏览。

八、可访问性的工程边界

8.1 字号的可读性

应用字号梯度:

用途 fontSize 视觉重量
应用名 22 最重
卡片主数值 13
卡片标题 15
Tab 文字 15
分类筛选 chip 13
副数值 11
分类副标签 11
进度条标签 10 极轻
图例文字 11 极轻

最小字号 10vp(进度条标签),在 360vp 窄屏上约对应 15-16px 物理像素,满足无障碍的可读性底线。

如果应用要支持更大字号的无障碍模式,所有 fontSize 都应该改成 sp 单位(HarmonyOS 的 sp 单位会跟随系统字号设置缩放),而不是 vp。但本应用用 vp 是为了"视觉固定",不跟随系统字号——工具型应用的字号设计通常更严格,避免大字号破坏布局。

8.2 触控目标的尺寸

可点击的元素:

  • Tab 文字:padding 12+12 横向、8+8 纵向,触控区约 60×30vp
  • 分类筛选 chip:padding 12+12 横向、6+6 纵向,触控区约 60×25vp

Material Design 推荐触控目标至少 48×48dp,iOS HIG 推荐 44×44pt。本应用的触控区都略小于这个推荐——分类 chip 25vp 高度不够 48dp。

这是工具型应用的紧凑设计取舍——分类筛选 chip 列一行要放 5 个,如果每个 48dp 高度就要占 240vp 垂直空间,挤压内容区。25vp 高度让 chip 列更紧凑,牺牲一点触控舒适性换内容空间。

更严谨的做法是给 chip 增加垂直 padding 让触控区扩大到 48dp,同时视觉高度保持 25vp(用 touch target padding)。但本应用目前没有这个无障碍优化。

8.3 色弱的应对

应用的可视化主要靠颜色编码(分类色、进度条色),对色弱用户有一定影响:

  • 红绿色弱:电气色绿与底盘色橙可能混淆(绿和橙在色相轮上接近)
  • 蓝紫色弱:发动机色蓝与车身色紫可能混淆

应对策略:

  1. 不只用颜色编码:分类除了色条还有文字副标签,即使色弱也能从文字辨识分类
  2. 色相轮均匀分布:4 个分类色相互间距大,色弱用户大概率仍能区分
  3. 进度条有标签:进度条上方有"里程" / "时间"文字标签,不依赖颜色辨识

这是"颜色 + 文字"的双重编码原则——颜色给前注意的快速辨识,文字给后注意的精确辨识。色弱用户即使颜色辨识失败,仍能从文字获取信息。

九、本篇小结

本章从 Stack 双层进度条的渲染技巧入手,完整覆盖了信息可视化 UX 的工程实现。关键点归纳:

  1. 数字转视觉长度:进度条让前注意视觉编码替代逐个数字心算,横向对比一眼完成
  2. Stack 双层叠覆盖:背景层 100% + 前景层百分比,Alignment.Start 让前景从左起覆盖
  3. 分类色相轮均匀分布:4 个分类色相互间距 90°,色弱用户也能辨识
  4. chip 胶囊形 borderRadius = height/2:14vp 圆角配 25vp 高度,两端完整半圆
  5. 对比度满足 WCAG AA:主文字 AAA、副文字 AA、提示文字 AA Large,无障碍覆盖广

十、附录:本篇涉及的关键视觉 API

API 用途 本篇体现
Stack({ alignContent }) Z 轴叠层容器 进度条背景层与前景层叠
.layoutWeight(n) 弹性布局权重 进度条两列等分、卡片内文字占满
Blank() 弹性空白 标题栏两端对齐
.borderRadius(n) 圆角 卡片 12vp、chip 14vp、进度条 3vp
.borderWidth({ bottom: n }) 单边边框 Tab 栏底部分隔线
.scrollable(dir) 滚动方向 分类筛选横滚、内容列表纵滚
.scrollBar(state) 滚动条显隐 分类筛选 Off、内容列表 Auto
.fontColor(Resource) 字色资源引用 全页面颜色取值
.backgroundColor(Resource) 背景色资源引用 卡片、chip、页面背景
.fontWeight(FontWeight.X) 字重 标题 Bold、卡片标题 Medium、正文 Normal

十一、附录:本篇涉及的 WCAG 对比度参考

文字色 背景色 对比度 WCAG 等级
text_primary #1F2329 card_bg #FFFFFF ~14:1 AAA
text_secondary #646A73 card_bg #FFFFFF ~5.8:1 AA
text_hint #8F959E card_bg #FFFFFF ~3.2:1 AA Large
#FFFFFF(选中态字色) primary #1F6FEB ~4.6:1 AA
text_primary #1F2329 page_bg #F5F6F8 ~13:1 AAA

至此完整覆盖了"信息可视化 UX 工程实现"的全貌。五个篇章联动,从需求拆解到资源体系到可视化 UX,构成「车辆保养手册」应用从零到完成的完整工程叙事。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐