Flutter ThemeData 主题系统
等价于 CSS Variables / Tailwind 主题 / styled-components ThemeProvider
一、核心对照
| CSS / React | Flutter | 说明 |
|---|---|---|
--primary-color: #6200EE |
colorScheme.primary |
主色 |
--background: #FFFFFF |
colorScheme.surface |
背景色 |
--text-color: #000000 |
colorScheme.onSurface |
文字色 |
--error-color: #B00020 |
colorScheme.error |
错误色 |
| CSS Variables 全局继承 | Theme.of(context) 读取 |
任何子组件可读 |
:root { --color: red } |
MaterialApp(theme: ThemeData(...)) |
全局定义 |
var(--primary-color) |
Theme.of(context).colorScheme.primary |
使用主题色 |
@media (prefers-color-scheme: dark) |
darkTheme: ThemeData(...) |
暗黑模式 |
styled-components ThemeProvider |
MaterialApp(theme: ...) |
主题注入 |
二、定义全局主题
dart
MaterialApp(
theme: ThemeData(
// Material 3 推荐:从种子色自动生成整套配色
// 等价于 Tailwind 的 primary 色系自动生成 50-900
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6200EE), // 主色种子
brightness: Brightness.light,
),
useMaterial3: true,
// 也可以手动指定每个颜色角色
// colorScheme: const ColorScheme.light(
// primary: Color(0xFF6200EE), // 主色
// secondary: Color(0xFF03DAC6), // 次要色
// surface: Color(0xFFFFFFFF), // 背景
// error: Color(0xFFB00020), // 错误色
// onPrimary: Colors.white, // 主色上的文字
// onSurface: Color(0xFF000000), // 背景上的文字
// ),
),
// 暗黑模式主题
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6200EE),
brightness: Brightness.dark, // 切换为深色
),
useMaterial3: true,
),
// 跟随系统 / 强制亮色 / 强制暗色
themeMode: ThemeMode.system, // ThemeMode.light / ThemeMode.dark
)
三、ColorScheme 颜色角色
Material 3 设计系统,每个颜色都有对应的「在其上的文字色」
| 颜色角色 | 用途 | 等价 CSS Variable |
|---|---|---|
primary |
主操作、重要按钮 | --color-primary |
onPrimary |
primary 上的文字/图标 | --color-primary-text |
secondary |
次要操作 | --color-secondary |
surface |
卡片、底部栏背景 | --color-surface |
onSurface |
surface 上的文字 | --color-on-surface |
background |
页面背景(M3 已废弃,用 surface) | --color-background |
error |
错误提示 | --color-error |
onError |
error 上的文字 | --color-error-text |
inversePrimary |
AppBar 上的背景色 | - |
outline |
边框、分隔线 | --color-border |
dart
// 在任意子组件中读取主题色
// 等价于 CSS: color: var(--color-primary)
final colorScheme = Theme.of(context).colorScheme;
Container(color: colorScheme.primary)
Text('标题', style: TextStyle(color: colorScheme.onSurface))
四、TextTheme 文字样式系统
等价于 Tailwind 的 text-xs / text-sm / text-base / text-lg ...
dart
// 全局定义
ThemeData(
textTheme: const TextTheme(
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
displayMedium: TextStyle(fontSize: 45),
displaySmall: TextStyle(fontSize: 36),
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
headlineMedium: TextStyle(fontSize: 28),
headlineSmall: TextStyle(fontSize: 24),
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
titleMedium: TextStyle(fontSize: 16),
titleSmall: TextStyle(fontSize: 14),
bodyLarge: TextStyle(fontSize: 16),
bodyMedium: TextStyle(fontSize: 14), // 默认正文
bodySmall: TextStyle(fontSize: 12),
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), // 按钮文字
labelMedium: TextStyle(fontSize: 12),
labelSmall: TextStyle(fontSize: 11),
),
)
// 使用
Text('标题', style: Theme.of(context).textTheme.headlineMedium)
Text('正文', style: Theme.of(context).textTheme.bodyMedium)
// 等价于:
// <h2 className="text-2xl font-bold">标题</h2>
// <p className="text-sm">正文</p>
五、组件主题定制
等价于 CSS 组件样式覆盖 / styled-components
dart
ThemeData(
// 按钮全局样式(等价于 .btn { border-radius: 8px })
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
// 输入框全局样式
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
// AppBar 全局样式
appBarTheme: const AppBarTheme(
elevation: 0,
centerTitle: true,
),
// Card 全局样式
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
// 全局字体
fontFamily: 'Roboto',
)
六、局部覆盖主题
dart
// 局部覆盖(等价于 CSS scope / styled-components 局部样式)
Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
primary: Colors.red, // 只改这个子树的主色
),
),
child: ElevatedButton(
onPressed: () {},
child: const Text('红色按钮'),
),
)
七、暗黑模式适配
dart
// 读取当前亮/暗模式
final isDark = Theme.of(context).brightness == Brightness.dark;
// 根据模式选色(等价于 CSS prefers-color-scheme)
Container(
color: isDark ? Colors.grey[900] : Colors.white,
)
// 推荐:直接用 colorScheme,自动适配亮暗
// colorScheme.surface 在亮色主题是白色,暗色主题是深灰
Container(
color: Theme.of(context).colorScheme.surface,
)
八、自定义颜色扩展
dart
// 扩展 ColorScheme,添加自定义颜色(等价于扩展 CSS Variables)
@immutable
class AppColors extends ThemeExtension<AppColors> {
final Color success;
final Color warning;
const AppColors({required this.success, required this.warning});
@override
AppColors copyWith({Color? success, Color? warning}) => AppColors(
success: success ?? this.success,
warning: warning ?? this.warning,
);
@override
AppColors lerp(AppColors other, double t) => AppColors(
success: Color.lerp(success, other.success, t)!,
warning: Color.lerp(warning, other.warning, t)!,
);
}
// 注册
ThemeData(
extensions: const [
AppColors(success: Color(0xFF4CAF50), warning: Color(0xFFFFC107)),
],
)
// 使用
final appColors = Theme.of(context).extension<AppColors>()!;
Icon(Icons.check, color: appColors.success)
九、完整主题配置示例
dart
ThemeData get lightTheme => ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF6200EE)),
fontFamily: 'PingFang SC',
textTheme: const TextTheme(
titleLarge: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
bodyMedium: TextStyle(fontSize: 14, height: 1.5),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
),
appBarTheme: const AppBarTheme(elevation: 0, centerTitle: true),
cardTheme: CardTheme(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
);
ThemeData get darkTheme => lightTheme.copyWith(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6200EE),
brightness: Brightness.dark,
),
);
十、主题速查
scss
Theme.of(context).colorScheme.primary → var(--color-primary)
Theme.of(context).colorScheme.surface → var(--color-background)
Theme.of(context).colorScheme.error → var(--color-error)
Theme.of(context).textTheme.headlineMedium → .text-2xl.font-bold
Theme.of(context).textTheme.bodyMedium → .text-sm(默认正文)
Theme.of(context).brightness → prefers-color-scheme