主题系统
主题系统让你的 App 视觉风格统一,修改一处全局生效。Flutter 使用 ThemeData 和 ColorScheme 来管理主题。
ThemeData 与 ColorScheme
全局主题配置
dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
// ─── ★ 全局主题配置 ──────────────
theme: ThemeData(
// ─── ★ fromSeed 自动生成色彩方案 ──────────────
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
),
// ─── ☆ fromSeed 自动生成色彩方案 ──────────────
useMaterial3: true,
fontFamily: 'NotoSansSC',
),
// ─── ☆ 全局主题配置 ──────────────
// ─── ★ 深色模式主题 ──────────────
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
// ─── ☆ 深色模式主题 ──────────────
// ─── ★ 跟随系统切换 ──────────────
themeMode: ThemeMode.system,
// ─── ☆ 跟随系统切换 ──────────────
home: const Scaffold(body: Center(child: Text('主题示例'))),
);
}
}ColorScheme — 色彩方案
ColorScheme 定义了一组协调的颜色,Material 3 推荐使用 fromSeed 自动生成:
dart
ColorScheme.fromSeed(seedColor: Colors.blue)自动生成的颜色角色:
| 颜色角色 | 用途 |
|---|---|
primary | 主色,按钮、重要元素 |
onPrimary | 主色上的文字颜色 |
primaryContainer | 主色容器(浅色背景) |
onPrimaryContainer | 主色容器上的文字 |
secondary | 次要色 |
tertiary | 第三色 |
error | 错误色 |
surface | 页面背景色 |
onSurface | 页面文字色 |
手动定义 ColorScheme
注意
手动构造 ColorScheme 需要提供大量参数,容易遗漏。推荐使用 ColorScheme.fromSeed() 自动生成,只在有特殊需求时手动构造。
dart
ThemeData(
colorScheme: ColorScheme(
brightness: Brightness.light,
primary: Color(0xFF2196F3),
onPrimary: Colors.white,
primaryContainer: Color(0xFFBBDEFB),
onPrimaryContainer: Color(0xFF0D47A1),
secondary: Color(0xFF03DAC6),
onSecondary: Colors.black,
secondaryContainer: Color(0xFFB2DFDB),
onSecondaryContainer: Color(0xFF004D40),
tertiary: Color(0xFF7C4DFF),
onTertiary: Colors.white,
error: Color(0xFFB00020),
onError: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
),
)局部主题覆盖
dart
import 'package:flutter/material.dart';
class LocalThemeExample extends StatelessWidget {
const LocalThemeExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('局部主题覆盖')),
body: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
primary: Colors.red,
),
),
child: const Center(
child: FilledButton(
onPressed: null,
child: Text('红色主题按钮'),
),
),
),
);
}
}深色模式适配
方式一:跟随系统(推荐)
dart
import 'package:flutter/material.dart';
void main() {
runApp(const DarkModeApp());
}
class DarkModeApp extends StatelessWidget {
const DarkModeApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
useMaterial3: true,
),
themeMode: ThemeMode.system,
home: const Scaffold(body: Center(child: Text('跟随系统深色模式'))),
);
}
}方式二:手动切换
dart
class ThemeNotifier extends ChangeNotifier {
ThemeMode _mode = ThemeMode.system;
ThemeMode get mode => _mode;
void toggle() {
_mode = _mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}
// 在 MaterialApp 中使用
Consumer<ThemeNotifier>(
builder: (_, notifier, __) => MaterialApp(
themeMode: notifier.mode,
theme: lightTheme,
darkTheme: darkTheme,
),
)判断当前是否深色模式
dart
import 'package:flutter/material.dart';
class DarkModeCheckExample extends StatelessWidget {
const DarkModeCheckExample({super.key});
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
body: Center(
child: Text(isDark ? '当前是深色模式' : '当前是浅色模式'),
),
);
}
}文字主题(TextTheme)
ThemeData.textTheme 定义了全局文字样式:
dart
ThemeData(
textTheme: TextTheme(
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.bold),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
bodyLarge: TextStyle(fontSize: 16),
bodyMedium: TextStyle(fontSize: 14),
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
),
)使用主题文字样式:
dart
Text('标题', style: Theme.of(context).textTheme.titleLarge)
Text('正文', style: Theme.of(context).textTheme.bodyMedium)主题速查
| 需求 | 做法 |
|---|---|
| 设置全局主题 | MaterialApp(theme: ThemeData(...)) |
| 从一个颜色生成主题 | ColorScheme.fromSeed(seedColor: color) |
| 深色模式 | 同时设置 theme 和 darkTheme |
| 局部覆盖 | Theme(data: ..., child: ...) |
| 获取当前主题 | Theme.of(context) |
| 获取主题颜色 | Theme.of(context).colorScheme.primary |
| 获取文字样式 | Theme.of(context).textTheme.bodyMedium |
