Files
App.K12.Student.Miniapp_Flu…/lib/pages/demo/seed_palette_demo.dart
T
2026-09-04 15:22:20 +08:00

258 lines
8.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<SeedPaletteDemoPage> createState() => _SeedPaletteDemoPageState();
}
class _SeedPaletteDemoPageState extends State<SeedPaletteDemoPage> {
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()}';
}
}