Flutter 主题与样式
本节将介绍 Flutter 中的主题配置,包括 Material Design 主题、自定义主题和深色模式。
ThemeData - 应用主题
使用 ThemeData 可以统一配置应用的主题颜色、字体、样式等。
实例:配置应用主题
void main() {
runApp(
MaterialApp(
theme: ThemeData(
// 主色调
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
// 使用 Material 3
useMaterial3: true,
// 字体
fontFamily: 'Roboto',
// 应用栏主题
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
// 按钮主题
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
// 输入框主题
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
),
),
home: const MyHomePage(),
),
);
}
runApp(
MaterialApp(
theme: ThemeData(
// 主色调
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
// 使用 Material 3
useMaterial3: true,
// 字体
fontFamily: 'Roboto',
// 应用栏主题
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
// 按钮主题
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
// 输入框主题
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
),
),
home: const MyHomePage(),
),
);
}
Theme.of - 使用主题
在 Widget 中使用 Theme.of(context) 获取当前主题。
实例:使用主题颜色
class ThemedButton extends StatelessWidget {
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// 获取主题
final theme = Theme.of(context);
return Column(
children: [
// 使用主题色
Container(
color: theme.colorScheme.primary,
padding: const EdgeInsets.all(16),
child: Text(
'主要颜色',
style: TextStyle(color: theme.colorScheme.onPrimary),
),
),
const SizedBox(height: 16),
// 使用次要色
Container(
color: theme.colorScheme.secondary,
padding: const EdgeInsets.all(16),
child: Text(
'次要颜色',
style: TextStyle(color: theme.colorScheme.onSecondary),
),
),
const SizedBox(height: 16),
// 使用错误色
Container(
color: theme.colorScheme.error,
padding: const EdgeInsets.all(16),
child: Text(
'错误颜色',
style: TextStyle(color: theme.colorScheme.onError),
),
),
],
);
}
}
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// 获取主题
final theme = Theme.of(context);
return Column(
children: [
// 使用主题色
Container(
color: theme.colorScheme.primary,
padding: const EdgeInsets.all(16),
child: Text(
'主要颜色',
style: TextStyle(color: theme.colorScheme.onPrimary),
),
),
const SizedBox(height: 16),
// 使用次要色
Container(
color: theme.colorScheme.secondary,
padding: const EdgeInsets.all(16),
child: Text(
'次要颜色',
style: TextStyle(color: theme.colorScheme.onSecondary),
),
),
const SizedBox(height: 16),
// 使用错误色
Container(
color: theme.colorScheme.error,
padding: const EdgeInsets.all(16),
child: Text(
'错误颜色',
style: TextStyle(color: theme.colorScheme.onError),
),
),
],
);
}
}
深色模式
实例:深色模式支持
void main() {
runApp(
MaterialApp(
theme: ThemeData(
// 浅色主题
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
darkTheme: ThemeData(
// 深色主题
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
// 同时启用(可选)
themeMode: ThemeMode.system, // 根据系统设置
// themeMode: ThemeMode.light // 强制浅色
// themeMode: ThemeMode.dark // 强制深色
home: const ThemeTogglePage(),
),
);
}
// 切换主题
class ThemeTogglePage extends StatelessWidget {
const ThemeTogglePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('主题切换')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('当前主题'),
const SizedBox(height: 20),
// 切换主题按钮
ElevatedButton(
onPressed: () {
final currentMode = Theme.of(context).brightness;
if (currentMode == Brightness.light) {
// 切换到深色
Theme.of(context).setThemeMode(ThemeMode.dark);
} else {
// 切换到浅色
Theme.of(context).setThemeMode(ThemeMode.light);
}
},
child: const Text('切换主题'),
),
],
),
),
);
}
}
runApp(
MaterialApp(
theme: ThemeData(
// 浅色主题
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
darkTheme: ThemeData(
// 深色主题
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
// 同时启用(可选)
themeMode: ThemeMode.system, // 根据系统设置
// themeMode: ThemeMode.light // 强制浅色
// themeMode: ThemeMode.dark // 强制深色
home: const ThemeTogglePage(),
),
);
}
// 切换主题
class ThemeTogglePage extends StatelessWidget {
const ThemeTogglePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('主题切换')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('当前主题'),
const SizedBox(height: 20),
// 切换主题按钮
ElevatedButton(
onPressed: () {
final currentMode = Theme.of(context).brightness;
if (currentMode == Brightness.light) {
// 切换到深色
Theme.of(context).setThemeMode(ThemeMode.dark);
} else {
// 切换到浅色
Theme.of(context).setThemeMode(ThemeMode.light);
}
},
child: const Text('切换主题'),
),
],
),
),
);
}
}
自定义样式扩展
实例:自定义 TextTheme
ThemeData(
textTheme: const TextTheme(
// 展示文字(大标题)
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
displayMedium: TextStyle(fontSize: 45, fontWeight: FontWeight.w400),
displaySmall: TextStyle(fontSize: 36, fontWeight: FontWeight.w400),
// 标题文字
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w400),
headlineSmall: TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
// 标题文字
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
// 正文文字
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
// 标签文字
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
)
textTheme: const TextTheme(
// 展示文字(大标题)
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
displayMedium: TextStyle(fontSize: 45, fontWeight: FontWeight.w400),
displaySmall: TextStyle(fontSize: 36, fontWeight: FontWeight.w400),
// 标题文字
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w400),
headlineSmall: TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
// 标题文字
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
// 正文文字
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
// 标签文字
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
)
使用 ThemeData 统一管理应用样式,可以轻松实现主题切换和样式统一,维护更方便。
