第2章:Material 3 设计语言——色彩系统、形状与字型、Material You 原理

说实话,刚开始接触 Material 3 的时候,我第一反应是:「这套色彩系统也太灵活了吧?」以前做 Material Design 2,调色板是固定的,Primary、Accent 写死。现在倒好,它直接拿你壁纸的颜色来生成主题——这就是 Material You 的核心。今天我们就顺着这根线,把色彩系统、形状字型、还有背后的自适应原理理清楚。

2.1 色彩系统:从「固定」到「动态」

Material 3 的色彩架构基于 色调调色板(Tonal Palette)。系统会从用户选择的壁纸中提取一个「源颜色(Source Color)」,然后自动生成 13 个色调色阶,每个色阶对应一个 调色板(Palette)。这些色阶再映射到具体的颜色角色上。

我遇到过不少团队,一上来就纠结「到底该用哪个色值」。实际上,真正重要的不是某个具体色值,而是 角色(Role) 和 对比度关系。

💡 核心角色对照表
角色用途典型色调(深浅)
Primary主要组件、FAB调色板第 40 阶(浅色) / 第 80 阶(深色)
On PrimaryPrimary 上的文字与 Primary 对比度 ≥ 4.5:1
Secondary次要按钮、Slider调色板第 30 阶左右
Tertiary强调性组件(如 Switch)另一组互补调色板
Error错误状态、警示固定红色调,#b3261e 等
Neutral背景、Surface低饱和度灰阶
Neutral VariantCard 背景、分隔线稍深于 Neutral

你看,整个系统其实是一棵 递归树:源颜色 → 调色板 → 角色 → 具体组件。系统会自动计算对比度,你只需要告诉它「哪个角色给哪个组件」,剩下的交给算法。

我个人习惯在定义主题时,先用 MaterialColorUtilities 生成完整调色板,再按角色映射。千万别手动写死色值——一旦用户换了壁纸,整个主题就崩了。

2.2 形状与字型:风格一致性的「可配置标尺」

形状和字型是 Material 3 让我觉得最「舒服」的部分——它们被设计成了 可调的 Scale。说白了,就是一个等级系统,你只要选一个「形状风格」或「字型风格」,系统会自动推算出所有组件的对应参数。

2.2.1 形状系统

形状通过 CornerFamily(圆角、裁剪、弯曲)和 ShapeLevel(0、1、2、3)两层来控制。什么意思呢?拿一个 Button 举例:

  • Level 0:直角,corner-size: 0px
  • Level 1:小圆角,4px
  • Level 2:中圆角,8px
  • Level 3:完全圆角,16px 或更高

每个组件都有自己的默认等级。比如 FAB 默认用 Level 3,Card 用 Level 2。但你可以整体调整 ShapeTheme 来覆盖全局。

⚠️ 我曾经踩过一个坑:为了视觉统一,我把所有组件都改成一样的圆角大小。结果 Switch 的 thumb 和 Card 的圆角看起来很不协调。后来发现,官方建议不同组件保留不同等级,才能形成视觉层级。别盲目统一。

2.2.2 字型系统

字型系统也是类似的 Scale,包含 Display、Headline、Title、Body、Label 五大类,每类有 Large / Medium / Small 三种尺寸。区别在于行高、字重和字号。

样式字重行高(dp)典型字号(sp)
Display Large4006457
Headline Medium5004432
Title Small6002818
Body Large4002416
Label Small5001611

你想想看,如果让一个 Dialog 的标题用 Display Large,那就显得太小气了。Material 3 本身已经给了推荐映射:Dialog 的标题应该用 Headline Small 或 Title Large。跟着 Scale 走,少翻车。

2.3 Material You 原理:个性化不是玄学

Material You 不是一堆花哨的动画效果,它的本质是 动态主题生成 + 自适应组件。原理上就三步:

  1. 提取源颜色:从壁纸用 ML 聚类,选出最突出的颜色。
  2. 生成调色板:通过 HCT 色轮(色相+色度+亮度)计算 13 色调色板。
  3. 应用到角色:把调色板色阶分配给 Primary、Secondary 等。

注意,这个 HCT 色彩空间是 Google 自己搞的,比 HSL/HSV 更接近人眼感知。我刚开始不理解为什么不用旧的 Palette 工具,结果用 HCT 写了个 demo 试了下——嗯,壁纸是草地,生成的 Primary 确实是草绿色,而且浅色对比度刚好达标。比 HSL 准确太多。

📐 核心公式(伪代码):
// HCT 转换(简化)
hue = extractDominantHue(bitmap)
chroma = 48 // 固定饱和度
tone = 40   // Primary 标准亮度
primary = Hct.of(hue, chroma, tone)
// 自动生成调色板
tones = [10,20,30,40,50,60,70,80,90]
palette = tones.map(t => Hct.of(hue, chroma, t))

2.4 三个支柱的关系

色彩系统、形状字型、Material You 原理不是孤立的。它们共同决定了组件在不同的设备、不同的壁纸下,既能保持品牌一致性,又有足够的视觉层级。我把它画成一张图,你可以看到完整的输入输出链路。

Material 3 设计语言核心三大支柱 设计语言核心 色彩系统 源颜色 → 调色板 → 角色 7个角色(Primary~NeutralVariant) HCT 色彩空间 → 自动对比度 形状 & 字型 ShapeScale (Level 0~3) TypeScale (Display~Label) 可配置权值 & 层级映射 Material You 壁纸取色 → ML聚类 HCT生成13色调色板 动态主题 & 自适应组件 所有 Material 3 组件 核心逻辑:源颜色 + ShapeScale + TypeScale → 动态主题 → 组件实例化

这张图把上面讲的串联起来了。三个支柱各自独立,但最终都汇聚到「组件实例化」这一步。我写代码的时候,通常会先配好 MaterialTheme 的三个参数:colors、shapes、typography。只要这三个对象定义得干净,整个 App 的视觉一致性就至少有了 80%。

📌 小建议:做加密动画优化的时候,记得检查动画中用到的颜色是否来自 MaterialTheme.colors.onSurface 这类角色,而不是硬编码十六进制。不然你壁纸一换,动画里的颜色还是旧的,一眼就能看出不协调。

总结(但换个说法)

Material 3 的设计语言其实是在告诉你:别操心具体数值,去操心 映射关系。颜色用角色,形状和字体用 Scale,主题生成交给 HCT。你只要把「某个元素该用什么角色」定好,剩下的交给系统自动适应。

嗯,下一块内容我们就要开始聊加密动画里的优化细节了,但等你吃透了这套设计语言,那些动画的配色和形状才不会跑偏。