07_主题与样式
Flutter 主题系统和样式管理
Flutter 没有独立的 CSS 文件,样式通过 ThemeData 全局配置,通过 Widget 属性局部覆盖。
ThemeData 全局主题
MaterialApp(
theme: ThemeData(
useMaterial3: true, // 启用 Material 3(2022 之后推荐)
// 颜色方案:从种子色自动生成完整调色板(类似 Tailwind CSS 色板)
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
),
// 全局字体
fontFamily: 'Noto Sans SC',
// 文字主题(类似 CSS typography 规范)
textTheme: const TextTheme(
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w600),
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w600),
bodyLarge: TextStyle(fontSize: 16, height: 1.6),
bodyMedium: TextStyle(fontSize: 14, height: 1.5),
labelSmall: TextStyle(fontSize: 11, letterSpacing: 0.5),
),
// 组件主题
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
filled: true,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
),
chipTheme: ChipThemeData(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
),
),
// 深色主题
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.dark,
),
),
// 主题模式
themeMode: ThemeMode.system, // 跟随系统
)
在组件中使用主题
Widget build(BuildContext context) {
// 获取当前主题(类似 CSS var(--primary-color))
final theme = Theme.of(context);
final colors = theme.colorScheme;
final textTheme = theme.textTheme;
return Container(
color: colors.surface, // 表面色(卡片/页面背景)
child: Column(
children: [
Text(
'标题',
style: textTheme.headlineMedium?.copyWith(
color: colors.primary, // 主色
),
),
Text(
'副标题',
style: textTheme.bodyMedium?.copyWith(
color: colors.onSurface.withOpacity(0.6), // 次要文字色
),
),
],
),
);
}
colorScheme 常用色值:
| 属性 | 用途 |
|---|---|
primary |
主色(按钮、链接) |
onPrimary |
主色上的文字色 |
secondary |
辅助色 |
surface |
卡片/表面背景色 |
onSurface |
表面上的文字色 |
error |
错误提示色 |
background |
页面背景色 |
深色模式动态切换
// 用 Provider 管理主题模式
class ThemeProvider extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.system;
ThemeMode get themeMode => _themeMode;
void setTheme(ThemeMode mode) {
_themeMode = mode;
notifyListeners();
}
void toggle() {
_themeMode = _themeMode == ThemeMode.dark
? ThemeMode.light
: ThemeMode.dark;
notifyListeners();
}
}
// MaterialApp 中接入
MaterialApp(
themeMode: context.watch<ThemeProvider>().themeMode,
...
)
// 切换按钮
Switch(
value: themeProvider.themeMode == ThemeMode.dark,
onChanged: (_) => themeProvider.toggle(),
)
局部样式覆盖
// 局部覆盖主题(类似 CSS scoped)
Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
primary: Colors.orange, // 这个子树内的主色变为橙色
),
),
child: ElevatedButton(
onPressed: () {},
child: const Text('橙色按钮'),
),
)
颜色工具
// 颜色定义方式
Colors.blue // Material 颜色
Colors.blue.shade300 // 色阶(100-900)
const Color(0xFF6750A4) // HEX(ARGB 格式)
Color.fromRGBO(103, 80, 164, 1.0) // RGB + 透明度
// 颜色操作
Colors.black.withOpacity(0.5) // 带透明度(类似 rgba())
Colors.blue.withAlpha(128) // Alpha 值(0-255)
Color.lerp(Colors.red, Colors.blue, 0.5) // 颜色插值(用于动画)
TextStyle 速查
TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold, // w100 ~ w900 / bold / normal
fontStyle: FontStyle.italic, // 斜体
color: Colors.black87,
letterSpacing: 0.5, // 字间距
wordSpacing: 2.0, // 词间距
height: 1.5, // 行高(字号的倍数)
decoration: TextDecoration.underline, // 下划线
decorationColor: Colors.blue,
decorationStyle: TextDecorationStyle.dashed,
shadows: [
Shadow(color: Colors.black38, blurRadius: 4, offset: Offset(2, 2)),
],
)
// 继承主题样式并覆盖部分属性(类似 CSS 继承)
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.blue,
)