Skip to content

Material 3 设计系统规范

最后更新:2026-02-21 版本:v1.2 状态:✅ 强制执行

本文档定义 Reading Vocab Helper 项目的 Material 3 设计系统,包括文本、颜色、图标、间距等基础规范和设计原则。

如需查看具体组件的详细实战指南,请参考:


📋 目录

  1. 文本样式最佳实践
  2. 字体尺寸和字重对应表 🆕
  3. 图标使用规范
  4. 图标尺寸规范 🆕
  5. 颜色系统规范
  6. 间距和布局规范
  7. 组件使用规范
  8. Claude自动化执行机制
  9. 反模式总结

文本样式最佳实践

核心原则:简洁优先 + 主题优先

核心理念

本章节定义 文本样式(fontSize、fontWeight、textStyle) 的使用原则:

  • 90%的文本使用默认样式(bodyMedium = 14sp, w400, onSurface)
  • 只在需要时设置 fontSize/fontWeight(建立视觉层级)
  • 颜色使用 colorScheme(详见颜色系统规范章节)
  • 避免硬编码(Colors.blue → colorScheme.primary)

三级简化策略

Level 0:不设置 fontSize(优先考虑,~87%场景)

dart
Text('这是普通正文')
Text('列表项描述')
Text('卡片内容')
  • 默认效果:14sp, w400, onSurface 色(= bodyMedium)
  • 适用场景:普通正文、列表项内容、卡片描述、对话框内容
  • 何时使用:标准大小、正常粗细的所有文本

Level 1:只设置必要的样式(常见,~45%场景)

dart
// 只改颜色(使用主题颜色,推荐)✅
Text('提示', style: TextStyle(
  color: Theme.of(context).colorScheme.onSurfaceVariant
))

Text('强调', style: TextStyle(
  color: Theme.of(context).colorScheme.tertiary
))

// 只改粗细
Text('加粗', style: TextStyle(fontWeight: FontWeight.w600))

// 同时改颜色和粗细
Text('重要提示', style: TextStyle(
  color: Theme.of(context).colorScheme.error,
  fontWeight: FontWeight.w600,
))
  • 适用场景:普通大小,但需要特殊颜色或粗细
  • 推荐:使用主题 colorScheme 而非硬编码颜色
  • 避免冗余bodyMedium.copyWith(color: xxx)TextStyle(color: xxx)

Level 2:使用语义样式(建立视觉层级,2%场景)

dart
// 大标题
Text('页面标题', style: context.headlineSmall)

// 节标签(或用 SectionLabel 组件)
SectionLabel('Definition')

// 按钮文字
Text('开始复习', style: context.bodyLarge)

// 小号说明
Text('次要信息', style: context.bodySmall)
  • Extension Methods 简化context.bodyLarge 替代 Theme.of(context).textTheme.bodyLarge
  • 语义组件封装SectionLabel('标签') 用于节标题
  • 适用场景:需要不同大小来建立视觉层级

Level 3:完全自定义(罕见场景,<1%)

dart
Text('特殊需求', style: context.bodyMedium.copyWith(
  color: Colors.blue,
  fontWeight: FontWeight.w600,
))

决策树:是否需要设置样式?

开始写 Text()

  是否需要不同的大小?
    ├─ 否(普通大小14sp)→ 是否需要特殊颜色/粗细?
    │                      ├─ 否 → ✅ 不写 style(默认 bodyMedium)
    │                      └─ 是 → ✅ TextStyle(color: colorScheme.xxx)
    │                             或 TextStyle(fontWeight: xxx)

    └─ 是(需要更大/更小)→ ✅ 使用语义样式
                           ├─ 大标题 → context.headlineSmall
                           ├─ 按钮文字 → context.bodyLarge
                           └─ 小号说明 → context.bodySmall

关键原则

  1. 默认优先 - 普通大小、黑色、正常粗细 → 不写 style
  2. 主题颜色 - 使用 colorScheme.tertiary 而非 Colors.blue
  3. 语义大小 - 使用 headlineSmall 而非 fontSize: 18

常见模式快速参考

文本类型推荐做法理由
普通正文Text('内容')默认 bodyMedium
次要文本Text('提示', style: TextStyle(color: colorScheme.onSurfaceVariant))使用主题色 ✅
强调文本Text('强调', style: TextStyle(color: colorScheme.tertiary))使用主题色 ✅
页面标题Text('标题', style: context.headlineSmall)语义大小
节标签SectionLabel('标签')统一组件
按钮文字Text('按钮', style: context.bodyLarge)稍大易点
小号说明Text('说明', style: context.bodySmall)12sp 次要
错误提示Text('错误', style: TextStyle(color: colorScheme.error))使用主题色 ✅
动态强调copyWith(fontWeight: isSelected ? w600 : w400)状态切换

避免过度设计 ❌

dart
// ❌ 错误:冗余的 bodyMedium(fontSize 重复)
Text('内容', style: Theme.of(context).textTheme.bodyMedium)
// ✅ 正确:直接使用默认
Text('内容')

// ❌ 错误:只改颜色却引用整个 bodyMedium
Text('提示', style: Theme.of(context).textTheme.bodyMedium?.copyWith(
  color: Theme.of(context).colorScheme.onSurfaceVariant,
))
// ✅ 正确:只写需要的
Text('提示', style: TextStyle(
  color: Theme.of(context).colorScheme.onSurfaceVariant,
))

// ⚠️ 不推荐:硬编码颜色(不跟随主题)
Text('提示', style: TextStyle(color: Colors.grey))
// ✅ 推荐:使用主题颜色(自动适配浅色/深色模式)
Text('提示', style: TextStyle(
  color: Theme.of(context).colorScheme.onSurfaceVariant,
))

主题颜色 vs 硬编码颜色 ⭐ 重要

使用主题颜色(推荐)

dart
// ✅ 语义清晰、主题适配、全局一致
color: Theme.of(context).colorScheme.tertiary       // 第三强调色
color: Theme.of(context).colorScheme.onSurfaceVariant  // 次要文本色
color: Theme.of(context).colorScheme.error          // 错误色

硬编码颜色(需谨慎)

dart
// ❌ 不跟随主题、可能在深色模式下不可见
color: Colors.blue
color: Colors.grey.shade600
color: Color(0xFF123456)

何时可以使用硬编码颜色

  • 品牌色(如公司 Logo)
  • 特殊视觉效果(如渐变、动画)
  • 临时调试

其他情况都应使用主题颜色!

工具支持

  • Extension Methodslib/core/extensions/text_style_extensions.dart
    • 简化语法:context.bodyLarge 替代 Theme.of(context).textTheme.bodyLarge
  • 语义组件lib/shared/presentation/widgets/text/section_label.dart
    • SectionLabel('Definition') 专用于节标题

最佳实践总结

  1. fontSize 优先级

    • 🥇 不设置(默认 bodyMedium = 14sp)→ 87%场景
    • 🥈 使用语义样式(headlineSmall, bodyLarge)→ 13%场景
    • 🚫 避免硬编码(fontSize: 18)
  2. 颜色优先级

    • 🥇 不设置(默认 onSurface = 黑色)→ 55%场景
    • 🥈 使用主题颜色(colorScheme.tertiary)→ 推荐!
    • 🚫 避免硬编码(Colors.blue)→ 需谨慎
  3. fontWeight 优先级

    • 🥇 不设置(默认 w400 或 w600)→ 78%场景
    • 🥈 有意修改(加粗/加重)→ 22%场景

核心原则:先不写 style,运行看效果,需要调整时:

  • 改大小 → 用语义样式(context.headlineSmall)
  • 改颜色 → 用主题颜色(colorScheme.tertiary)
  • 改粗细 → 用 TextStyle(fontWeight: xxx)

保持简洁,遵循主题!


字体尺寸和字重对应表 🆕

Material 3 标准 fontSize

TextStylefontSize典型用途示例
displayLarge57sp超大展示文字启动页标题
displayMedium45sp大展示文字空状态标题
displaySmall36sp小展示文字页面大标题
headlineLarge32sp大标题章节标题
headlineMedium28sp中标题详情页标题
headlineSmall24sp小标题卡片标题
titleLarge22sp大标题AppBar 标题
titleMedium16sp中标题ListTile 标题
titleSmall14sp小标题Tab 标签
bodyLarge16sp大正文主要内容
bodyMedium14sp中正文(默认)普通文本
bodySmall12sp小正文辅助说明
labelLarge14sp大标签按钮文字
labelMedium12sp中标签导航标签
labelSmall11sp小标签徽章文字

Material 3 标准 fontWeight

FontWeight数值用途示例
FontWeight.w100Thin极细(少用)装饰文字
FontWeight.w200ExtraLight超轻(少用)装饰文字
FontWeight.w300Light次要说明
FontWeight.w400Regular(默认)正文bodyMedium
FontWeight.w500Medium中等强调文字
FontWeight.w600SemiBold半粗标题
FontWeight.w700Bold粗体重要标题
FontWeight.w800ExtraBold超粗(少用)特殊强调
FontWeight.w900Black黑体(少用)特殊设计

常用组合速查

场景fontSizefontWeight示例代码
页面大标题24spw600headlineSmall
卡片标题16spw500titleMedium
按钮文字14spw500labelLarge
普通正文14spw400bodyMedium(默认)
辅助说明12spw400bodySmall
强调文字14spw600bodyMedium + w600
错误提示12spw400bodySmall + error

代码示例

dart
// ✅ 使用语义化样式(推荐)
Text('标题', style: context.headlineSmall)
Text('正文', style: context.bodyMedium)
Text('说明', style: context.bodySmall)

// ✅ 需要修改时,最小化设置
Text('强调', style: TextStyle(fontWeight: FontWeight.w600))
Text('错误', style: TextStyle(color: colorScheme.error))

// ❌ 避免硬编码完整样式
Text('标题', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600))

图标使用规范

核心原则:使用语义化颜色 + 避免自定义背景

图标颜色使用规范

图标类型推荐颜色使用场景默认行为
主要操作图标primaryFAB、主按钮图标⚠️ 需手动设置
导航图标onSurfaceAppBar、BottomNavigationBar✅ 部分自动
列表项辅助图标onSurfaceVariantSettings、ListTile✅ ListTile 自动
次要图标onSurfaceVariant提示、说明⚠️ 需手动设置
强调图标primary选中状态、CTA⚠️ 需手动设置
错误/警告图标error错误提示⚠️ 需手动设置

Widget 默认颜色行为

✅ 自动使用正确颜色的 Widget

dart
// IconButton 默认 onSurfaceVariant
IconButton(
  icon: Icon(Icons.settings),  // ✅ 自动灰色
  onPressed: () {},
)

// ListTile 默认 onSurfaceVariant
ListTile(
  leading: Icon(Icons.settings),  // ✅ 自动灰色
  title: Text('Settings'),
)

⚠️ 需要手动设置颜色的场景

dart
// 裸 Icon 默认 onSurface(太深)
Icon(Icons.info)  // ❌ 黑色,应手动设置

// 自定义布局中的图标
Row(
  children: [
    Icon(Icons.star, color: colorScheme.onSurfaceVariant),  // ✅
    Text('收藏'),
  ],
)

避免过度设计 ❌

❌ 错误:iOS 风格的图标背景

dart
// Settings 页面当前问题(已识别需修复)
Container(
  decoration: BoxDecoration(
    color: colorScheme.onSurface,  // ❌ 黑色背景
    shape: BoxShape.circle,
  ),
  child: Icon(icon, color: Colors.white),  // ❌ 硬编码白色
)

✅ 正确:直接使用主题色图标

dart
// 方案1:最简洁(推荐)
Icon(icon, color: colorScheme.onSurfaceVariant)

// 方案2:如需背景,使用主题色容器
Container(
  padding: const EdgeInsets.all(8),
  decoration: BoxDecoration(
    color: colorScheme.primaryContainer,
    borderRadius: BorderRadius.circular(8),  // 圆角矩形
  ),
  child: Icon(icon, color: colorScheme.onPrimaryContainer),
)

特殊场景例外

合理使用硬编码颜色的场景

  1. 相机/全屏查看器:黑色背景 → 白色图标
  2. 数据可视化:图表图例色块
  3. 品牌元素:Logo、特定品牌色

其他场景都应使用主题颜色!

快速决策树

需要显示图标

使用 IconButton 或 ListTile?
    ├─ 是 → ✅ 不设置 color(自动正确)
    └─ 否 → 这是什么类型的图标?
           ├─ 主要操作 → color: colorScheme.primary
           ├─ 导航图标 → color: colorScheme.onSurface
           ├─ 辅助图标 → color: colorScheme.onSurfaceVariant
           └─ 错误提示 → color: colorScheme.error

常见模式快速参考

场景推荐代码
FAB 图标Icon(Icons.add, color: colorScheme.onPrimary)
AppBar 返回Icon(Icons.arrow_back)IconButton(...)
Settings 列表项Icon(Icons.settings, color: colorScheme.onSurfaceVariant)
错误提示Icon(Icons.error, color: colorScheme.error)
成功提示Icon(Icons.check_circle, color: Colors.green) ⚠️

参考资料

保持简洁,遵循主题!


图标尺寸规范 🆕

标准图标尺寸

尺寸数值用途
超小16dp下拉箭头、Badge
18dpChip、密集列表
按钮内20dpButton.icon
标准24dpIconButton、AppBar、ListTile
中等28dp略大图标
32dp底部导航
超大36dp强调图标、大 FAB
特大40dp主要 CTA
巨大48dp空状态主图标

组件默认图标大小

组件默认大小
IconButton24dp
FilledButton.icon18dp
FAB24dp
FAB.large36dp
BottomNavigationBar24dp
ListTile24dp
AppBar24dp
Chip18dp

详细规范

完整的图标尺寸规范请查看:icon-size-guide.md


颜色系统规范

核心原则:永远使用 colorScheme,避免硬编码颜色

颜色角色系统

Material 3 采用语义化颜色角色系统,每个颜色都有明确的用途:

颜色角色用途典型场景示例
primary主要操作和强调FAB、主要按钮、选中状态colorScheme.primary
onPrimaryprimary 上的文本/图标白色文本在蓝色按钮上colorScheme.onPrimary
secondary次要操作次要按钮、筛选器colorScheme.secondary
tertiary补充强调标签、小图标、辅助操作colorScheme.tertiary
error错误状态错误提示、删除按钮colorScheme.error
surface卡片/容器背景Card、BottomSheet、DialogcolorScheme.surface
onSurfacesurface 上的主要文本标题、正文colorScheme.onSurface
onSurfaceVariantsurface 上的次要文本说明文字、图标、边框colorScheme.onSurfaceVariant
outline边框和分隔线TextField 边框、DividercolorScheme.outline
surfaceContainerHighest最高层级容器输入框背景、菜单背景colorScheme.surfaceContainerHighest

决策树:如何选择颜色

需要设置颜色?
├─ 文本/图标
│  ├─ 主要内容(标题、正文) → onSurface(默认,通常不设置)
│  ├─ 次要内容(说明、辅助) → onSurfaceVariant
│  ├─ 主要操作 → primary
│  ├─ 错误提示 → error
│  └─ 禁用状态 → onSurface.withOpacity(0.38)

├─ 背景/容器
│  ├─ 页面背景 → scaffoldBackgroundColor(默认)
│  ├─ 卡片/弹窗 → surface
│  ├─ 选中容器 → primaryContainer
│  ├─ 输入框背景 → surfaceContainerHighest
│  └─ 错误容器 → errorContainer

└─ 边框/分隔线
   ├─ 标准边框 → outline
   ├─ 输入框边框 → outline(未聚焦)/ primary(聚焦)
   └─ 分隔线 → outline.withOpacity(0.12)

三级规范

Level 1:100%主题色(推荐,~85%场景)

dart
// ✅ 正确:使用 colorScheme
Container(
  color: colorScheme.surface,
  child: Text(
    'Title',
    style: TextStyle(color: colorScheme.onSurface),
  ),
)

Icon(Icons.info, color: colorScheme.primary)

Level 2:主题色 + 透明度调整(谨慎使用,~13%场景) ⚠️

dart
// ⚠️ 可接受:基于主题色调整透明度
Container(
  color: colorScheme.primary.withOpacity(0.1),  // 淡背景
)

Text(
  'Disabled',
  style: TextStyle(color: colorScheme.onSurface.withOpacity(0.38)),
)

Level 3:硬编码颜色(禁止,只在极特殊情况)

dart
// ❌ 错误:硬编码颜色
Container(color: Colors.blue)  // 不适配深色模式
Text('Error', style: TextStyle(color: Color(0xFFFF0000)))  // 不语义化

常见场景快速参考

场景推荐颜色示例代码
卡片背景surfaceContainer(color: colorScheme.surface)
卡片标题onSurface(默认)Text('Title')TextStyle(color: colorScheme.onSurface)
卡片说明文字onSurfaceVariantTextStyle(color: colorScheme.onSurfaceVariant)
主要按钮primaryElevatedButton(自动使用)
次要按钮secondaryFilledButton.tonal(自动使用)
文本按钮primaryTextButton(自动使用)
错误提示errorTextStyle(color: colorScheme.error)
成功提示tertiaryprimaryTextStyle(color: colorScheme.tertiary)
边框outlineBorderSide(color: colorScheme.outline)
分隔线outline.withOpacity(0.12)Divider(color: colorScheme.outline.withOpacity(0.12))
选中状态背景primaryContainerContainer(color: colorScheme.primaryContainer)
选中状态文字onPrimaryContainerTextStyle(color: colorScheme.onPrimaryContainer)

⚠️ 反模式和常见错误

dart
// ❌ 错误示例
Colors.blue                    // 硬编码,不适配深色模式
Color(0xFF2196F3)             // 硬编码,不语义化
Colors.grey[600]              // 不语义化
Theme.of(context).primaryColor  // 已废弃,使用 colorScheme.primary

// ✅ 正确示例
colorScheme.primary           // 语义化,自动适配主题
colorScheme.onSurfaceVariant  // 语义化,自动适配主题
colorScheme.outline           // 语义化,自动适配主题

特殊场景例外

例外1:品牌色强制要求

dart
// 仅当品牌指南明确要求固定色值时使用
const brandBlue = Color(0xFF1976D2);  // 必须在 theme_config.dart 中定义

例外2:数据可视化图表

dart
// 图表需要多种区分色时,仍优先使用 colorScheme 扩展
final chartColors = [
  colorScheme.primary,
  colorScheme.secondary,
  colorScheme.tertiary,
  colorScheme.error,  // 作为最后手段
];

参考资料


间距和布局规范

核心原则:使用 4dp 倍数,遵循视觉层次

标准间距系统

Material 3 采用4dp 基准网格系统

间距名称数值用途示例
xxs4dp紧密元素间距图标与文字间距、内联标签间距
xs8dp相关元素间距列表项内部元素、表单字段内部
sm12dp小组件间距按钮组内部间距、小卡片内边距
md16dp标准间距(最常用)页面水平边距、卡片内边距、段落间距
lg24dp大组件间距Section 之间、大卡片间距
xl32dp页面级间距页面顶部间距、大标题下方间距
xxl48dp超大间距空状态图标与文字、启动页元素

决策树:如何选择间距

需要设置间距?
├─ 水平方向
│  ├─ 页面左右边距 → 16dp (md)
│  ├─ 卡片内容左右边距 → 16dp (md)
│  ├─ 列表项左右边距 → 16dp (md)
│  ├─ 图标与文字间距 → 8dp (xs) 或 12dp (sm)
│  └─ 按钮组内部间距 → 8dp (xs) 或 12dp (sm)

├─ 垂直方向
│  ├─ Section 标题上方 → 24dp (lg) 或 32dp (xl)
│  ├─ Section 标题下方 → 12dp (sm)
│  ├─ 卡片之间 → 16dp (md)
│  ├─ 列表项之间 → 12dp (sm) 或 16dp (md)
│  ├─ 段落之间 → 16dp (md)
│  └─ 页面顶部/底部 → 16dp (md) 或 24dp (lg)

└─ 内边距 (Padding)
   ├─ 卡片内边距 → 16dp (md)
   ├─ 按钮内边距 → 水平 16dp, 垂直 8dp
   ├─ Dialog 内边距 → 24dp (lg)
   └─ BottomSheet 内边距 → 水平 16dp, 垂直 24dp

项目标准间距常量

建议在项目中定义常量(可选,但推荐):

dart
// lib/config/spacing_config.dart
class Spacing {
  static const double xxs = 4;
  static const double xs = 8;
  static const double sm = 12;
  static const double md = 16;  // 最常用
  static const double lg = 24;
  static const double xl = 32;
  static const double xxl = 48;
}

// 使用示例
Padding(
  padding: EdgeInsets.all(Spacing.md),  // 16dp
  child: Column(
    spacing: Spacing.sm,  // 12dp (Flutter 3.16+)
    children: [...],
  ),
)

常见场景快速参考

场景推荐间距示例代码
页面水平边距16dpEdgeInsets.symmetric(horizontal: 16)
页面顶部间距16dp + statusBarEdgeInsets.only(top: MediaQuery.of(context).padding.top + 16)
Card 内边距16dpEdgeInsets.all(16)
ListTile 内边距水平16dp, 垂直12dpEdgeInsets.symmetric(horizontal: 16, vertical: 12)
图标与文字间距8dp 或 12dpSizedBox(width: 8)
Section 标题间距上24dp, 下12dpEdgeInsets.only(top: 24, bottom: 12)
按钮组间距8dp 或 12dpRow(spacing: 8, children: [...])
卡片之间间距16dpSizedBox(height: 16)

⚠️ 反模式和常见错误

dart
// ❌ 错误示例
Padding(padding: EdgeInsets.all(15))    // 非4倍数
SizedBox(height: 10)                    // 非4倍数
EdgeInsets.symmetric(horizontal: 20, vertical: 14)  // 混用非标准值

// ✅ 正确示例
Padding(padding: EdgeInsets.all(16))    // 4倍数
SizedBox(height: 12)                    // 4倍数
EdgeInsets.symmetric(horizontal: 16, vertical: 12)  // 标准值

响应式间距(可选)

dart
// 大屏设备可适当增加间距
final horizontalPadding = MediaQuery.of(context).size.width > 600 ? 24.0 : 16.0;

参考资料


组件使用规范

核心原则:优先使用 Material 3 组件,让组件自动处理样式

常用组件规范

1. 按钮 (Buttons)

快速参考

组件用途自动样式示例
FilledButton主要操作(高强调)primary 背景 + onPrimary 文字保存、提交、确认
FilledButton.tonal次要操作(中强调)secondaryContainer 背景编辑、下一步
OutlinedButton备选操作(低强调)透明背景 + outline 边框取消、返回
TextButton最低优先级操作透明背景 + primary 文字跳过、了解更多
IconButton工具栏操作自动使用 onSurfaceVariant搜索、设置
FloatingActionButton主要浮动操作primary 背景 + onPrimary 图标添加、拍照

📖 详细规范:查看 按钮样式规范

  • 完整的代码示例和模板
  • 详细的布局规范(高度/宽度/间距)
  • 常见错误对比和修复方案
  • 圆角统一规范(12px)

✅ 推荐用法(让组件自动处理颜色):

dart
FilledButton(
  onPressed: () {},
  child: Text('保存'),  // 自动使用 onPrimary 颜色
)

FilledButton.tonal(
  onPressed: () {},
  child: Text('编辑'),  // 自动使用 onSecondaryContainer 颜色
)

IconButton(
  icon: Icon(Icons.search),  // 自动使用 onSurfaceVariant 颜色
  onPressed: () {},
)

❌ 不推荐(手动设置颜色):

dart
// ❌ 多余的颜色设置
FilledButton(
  onPressed: () {},
  style: ButtonStyle(
    backgroundColor: MaterialStateProperty.all(colorScheme.primary),  // 多余
  ),
  child: Text('保存', style: TextStyle(color: colorScheme.onPrimary)),  // 多余
)

2. 卡片和容器 (Cards & Containers)

组件用途自动样式示例
Card内容容器surface 背景 + elevation + 圆角列表项、详情卡片
Container自定义容器需手动设置 color: colorScheme.surface自定义卡片
ListTile列表项自动 padding + 点击效果设置列表、导航列表

✅ 推荐用法

dart
Card(
  child: ListTile(
    leading: Icon(Icons.book),  // 自动使用 onSurfaceVariant
    title: Text('书名'),  // 自动使用 onSurface
    subtitle: Text('100 words'),  // 自动使用 onSurfaceVariant
  ),
)

3. AppBar 和导航 (AppBar & Navigation)

组件用途自动样式示例
AppBar标准顶栏surface 背景 + onSurface 文字页面标题栏
BottomNavigationBar底部导航自动使用 primary(选中)/ onSurfaceVariant(未选中)主导航
NavigationRail侧边导航同上平板侧边导航

✅ 推荐用法

dart
AppBar(
  title: Text('书籍列表'),  // 自动使用 onSurface
  actions: [
    IconButton(
      icon: Icon(Icons.search),  // 自动使用 onSurface
      onPressed: () {},
    ),
  ],
)

4. 输入组件 (Input)

组件用途自动样式注意事项
TextField文本输入outline 边框 + onSurface 文字聚焦时边框自动变 primary
Switch开关primary(开启)/ outline(关闭)需设置 activeColorcolorScheme.primary
Checkbox复选框同上自动使用主题色
Radio单选框同上自动使用主题色

✅ 推荐用法

dart
TextField(
  decoration: InputDecoration(
    labelText: '书名',  // 自动使用 onSurfaceVariant
    hintText: '请输入书名',  // 自动使用 onSurfaceVariant
  ),
)

Switch(
  value: value,
  onChanged: (v) {},
  activeColor: colorScheme.primary,  // 需手动设置
)

5. 对话框和弹窗 (Dialogs & Sheets)

快速参考

组件用途自动样式示例
AlertDialog警告对话框surface 背景 + 28dp 圆角确认删除、错误提示
BottomSheet底部弹窗surface 背景 + 顶部圆角分组选择、操作菜单
SnackBar底部提示条inverseSurface 背景 + onInverseSurface 文字操作反馈

📖 详细规范:查看 对话框样式规范

  • 完整的使用场景和示例
  • 详细的代码模板
  • 按钮布局规范
  • 圆角统一规范(28px)

✅ 推荐用法

dart
AlertDialog(
  title: Text('确认删除'),  // 自动使用 onSurface
  content: Text('删除后无法恢复'),  // 自动使用 onSurfaceVariant
  actions: [
    TextButton(
      onPressed: () {},
      child: Text('取消'),
    ),
    FilledButton(
      onPressed: () {},
      child: Text('删除'),
    ),
  ],
)

组件选择决策树

需要交互组件?
├─ 操作按钮
│  ├─ 主要操作(1个) → FilledButton
│  ├─ 次要操作(1-2个) → FilledButton.tonal
│  ├─ 取消/返回 → OutlinedButton 或 TextButton
│  └─ 工具栏操作 → IconButton

├─ 容器
│  ├─ 标准卡片 → Card(自动样式)
│  ├─ 列表项 → ListTile(自动样式)
│  └─ 自定义容器 → Container(color: colorScheme.surface)

├─ 输入
│  ├─ 文本输入 → TextField(自动样式)
│  ├─ 开关 → Switch(需设置 activeColor)
│  └─ 选择 → Checkbox / Radio(自动样式)

└─ 反馈
   ├─ 确认/警告 → AlertDialog
   ├─ 选择菜单 → BottomSheet
   └─ 操作反馈 → SnackBar

⚠️ 反模式和常见错误

dart
// ❌ 错误:手动构建按钮样式
Container(
  decoration: BoxDecoration(
    color: colorScheme.primary,
    borderRadius: BorderRadius.circular(8),
  ),
  child: InkWell(
    onTap: () {},
    child: Padding(
      padding: EdgeInsets.all(16),
      child: Text('按钮', style: TextStyle(color: colorScheme.onPrimary)),
    ),
  ),
)

// ✅ 正确:使用标准组件
FilledButton(
  onPressed: () {},
  child: Text('按钮'),
)

// ❌ 错误:手动设置已有的默认颜色
ListTile(
  leading: Icon(Icons.book, color: colorScheme.onSurfaceVariant),  // 多余
  title: Text('书名', style: TextStyle(color: colorScheme.onSurface)),  // 多余
)

// ✅ 正确:让组件自动处理
ListTile(
  leading: Icon(Icons.book),
  title: Text('书名'),
)

参考资料


Claude自动化执行机制

目标:让 Claude 自动遵循 Material 3 规范,并在用户提出非规范需求时给出建议

工作流程

用户提出需求

Claude 分析需求类型
  ├─ 符合 Material 3 规范 → 直接实施
  ├─ 可用 Material 3 替代 → 提供建议 + 等待用户确认
  └─ 必须自定义(品牌要求) → 提醒潜在问题 + 实施

决策矩阵

用户需求Claude 响应示例
"按钮改成蓝色"🔄 提供 Material 3 建议"建议使用 FilledButton(自动使用主题 primary 色),而不是硬编码蓝色。这样可以自动适配深色模式。是否采用?"
"字体大小改成 15sp"🔄 提供语义化建议"Material 3 没有 15sp 标准尺寸。建议使用 bodyLarge(16sp)或 bodyMedium(14sp)。您希望用哪一个?"
"图标改成灰色"🔄 提供主题色建议"建议使用 colorScheme.onSurfaceVariant(自动适配主题),而不是硬编码灰色。是否采用?"
"卡片圆角改成 20dp"⚠️ 提醒后实施"Material 3 标准圆角为 12dp。如需自定义为 20dp,会与系统风格不一致。确认继续?"
"品牌要求主色必须是 #1976D2"✅ 引导到正确位置"了解。建议在 theme_config.dart 中统一定义,然后通过 colorScheme.primary 使用,而不是在代码中硬编码。这样便于维护。"
"删除按钮背景改成红色"✅ 符合规范(错误状态)"使用 colorScheme.error 表示危险操作是 Material 3 推荐做法。✅"

Claude 响应模板

模板 1:建议 Material 3 替代方案

⚠️ Material 3 规范建议

您的需求:【用户原始需求】
建议方案:【Material 3 标准方案】

理由:
- ✅ 自动适配深色模式
- ✅ 保持系统一致性
- ✅ 减少维护成本

是否采用建议方案?

模板 2:自定义需求确认

⚠️ 自定义需求确认

您的需求:【用户原始需求】
影响:
- ⚠️ 与 Material 3 标准不一致(标准值:XXX)
- ⚠️ 可能在深色模式下效果不佳
- ⚠️ 增加维护成本

如需继续,建议:
- 定义在 theme_config.dart 而非硬编码
- 添加注释说明原因

是否确认继续?

模板 3:引导到正确实现位置

✅ 需求合理,建议实施位置

您的需求:【用户原始需求】
推荐实施方式:
1. 在 `theme_config.dart` 中定义常量
2. 通过 `colorScheme` 或 `textTheme` 引用
3. 避免在组件中硬编码

这样做的好处:
- ✅ 集中管理,便于修改
- ✅ 保持一致性
- ✅ 易于测试和维护

是否采用此方式?

自动检查清单(Claude 内部使用)

每次实施前,Claude 应自问:

  • [ ] 是否使用了 colorScheme 而非 Colors.xxx
  • [ ] 是否使用了 textTheme 而非硬编码 fontSize
  • [ ] 是否使用了 Material 3 标准组件而非手动构建?
  • [ ] 是否使用了 4dp 倍数的间距?
  • [ ] 是否让组件自动处理默认样式(而非手动设置)?
  • [ ] 如果必须自定义,是否在 theme_config.dart 中定义?

实施优先级

  1. P0(必须遵守)

    • 永远不硬编码 Colors.xxx,必须使用 colorScheme
    • 永远不硬编码 fontSize,必须使用 textTheme 或不设置
  2. P1(强烈推荐)

    • 使用 Material 3 标准组件而非手动构建
    • 使用 4dp 倍数间距
    • 让组件自动处理默认样式
  3. P2(最佳实践)

    • theme_config.dart 中集中定义自定义值
    • 使用语义化命名(如 primaryAction 而非 blueButton

Claude 学习建议

每次会话开始时,Claude 应:

  1. 查看 CLAUDE.md 中的 Material 3 规范引用
  2. 检查项目 theme_config.dart 中定义的颜色和文本样式
  3. 在实施前对照本文档的决策矩阵

反模式总结

所有需要避免的错误模式汇总

颜色反模式

❌ 错误✅ 正确原因
Colors.bluecolorScheme.primary不适配深色模式
Color(0xFF2196F3)colorScheme.primary不语义化
Colors.grey[600]colorScheme.onSurfaceVariant不语义化
Theme.of(context).primaryColorcolorScheme.primary已废弃

文本样式反模式

❌ 错误✅ 正确原因
fontSize: 15bodyLargebodyMedium非标准尺寸
fontSize: 14, fontWeight: w400不设置(默认)重复默认值
textTheme.bodyMedium.copyWith(color: xxx)TextStyle(color: xxx)不必要的 copyWith

间距反模式

❌ 错误✅ 正确原因
EdgeInsets.all(15)EdgeInsets.all(16)非4倍数
SizedBox(height: 10)SizedBox(height: 8)12非4倍数

组件反模式

❌ 错误✅ 正确原因
手动构建按钮(Container + InkWell)FilledButton重复造轮子
Icon(..., color: colorScheme.onSurfaceVariant) 在 ListTile 中Icon(...)ListTile 自动设置
Switch(value: v, onChanged: null)Switch(value: v, onChanged: (v) {})activeColor 需设置

维护者:Reading Vocab Helper Team 问题反馈:请在项目中提 Issue 最后更新:2026-01-18