92 lines
3.4 KiB
Markdown
92 lines
3.4 KiB
Markdown
# 【Demo】Seed 色板验证页(colorSchemeSeed 原理)
|
||
|
||
> 源文件:`lib/pages/demo/seed_palette_demo.dart` | 分类:基础布局
|
||
> 一句话:所有"没写死颜色"的 Material 组件,换一个 seed 就整体变色 —— 本页就是证据。
|
||
|
||
---
|
||
|
||
## 一、这个 Demo 解决什么问题
|
||
|
||
新手经常困惑:`colorSchemeSeed` 到底有什么用?为什么有的页面换主题变色,有的不变?
|
||
|
||
答案:**MaterialApp 的 `theme.colorSchemeSeed` 会自动生成整套 ColorScheme**,
|
||
页面里**不指定颜色**的 Material 组件(FilledButton/Checkbox/Switch/进度圈/聚焦输入框等)
|
||
颜色全部取自这套色板。本页把所有"不写死颜色"的组件摆在一起,换 seed 看整体变色。
|
||
|
||
---
|
||
|
||
## 二、怎么运行 / 演示内容
|
||
|
||
```bash
|
||
flutter run # 默认品牌 → 本页所有组件 SkyBlue 蓝
|
||
flutter run --dart-define=BRAND=chucai # 换品牌 → 本页所有组件变 Red 红
|
||
```
|
||
|
||
`--dart-define` 是编译期变量,由 `core/config/app_config.dart` 读取并决定 `seedColor`。
|
||
|
||
> 对照登录页为什么不变色:登录页所有颜色写死 `Color(0xFF3B82F6)` → 永远蓝色,不随主题走。
|
||
> **写死了就不跟主题,没写死才跟** —— 这是理解主题系统的关键。
|
||
|
||
---
|
||
|
||
## 三、核心知识点(新手向)
|
||
|
||
### 1. 色板怎么生成的
|
||
```dart
|
||
ThemeData(colorSchemeSeed: seedColor)
|
||
```
|
||
Material 的 ColorScheme.fromSeed 算法从种子色推出一整套颜色:
|
||
primary / onPrimary / secondary / tertiary / error / surface 等几十个语义色。
|
||
组件默认取语义色:按钮取 primary、进度圈取 primary、Checkbox 选中取 primary……
|
||
|
||
### 2. 本页验证清单(全部未写死颜色)
|
||
- 按钮组:FilledButton / OutlinedButton / TextButton;
|
||
- Checkbox / Switch / ChoiceChip 选中态;
|
||
- CircularProgressIndicator / LinearProgressIndicator;
|
||
- TextField 聚焦边框 + 光标。
|
||
|
||
### 3. 取色值显示
|
||
```dart
|
||
String _hex(Color c) {
|
||
final v = c.toARGB32() & 0xFFFFFF; // Flutter 3.27+ 用 toARGB32 取色值
|
||
return '#${v.toRadixString(16).padLeft(6, '0').toUpperCase()}';
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 四、关键代码剖析
|
||
|
||
```dart
|
||
// 当前品牌主题(来自 AppConfig,启动时由 --dart-define 决定)
|
||
final brandTheme = AppConfig.theme;
|
||
|
||
// 展示 seed 色块 + 品牌信息
|
||
Container(
|
||
width: 56.w, height: 56.h,
|
||
decoration: BoxDecoration(color: brandTheme.seedColor, ...),
|
||
),
|
||
Text('主题 ${brandTheme.name} · seed ${_hex(brandTheme.seedColor)}'),
|
||
|
||
// 一个不写颜色的组件(示例)—— 它的颜色来自当前 seed 色板
|
||
FilledButton(onPressed: () {}, child: const Text('FilledButton')),
|
||
```
|
||
|
||
---
|
||
|
||
## 五、踩坑记录
|
||
|
||
1. **`.w/.h` 的 widget 不能 const** —— 本页 CircularProgressIndicator 外面套的 SizedBox 就踩过
|
||
(`const_eval_extension_method` 编译错误);
|
||
2. `toARGB32()` 是新 API,旧的 `.value` 已废弃;
|
||
3. 别在页面里 `Theme.of(context).colorScheme.primary` 到处取 —— 组件不写颜色才是正道;
|
||
4. `--dart-define` 是编译期常量,热重载不生效,改品牌要重新 run。
|
||
|
||
---
|
||
|
||
## 六、扩展思考
|
||
|
||
- 二级主题(页面级细节)见 [theme_demo.md](theme_demo.md);
|
||
- 想精确控制色板:`ColorScheme.fromSeed(seedColor: x, primary: y, ...)` 手动覆盖某些槽位;
|
||
- 动态切换主题(运行时换色):Theme 局部覆盖或 AnimatedTheme,不依赖 --dart-define。
|