外观
字阶 — Typography / NumberStyles
全站排版的唯一来源。页面里不要写 fontSize / fontWeight / letterSpacing。
基本用法
kotlin
Text("标题", style = MaterialTheme.typography.titleMedium)
Text("正文", style = MaterialTheme.typography.bodyMedium)
// 会变宽度的数字必须等宽,否则整行左右抖
Text(balance.toString(), style = NumberStyles.display)
Text("$count 次", style = NumberStyles.title)临时给任意样式开等宽数字:
kotlin
Text("12:34", style = MaterialTheme.typography.titleLarge.tabular())参数
15 级字阶 Typography
用 MaterialTheme.typography.xxx 取。
| 档位 | 字号 | 行高 | 字距 | 字重 | 用在哪 |
|---|---|---|---|---|---|
displayLarge | 57sp | 64sp | -0.25sp | Bold | 大数字、全屏展示 |
displayMedium | 45sp | 52sp | 0 | Bold | |
displaySmall | 36sp | 44sp | 0 | Bold | 空态主文案、NumberStyles.display 的基底 |
headlineLarge | 32sp | 40sp | -0.2sp | Black | 折叠标题栏 |
headlineMedium | 28sp | 36sp | 0 | Black | 普通标题栏(TopTitleBar 默认取这条) |
headlineSmall | 24sp | 32sp | 0 | SemiBold | 区块小标题 |
titleLarge | 22sp | 28sp | 0 | SemiBold | |
titleMedium | 16sp | 24sp | 0.15sp | SemiBold | 卡片标题、列表项标题、菜单选中项 |
titleSmall | 14sp | 20sp | 0.1sp | SemiBold | 弹窗标题、空态主文案、提示条标题 |
bodyLarge | 16sp | 26sp | 0.5sp | Normal | 正文、菜单项 |
bodyMedium | 14sp | 22sp | 0.25sp | Normal | 次要正文、错误说明 |
bodySmall | 12sp | 18sp | 0.4sp | Normal | 副标题、说明文案 |
labelLarge | 14sp | 20sp | 0.1sp | Medium | 按钮文字 |
labelMedium | 12sp | 16sp | 0.5sp | Medium | 标签、小号辅助文案 |
labelSmall | 11sp | 16sp | 0.5sp | Medium | 角标 |
数字字阶 NumberStyles
三档都开了 tnum(等宽数字):
| 名称 | 基于 | 字重 | 用在哪 |
|---|---|---|---|
display | displaySmall | Bold | 资产卡余额、统计值 |
title | titleMedium | SemiBold | 列表右侧计数 |
label | labelMedium | Medium | 角标、百分比 |
要点
- 字重只走字阶,页面里不要再手写
FontWeight。 约定是:Bold(700) = 页面大标题 / 折叠标题栏;SemiBold(600) = 区块与卡片标题、headlineSmall;Medium(500) = 标签与按钮;Normal(400) = 正文。 - 会变宽度的数字必须用
NumberStyles或.tabular()。 默认是比例数字,1比8窄 —— 余额、观看次数、版本号、下载进度一变,整行就左右抖。 - 大字号收紧字距、小字号放开字距。
display*/headlineLarge是负字距,label*是正字距。这是按字号校准过的,不要覆盖。 - 行高比 M3 英文基线略大,因为中文比拉丁文高。多行中文靠这个才不挤在一起。
- 字体是系统默认(
FontFamily.Default),不内嵌第三方字体 —— 各厂商 ROM 自带的中文黑体已是现代字体,内嵌会让 APK 多出十几 MB。
已知的代码与注释不一致
Type.kt 的注释声称 headlineLarge / headlineMedium 已经从 FontWeight.Black 改成 Bold,但代码里的实际值仍是 FontWeight.Black。上表以代码为准。任何直接引用这两个 token 的组件(例如 TopTitleBar)拿到的是 Black(900);折叠标题栏和登录页大标题不受影响,因为它们是自己手写 FontWeight.Bold 的。
说明
- 「字体家族可替换、字阶与字重是骨架」:这一套和 Material 3 Expressive 的思路一致 —— 换字体只需要替换
fontFamily,其余不动。 - 刻意不用 Black(900)(
headline*两处例外,见上面的 warning):中文黑体在 900 下笔画会糊成一团,加大字重反而降低辨识度。大标题靠Bold+ 负字距就够有分量。 NumberStyles的三档是「取同名 token 再压字重」,只额外加了fontFeatureSettings = "tnum"。它们和本文件那套自定义Typography在同名字号 / 行高 / 字距上是一致的,所以两者混用不会跳。display*三档没有负字距之外的特殊处理:displayMedium/displaySmall是 0 字距,只有最大的displayLarge收 -0.25sp —— 字号越大越需要收,但不是所有大字号都需要收。