import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:new_learn/core/config/app_config.dart'; /// ============================================================ /// 【SeedPaletteDemo】Seed 色板 —— 验证"主题 seed 是否生效"的演示页 /// /// 一、原理: /// MaterialApp 的 theme.colorSchemeSeed(来自 AppConfig.theme.seedColor) /// 会自动生成整套 ColorScheme(primary/secondary/tertiary/...)。 /// 页面里【不指定颜色】的 Material 组件,颜色全部取自这套色板: /// FilledButton/Checkbox/Switch/Radio/进度圈/聚焦输入框 等。 /// 所以换一个品牌(seed 不同),整页组件整体变色 —— 这就是 /// "seed 驱动全局 Material 色板" 的直接证明。 /// /// 二、怎么验证: /// flutter run → 本页所有组件是 SkyBlue 蓝 /// flutter run --dart-define=BRAND=chucai → 本页所有组件变 Red 红 /// /// 三、对比理解(对照登录页为什么不变色): /// 本页组件【没写死颜色】→ 跟随 seed 变; /// 登录页所有颜色写死 Color(0xFF3B82F6) 等 → 永远蓝色,不随主题走。 /// ============================================================ class SeedPaletteDemoPage extends StatefulWidget { const SeedPaletteDemoPage({super.key}); @override State createState() => _SeedPaletteDemoPageState(); } class _SeedPaletteDemoPageState extends State { final _focusController = TextEditingController(); bool _checked = true; bool _switched = true; int _chipSelected = 1; @override void dispose() { // 输入框 controller 必须在 dispose 释放(防内存泄漏) _focusController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final brandTheme = AppConfig.theme; return Scaffold( appBar: AppBar( title: const Text('Seed 色板'), centerTitle: true, ), body: ListView( padding: EdgeInsets.all(16.w), children: [ // ─── ① 当前品牌 / seed 信息卡 ─── _sectionTitle('① 当前生效的 seed'), Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12.r), border: Border.all(color: const Color(0xFFEEF1F5)), ), child: Row( children: [ // seed 色块:就是 AppConfig.theme.seedColor Container( width: 56.w, height: 56.h, decoration: BoxDecoration( color: brandTheme.seedColor, borderRadius: BorderRadius.circular(12.r), ), ), SizedBox(width: 16.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( AppConfig.appName, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: const Color(0xFF333333), ), ), SizedBox(height: 4.h), Text( '主题 ${brandTheme.name} · seed ' '${_hex(brandTheme.seedColor)}', style: TextStyle( fontSize: 12.sp, color: const Color(0xFF999999), ), ), ], ), ), ], ), ), SizedBox(height: 24.h), // ─── ② 组件区说明 ─── _sectionTitle('② 下列组件【未写死颜色】'), _tipCard('它们的颜色全部取自 colorSchemeSeed 自动生成的色板。' '跑不同品牌包,下面所有组件整体变色。'), // ─── ③ 按钮组 ─── _sectionTitle('按钮(默认取 primary)'), Row( children: [ FilledButton( onPressed: () {}, child: const Text('FilledButton'), ), SizedBox(width: 12.w), OutlinedButton( onPressed: () {}, child: const Text('OutlinedButton'), ), SizedBox(width: 12.w), TextButton( onPressed: () {}, child: const Text('TextButton'), ), ], ), SizedBox(height: 24.h), // ─── ④ 勾选 / 开关 / 选择标签 ─── _sectionTitle('勾选 / 开关 / 选择标签(选中色取自 seed 色板)'), Row( children: [ Checkbox( value: _checked, onChanged: (v) => setState(() => _checked = v!), ), const Text('Checkbox'), SizedBox(width: 24.w), Switch( value: _switched, onChanged: (v) => setState(() => _switched = v), ), SizedBox(width: 12.w), const Text('Switch'), SizedBox(width: 24.w), ChoiceChip( label: const Text('选项1'), selected: _chipSelected == 1, onSelected: (_) => setState(() => _chipSelected = 1), ), SizedBox(width: 12.w), ChoiceChip( label: const Text('选项2'), selected: _chipSelected == 2, onSelected: (_) => setState(() => _chipSelected = 2), ), ], ), SizedBox(height: 24.h), // ─── ⑤ 进度指示器 ─── _sectionTitle('进度指示器(默认取 primary)'), Row( children: [ // 注意:这里不能写 const —— .w/.h 是 ScreenUtil 扩展方法, // extension 方法不允许出现在 const 表达式里(const_eval_extension_method) SizedBox( width: 32.w, height: 32.h, child: const CircularProgressIndicator(strokeWidth: 3), ), SizedBox(width: 20.w), Expanded( child: ClipRRect( borderRadius: BorderRadius.circular(4.r), child: const LinearProgressIndicator(value: 0.6), ), ), ], ), SizedBox(height: 24.h), // ─── ⑥ 聚焦输入框 ─── _sectionTitle('聚焦输入框(边框取 primary)'), _tipCard('点进输入框,光标 + 聚焦边框颜色 = 当前 seed 主色。'), TextField( controller: _focusController, decoration: InputDecoration( labelText: '点击聚焦看边框颜色', border: const OutlineInputBorder(), ), ), SizedBox(height: 24.h), // ─── ⑦ 验证提示 ─── _sectionTitle('⑦ 怎么看到变化'), Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: const Color(0xFFE8F0FE), borderRadius: BorderRadius.circular(12.r), ), child: Text( 'flutter run --dart-define=BRAND=chucai\n' '→ 本页所有组件变成红色系。\n\n' 'flutter run(默认爱学蝶变)\n' '→ 恢复 SkyBlue 蓝色系。', style: TextStyle(fontSize: 13.sp, color: const Color(0xFF3B82F6)), ), ), ], ), ); } /// 段落小标题 Widget _sectionTitle(String text) { return Padding( padding: EdgeInsets.only(bottom: 10.h), child: Text( text, style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: const Color(0xFF333333), ), ), ); } /// 灰色提示卡 Widget _tipCard(String text) { return Container( padding: EdgeInsets.all(12.w), margin: EdgeInsets.only(bottom: 12.h), decoration: BoxDecoration( color: const Color(0xFFF7F8FA), borderRadius: BorderRadius.circular(10.r), ), child: Text( text, style: TextStyle(fontSize: 12.sp, color: const Color(0xFF666666)), ), ); } /// Color → #RRGGBB 显示(Flutter 3.27+ 用 toARGB32 取色值) String _hex(Color c) { final v = c.toARGB32() & 0xFFFFFF; return '#${v.toRadixString(16).padLeft(6, '0').toUpperCase()}'; } }