Flutter 的主题系统(ThemeData)提供了统一的视觉风格管理,通过 Material 3 的颜色系统和深色模式支持,可以轻松构建专业的视觉体系。
一、ThemeData 动态切换
1.1 定义双主题
dart
class AppTheme {
// 亮色主题
static ThemeData get lightTheme => ThemeData(
useMaterial3: true,
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4), // 主色调
brightness: Brightness.light,
),
// 文字主题
textTheme: _buildTextTheme(Brightness.light),
// 组件主题
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(48),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
),
);
// 暗色主题
static ThemeData get darkTheme => ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.dark,
),
textTheme: _buildTextTheme(Brightness.dark),
appBarTheme: const AppBarTheme(centerTitle: true, elevation: 0),
cardTheme: CardTheme(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
);
static TextTheme _buildTextTheme(Brightness brightness) {
final color = brightness == Brightness.light
? const Color(0xFF1C1B1F)
: const Color(0xFFE6E1E5);
return TextTheme(
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: color),
headlineMedium: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: color),
titleLarge: TextStyle(fontSize: 20, fontWeight: FontWeight.w600, color: color),
bodyLarge: TextStyle(fontSize: 16, color: color),
bodyMedium: TextStyle(fontSize: 14, color: color.withOpacity(0.8)),
);
}
}
1.2 主题切换控制器
dart
class ThemeController extends ChangeNotifier {
ThemeMode _themeMode;
ThemeController({ThemeMode initial = ThemeMode.system})
: _themeMode = initial;
ThemeMode get themeMode => _themeMode;
bool get isDark => _themeMode == ThemeMode.dark;
void setThemeMode(ThemeMode mode) {
_themeMode = mode;
PreferencesService.saveThemeMode(mode.index);
notifyListeners();
}
void toggleTheme() {
setThemeMode(isDark ? ThemeMode.light : ThemeMode.dark);
}
// 跟随系统
void followSystem() => setThemeMode(ThemeMode.system);
}
// 在 App 入口
ChangeNotifierProvider(
create: (_) => ThemeController(
initial: ThemeMode.values[PreferencesService.getThemeMode()],
),
child: Consumer<ThemeController>(
builder: (context, themeController, _) => MaterialApp(
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: themeController.themeMode,
home: const HomePage(),
),
),
)
二、自定义颜色与字体系统
2.1 Material 3 颜色系统
dart
// 从种子色生成完整颜色系统
final colorScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
);
// 颜色角色对应表
// primary → 主要操作按钮背景
// onPrimary → primary 上的文字/图标
// primaryContainer → 次要容器背景
// secondary → 次要操作
// surface → 卡片、对话框背景
// onSurface → surface 上的文字
// error → 错误状态
// 在 Widget 中使用
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
color: colorScheme.primaryContainer,
child: Text(
'Hello',
style: TextStyle(color: colorScheme.onPrimaryContainer),
),
);
}
2.2 扩展主题颜色(自定义颜色)
dart
// 定义扩展颜色
@immutable
class AppColors extends ThemeExtension<AppColors> {
final Color success;
final Color warning;
final Color info;
final Color gradientStart;
final Color gradientEnd;
const AppColors({
required this.success,
required this.warning,
required this.info,
required this.gradientStart,
required this.gradientEnd,
});
@override
AppColors copyWith({
Color? success,
Color? warning,
Color? info,
Color? gradientStart,
Color? gradientEnd,
}) {
return AppColors(
success: success ?? this.success,
warning: warning ?? this.warning,
info: info ?? this.info,
gradientStart: gradientStart ?? this.gradientStart,
gradientEnd: gradientEnd ?? this.gradientEnd,
);
}
@override
AppColors lerp(AppColors? other, double t) {
if (other == null) return this;
return AppColors(
success: Color.lerp(success, other.success, t)!,
warning: Color.lerp(warning, other.warning, t)!,
info: Color.lerp(info, other.info, t)!,
gradientStart: Color.lerp(gradientStart, other.gradientStart, t)!,
gradientEnd: Color.lerp(gradientEnd, other.gradientEnd, t)!,
);
}
// 亮色配置
static const light = AppColors(
success: Color(0xFF4CAF50),
warning: Color(0xFFFF9800),
info: Color(0xFF2196F3),
gradientStart: Color(0xFF6750A4),
gradientEnd: Color(0xFF03DAC6),
);
// 暗色配置
static const dark = AppColors(
success: Color(0xFF81C784),
warning: Color(0xFFFFB74D),
info: Color(0xFF64B5F6),
gradientStart: Color(0xFFD0BCFF),
gradientEnd: Color(0xFF6FF7EC),
);
}
// 注册到 ThemeData
ThemeData get lightTheme => ThemeData(
extensions: const [AppColors.light],
// ...
)
// 在 Widget 中使用
final appColors = Theme.of(context).extension<AppColors>()!;
Container(color: appColors.success)
2.3 自定义字体
yaml
# pubspec.yaml
flutter:
fonts:
- family: Outfit
fonts:
- asset: assets/fonts/Outfit-Regular.ttf
weight: 400
- asset: assets/fonts/Outfit-Medium.ttf
weight: 500
- asset: assets/fonts/Outfit-Bold.ttf
weight: 700
dart
ThemeData get theme => ThemeData(
fontFamily: 'Outfit', // 全局字体
textTheme: const TextTheme(
headlineLarge: TextStyle(
fontFamily: 'Outfit',
fontSize: 32,
fontWeight: FontWeight.w700,
),
),
)
2.4 动态主题色(用户自定义)
dart
class DynamicThemeController extends ChangeNotifier {
Color _seedColor = const Color(0xFF6750A4);
Color get seedColor => _seedColor;
ThemeData get lightTheme => ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: _seedColor,
brightness: Brightness.light,
),
);
ThemeData get darkTheme => ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: _seedColor,
brightness: Brightness.dark,
),
);
void updateSeedColor(Color color) {
_seedColor = color;
notifyListeners();
}
}
小结
| 知识点 | 核心要点 |
|---|---|
| ThemeData | 定义全局视觉风格,lightTheme + darkTheme |
| ThemeMode | system / light / dark 三种切换模式 |
| ColorScheme.fromSeed | 从种子色自动生成 Material 3 完整颜色系统 |
| ThemeExtension | 扩展自定义颜色,支持亮/暗色自动切换 |
| 字体配置 | pubspec.yaml 注册,fontFamily 全局应用 |
👉 下一节:6.2 国际化(i18n)