主题
图标尺寸规范
最后更新:2026-02-21 版本:v1.0 状态:✅ 强制执行
本文档定义 Reading Vocab Helper 项目的 图标尺寸规范,包括标准尺寸、各组件图标大小、颜色使用等。
📋 目录
标准图标尺寸
核心原则:使用 Material 3 标准图标尺寸
Material 3 标准尺寸
| 尺寸级别 | 数值 | 用途 | 示例 |
|---|---|---|---|
| 超小 | 16dp | 极小空间、微型指示器 | 下拉箭头、状态点 |
| 小 | 18dp | 密集列表、辅助图标 | 列表项尾部图标 |
| 按钮内 | 20dp | 按钮内图标 | FilledButton.icon |
| 标准 | 24dp | 默认图标大小 | IconButton、AppBar |
| 中等 | 28dp | 略大图标 | 重要操作图标 |
| 大 | 32dp | 导航图标 | BottomNavigationBar |
| 超大 | 36dp | 强调图标 | 空状态、成功提示 |
| 特大 | 40dp | 主要 CTA 图标 | FAB 图标 |
| 巨大 | 48dp | 启动页、空状态主图标 | 空白页插图中心 |
尺寸可视化
16dp ● 极小(下拉箭头)
18dp ● 小(密集列表)
20dp ● 按钮内
24dp ●● 标准(默认)
28dp ●● 中等
32dp ●●● 大(底部导航)
36dp ●●● 超大(强调)
40dp ●●●● 特大(FAB)
48dp ●●●● 巨大(空状态)组件图标规范
按组件类型
| 组件 | 图标大小 | 说明 |
|---|---|---|
| IconButton | 24dp(默认) | 可通过 iconSize 调整 |
| AppBar actions | 24dp | 标准导航图标 |
| AppBar leading | 24dp | 返回/菜单图标 |
| FilledButton.icon | 18-20dp | 按钮内图标略小 |
| OutlinedButton.icon | 18-20dp | 按钮内图标略小 |
| TextButton.icon | 18-20dp | 按钮内图标略小 |
| FloatingActionButton | 24dp(默认) | FAB 自动居中 |
| FloatingActionButton.large | 36dp | 大型 FAB |
| FloatingActionButton.small | 24dp | 小型 FAB |
| BottomNavigationBar | 24dp | 导航图标 |
| NavigationRail | 24dp | 侧边导航 |
| ListTile leading | 24dp | 列表项前导图标 |
| ListTile trailing | 24dp | 列表项尾部图标 |
| Chip | 18dp | 标签内图标 |
| Badge | 16dp | 徽章内图标 |
| SnackBar action | 24dp | 操作图标 |
特殊场景
| 场景 | 图标大小 | 说明 |
|---|---|---|
| 空状态插图 | 48-64dp | 主图标 |
| 成功/失败反馈 | 36-48dp | 强调图标 |
| 引导页插图 | 48-64dp | 中心图标 |
| 设置项图标 | 24dp | 与文字平齐 |
| 搜索框内图标 | 20-24dp | 搜索/清除 |
| 输入框后缀 | 20-24dp | 密码显示/清除 |
图标颜色规范
核心原则:使用 colorScheme 语义化颜色
颜色选择
| 图标类型 | 推荐颜色 | 示例 |
|---|---|---|
| 主要操作 | primary | FAB、主按钮图标 |
| 导航选中 | primary | 底部导航选中项 |
| 导航未选中 | onSurfaceVariant | 底部导航未选中项 |
| 列表项图标 | onSurfaceVariant | ListTile leading |
| 辅助图标 | onSurfaceVariant | 说明、提示 |
| 错误图标 | error | 错误提示 |
| 成功图标 | tertiary 或 green | 成功反馈 |
| 禁用图标 | onSurface.withOpacity(0.38) | 禁用状态 |
自动颜色的组件
以下组件自动使用正确的颜色,无需手动设置:
| 组件 | 自动颜色 |
|---|---|
IconButton | onSurfaceVariant |
ListTile.leading | onSurfaceVariant |
AppBar.actions | onSurface |
BottomNavigationBar | 自动选中/未选中 |
FilledButton.icon | onPrimary |
决策树:如何选择图标大小
图标位置?
├─ 按钮内部
│ ├─ FilledButton.icon → 18-20dp
│ ├─ FAB → 24dp(标准)/ 36dp(大)
│ └─ IconButton → 24dp
│
├─ 导航
│ ├─ AppBar → 24dp
│ ├─ BottomNavigationBar → 24dp
│ └─ Drawer → 24dp
│
├─ 列表/表单
│ ├─ ListTile → 24dp
│ ├─ TextField 后缀 → 20-24dp
│ └─ Chip → 18dp
│
├─ 强调/反馈
│ ├─ 成功/失败图标 → 36-48dp
│ ├─ 空状态主图标 → 48-64dp
│ └─ 引导页图标 → 48-64dp
│
└─ 辅助
├─ Badge → 16dp
├─ 下拉箭头 → 16dp
└─ 状态指示器 → 16dp代码示例
标准图标
dart
// 默认 24dp 图标
Icon(Icons.home)
// 指定大小
Icon(Icons.home, size: 24)
// 带颜色
Icon(
Icons.home,
size: 24,
color: colorScheme.onSurfaceVariant,
)IconButton
dart
// 标准 IconButton(24dp 图标,48dp 触摸区域)
IconButton(
icon: Icon(Icons.search),
onPressed: onSearch,
)
// 自定义图标大小
IconButton(
iconSize: 20,
icon: Icon(Icons.close),
onPressed: onClose,
)
// 填充样式
IconButton.filled(
icon: Icon(Icons.add),
onPressed: onAdd,
)
// 柔和填充样式
IconButton.filledTonal(
icon: Icon(Icons.edit),
onPressed: onEdit,
)按钮内图标
dart
// FilledButton 带图标(图标自动 18dp)
FilledButton.icon(
onPressed: onSave,
icon: Icon(Icons.save),
label: Text('保存'),
)
// OutlinedButton 带图标
OutlinedButton.icon(
onPressed: onCancel,
icon: Icon(Icons.close),
label: Text('取消'),
)
// 自定义图标大小
FilledButton.icon(
onPressed: onSave,
icon: Icon(Icons.save, size: 20), // 明确指定
label: Text('保存'),
)FAB
dart
// 标准 FAB(24dp 图标)
FloatingActionButton(
onPressed: onAdd,
child: Icon(Icons.add),
)
// 小型 FAB(24dp 图标)
FloatingActionButton.small(
onPressed: onAdd,
child: Icon(Icons.add),
)
// 大型 FAB(36dp 图标)
FloatingActionButton.large(
onPressed: onAdd,
child: Icon(Icons.add, size: 36),
)
// 扩展 FAB
FloatingActionButton.extended(
onPressed: onAdd,
icon: Icon(Icons.add),
label: Text('新建'),
)底部导航
dart
// BottomNavigationBar(24dp 图标)
BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.book),
label: '词汇',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '设置',
),
],
)
// NavigationBar (Material 3)
NavigationBar(
destinations: [
NavigationDestination(
icon: Icon(Icons.home_outlined),
selectedIcon: Icon(Icons.home),
label: '首页',
),
],
)列表项图标
dart
// ListTile 图标(自动 24dp)
ListTile(
leading: Icon(Icons.person),
title: Text('个人资料'),
trailing: Icon(Icons.chevron_right),
)
// 自定义图标大小
ListTile(
leading: Icon(Icons.person, size: 28),
title: Text('个人资料'),
)空状态图标
dart
// 空状态(大图标)
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.inbox_outlined,
size: 64,
color: colorScheme.onSurfaceVariant,
),
SizedBox(height: 16),
Text(
'暂无数据',
style: context.bodyLarge,
),
],
)
// 成功反馈
Icon(
Icons.check_circle,
size: 48,
color: colorScheme.primary,
)输入框图标
dart
// TextField 前缀图标
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.search, size: 24),
hintText: '搜索...',
),
)
// TextField 后缀图标
TextField(
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.clear, size: 20),
onPressed: onClear,
),
),
)反模式总结
尺寸反模式
| ❌ 错误 | ✅ 正确 | 原因 |
|---|---|---|
size: 22 | size: 20 或 24 | 非标准尺寸 |
size: 30 | size: 28 或 32 | 非标准尺寸 |
size: 25 | size: 24 或 28 | 非标准尺寸 |
size: 50 | size: 48 | 非标准尺寸 |
颜色反模式
| ❌ 错误 | ✅ 正确 | 原因 |
|---|---|---|
Colors.grey | colorScheme.onSurfaceVariant | 硬编码颜色 |
Colors.blue | colorScheme.primary | 硬编码颜色 |
Colors.red | colorScheme.error | 硬编码颜色 |
Colors.black | colorScheme.onSurface | 硬编码颜色 |
使用反模式
| ❌ 错误 | ✅ 正确 | 原因 |
|---|---|---|
| 按钮内大图标 (32dp) | 按钮内小图标 (18-20dp) | 尺寸不协调 |
| 密集列表大图标 | 密集列表小图标 (18dp) | 空间不足 |
| 导航小图标 (16dp) | 导航标准图标 (24dp) | 难以点击 |
🔴 图标容器反模式(P0 严重)
核心原则:禁止使用自定义 Container/BoxDecoration 包裹图标
Material 3 提供了专门的图标组件,不应该自定义容器来包裹图标。
| ❌ 错误做法 | ✅ 正确做法 | 场景 |
|---|---|---|
Container(decoration: BoxDecoration(...), child: Icon(...)) | IconButton.filledTonal(...) | 可点击的强调图标 |
Container(color: ..., child: Icon(...)) | IconButton.filled(...) | 可点击的主要图标 |
Container(shape: BoxShape.circle, child: Icon(...)) | CircleAvatar(child: Icon(...)) | 装饰性圆形图标 |
| 自定义圆角矩形包裹图标 | 直接使用 Icon(...) | 普通展示图标 |
错误示例:
dart
// ❌ 错误:自定义容器包裹图标
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(Icons.check, color: colorScheme.primary),
)正确示例:
dart
// ✅ 正确:可点击图标按钮
IconButton.filledTonal(
onPressed: onTap,
icon: const Icon(Icons.check),
)
// ✅ 正确:装饰性圆形图标(不可点击)
CircleAvatar(
backgroundColor: colorScheme.primaryContainer,
child: Icon(Icons.check, color: colorScheme.onPrimaryContainer),
)
// ✅ 正确:普通展示图标
Icon(Icons.check, color: colorScheme.primary)决策树:如何选择图标组件
图标是否可点击?
├─ 是 → 使用 IconButton 系列
│ ├─ 主要操作 → IconButton.filled
│ ├─ 次要操作 → IconButton.filledTonal
│ ├─ 低优先级 → IconButton.outlined
│ └─ 最低优先级 → IconButton(无背景)
│
└─ 否 → 装饰性图标
├─ 需要圆形背景 → CircleAvatar
├─ 需要徽章效果 → Badge
└─ 普通展示 → Icon(无背景)快速参考表
标准尺寸
| 尺寸 | 使用场景 |
|---|---|
| 16dp | 微型指示器、下拉箭头、Badge |
| 18dp | 密集列表、Chip |
| 20dp | 按钮内图标、输入框后缀 |
| 24dp | 默认(IconButton、AppBar、ListTile) |
| 28dp | 中等强调 |
| 32dp | 底部导航(较大设备) |
| 36dp | 强调图标、大 FAB |
| 40dp | 特大 CTA |
| 48dp | 空状态、启动页 |
组件默认尺寸
| 组件 | 默认图标大小 |
|---|---|
| IconButton | 24dp |
| FilledButton.icon | 18dp |
| FAB | 24dp |
| FAB.large | 36dp |
| BottomNavigationBar | 24dp |
| ListTile | 24dp |
| Chip | 18dp |
| AppBar | 24dp |
颜色映射
| 场景 | 颜色 |
|---|---|
| 主要操作 | primary |
| 导航选中 | primary |
| 辅助图标 | onSurfaceVariant |
| 错误图标 | error |
| 禁用图标 | onSurface.withOpacity(0.38) |
参考资料:
维护者:Reading Vocab Helper Team 问题反馈:请在项目中提 Issue