Appearance
第11章:Flutter 样式与主题
11.1 Flutter 样式基础
文本样式(TextStyle)
TextStyle 用于定义文本的样式,包括字体、颜色、粗细、间距等。
常用属性:
| 属性 | 类型 | 描述 |
|---|---|---|
color | Color | 文本颜色 |
fontSize | double | 字体大小 |
fontWeight | FontWeight | 字体粗细(bold、normal等) |
fontStyle | FontStyle | 字体样式(normal、italic) |
letterSpacing | double | 字母间距 |
wordSpacing | double | 单词间距 |
lineHeight | double | 行高 |
decoration | TextDecoration | 文本装饰(underline、lineThrough等) |
fontFamily | String | 字体系列 |
使用示例:
dart
Text(
'Hello Flutter!',
style: TextStyle(
color: Colors.blue,
fontSize: 24,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
letterSpacing: 2.0,
wordSpacing: 4.0,
decoration: TextDecoration.underline,
decorationColor: Colors.red,
decorationStyle: TextDecorationStyle.wavy,
),
);容器样式(BoxDecoration)
BoxDecoration 用于定义容器的样式,包括背景色、边框、圆角、阴影、渐变等。
常用属性:
| 属性 | 类型 | 描述 |
|---|---|---|
color | Color | 背景颜色 |
border | BoxBorder | 边框 |
borderRadius | BorderRadius | 圆角 |
boxShadow | List<BoxShadow> | 阴影 |
gradient | Gradient | 渐变 |
image | DecorationImage | 背景图片 |
使用示例:
dart
Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.blue,
width: 2,
),
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // 阴影偏移
),
],
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.blue, Colors.purple],
),
),
child: Center(
child: Text('Styled Container'),
),
);11.2 主题(Theme)配置
全局主题
通过 MaterialApp 的 theme 属性配置全局主题,应用于整个应用。
基本配置:
dart
MaterialApp(
theme: ThemeData(
// 主色调
primaryColor: Colors.blue,
primarySwatch: Colors.blue,
// 次要色调
accentColor: Colors.orange,
// 背景色
backgroundColor: Colors.grey[100],
// 卡片颜色
cardColor: Colors.white,
// 文本主题
textTheme: TextTheme(
headline1: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.black,
),
bodyText1: TextStyle(
fontSize: 16,
color: Colors.grey[800],
),
bodyText2: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
// 按钮主题
buttonTheme: ButtonThemeData(
buttonColor: Colors.blue,
textTheme: ButtonTextTheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
// 输入框主题
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
borderRadius: BorderRadius.circular(8),
),
),
),
home: HomePage(),
);局部主题
使用 Theme 组件覆盖全局主题,实现局部样式差异。
使用示例:
dart
Theme(
data: ThemeData(
primaryColor: Colors.green,
accentColor: Colors.yellow,
textTheme: TextTheme(
bodyText1: TextStyle(color: Colors.green),
),
),
child: Container(
child: Text('Local Theme Text'),
),
);主题数据获取
使用 Theme.of(context) 获取当前主题数据:
dart
Container(
color: Theme.of(context).primaryColor,
child: Text(
'Themed Text',
style: Theme.of(context).textTheme.bodyText1,
),
);11.3 字体与图标自定义
自定义字体导入
步骤 1:添加字体文件
将字体文件(.ttf 或 .otf)添加到项目的 assets/fonts 目录中。
步骤 2:配置 pubspec.yaml
yaml
flutter:
fonts:
- family: CustomFont
fonts:
- asset: assets/fonts/CustomFont-Regular.ttf
- asset: assets/fonts/CustomFont-Bold.ttf
weight: 700
- asset: assets/fonts/CustomFont-Italic.ttf
style: italic步骤 3:使用自定义字体
dart
Text(
'Custom Font Text',
style: TextStyle(
fontFamily: 'CustomFont',
fontSize: 20,
),
);自定义图标导入
步骤 1:生成图标字体
使用 FlutterIcon 或 IconMoon 等工具生成图标字体。
步骤 2:添加图标文件
将生成的字体文件和 Dart 类文件添加到项目中。
步骤 3:使用自定义图标
dart
import 'package:your_app/icons/custom_icons.dart';
Icon(
CustomIcons.heart,
size: 24,
color: Colors.red,
);11.4 实操案例:配置全局主题,自定义页面样式,实现主题切换
目标
创建一个应用,配置全局主题,自定义页面样式,并实现亮色/暗色主题切换功能。
步骤 1:创建主题管理类
dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ThemeModel extends ChangeNotifier {
bool _isDarkMode = false;
bool get isDarkMode => _isDarkMode;
// 初始化:从本地存储加载主题设置
Future<void> init() async {
final prefs = await SharedPreferences.getInstance();
_isDarkMode = prefs.getBool('isDarkMode') ?? false;
notifyListeners();
}
// 切换主题
Future<void> toggleTheme() async {
_isDarkMode = !_isDarkMode;
// 保存到本地存储
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isDarkMode', _isDarkMode);
notifyListeners();
}
// 获取当前主题
ThemeData get themeData => _isDarkMode ? darkTheme : lightTheme;
// 亮色主题
static final lightTheme = ThemeData(
brightness: Brightness.light,
primaryColor: Colors.blue,
primarySwatch: Colors.blue,
accentColor: Colors.orange,
backgroundColor: Colors.grey[100],
cardColor: Colors.white,
textTheme: TextTheme(
headline1: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.black,
),
bodyText1: TextStyle(
fontSize: 16,
color: Colors.grey[800],
),
bodyText2: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
buttonTheme: ButtonThemeData(
buttonColor: Colors.blue,
textTheme: ButtonTextTheme.primary,
),
);
// 暗色主题
static final darkTheme = ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.blue[700],
primarySwatch: Colors.blue,
accentColor: Colors.orange[700],
backgroundColor: Colors.grey[900],
cardColor: Colors.grey[800],
textTheme: TextTheme(
headline1: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.white,
),
bodyText1: TextStyle(
fontSize: 16,
color: Colors.grey[300],
),
bodyText2: TextStyle(
fontSize: 14,
color: Colors.grey[400],
),
),
buttonTheme: ButtonThemeData(
buttonColor: Colors.blue[700],
textTheme: ButtonTextTheme.primary,
),
);
}步骤 2:创建主应用
dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'theme_model.dart';
import 'home_page.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => ThemeModel()..init(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<ThemeModel>(
builder: (context, themeModel, child) {
return MaterialApp(
title: 'Theme Demo',
theme: themeModel.themeData,
home: HomePage(),
);
},
);
}
}步骤 3:创建首页
dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'theme_model.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final themeModel = Provider.of<ThemeModel>(context);
return Scaffold(
appBar: AppBar(
title: Text('Theme Demo'),
actions: [
IconButton(
icon: Icon(
themeModel.isDarkMode ? Icons.wb_sunny : Icons.nightlight_round,
),
onPressed: () {
themeModel.toggleTheme();
},
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Welcome to Flutter Theme Demo',
style: Theme.of(context).textTheme.headline1,
textAlign: TextAlign.center,
),
SizedBox(height: 40),
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
'Card Title',
style: Theme.of(context).textTheme.headline6,
),
SizedBox(height: 10),
Text(
'This is a sample card with themed content. The colors will change based on the selected theme.',
style: Theme.of(context).textTheme.bodyText1,
textAlign: TextAlign.center,
),
],
),
),
),
SizedBox(height: 40),
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Button clicked!'),
),
);
},
child: Text('Click Me'),
),
SizedBox(height: 40),
Text(
'Current Theme: ${themeModel.isDarkMode ? 'Dark' : 'Light'}',
style: Theme.of(context).textTheme.bodyText2,
),
],
),
),
);
}
}步骤 4:运行应用
- 启动模拟器或连接真机
- 运行项目
- 点击右上角的图标切换主题
- 观察主题变化效果
- 重启应用,验证主题设置是否保存
11.5 样式与主题最佳实践
1. 全局主题统一
- 集中管理:在
MaterialApp中配置全局主题 - 一致性:确保应用整体风格一致
- 可维护性:便于后续统一修改样式
2. 主题层次结构
- 全局主题:设置应用的基本风格
- 局部主题:针对特定页面或组件进行样式调整
- 组件样式:对单个组件进行样式定制
3. 响应式设计
- 适配不同屏幕:考虑不同屏幕尺寸的样式表现
- 动态字体:使用
MediaQuery调整字体大小 - 布局适配:确保样式在不同设备上都能正常显示
4. 性能优化
- 避免重复创建:复用样式对象
- 使用 const:对于固定样式使用
const构造函数 - 主题数据缓存:避免频繁获取主题数据
5. 可访问性
- 对比度:确保文本与背景的对比度符合可访问性标准
- 字体大小:支持系统字体大小设置
- 色彩方案:考虑色盲用户的体验
11.6 小结
本章介绍了 Flutter 的样式与主题,包括文本样式、容器样式、主题配置、字体与图标自定义等内容。样式与主题是 Flutter 应用的重要组成部分,它们直接影响用户体验和应用的视觉效果。
我们学习了:
- TextStyle:定义文本的样式,包括字体、颜色、粗细等
- BoxDecoration:定义容器的样式,包括背景色、边框、圆角、阴影等
- ThemeData:配置全局主题,统一应用的整体风格
- Theme 组件:实现局部主题覆盖,实现样式差异
- 自定义字体:导入和使用自定义字体
- 自定义图标:导入和使用自定义图标
- 主题切换:实现亮色/暗色主题切换功能
通过实操案例,我们创建了一个应用,配置了全局主题,实现了主题切换功能,并保存了主题设置。在实际开发中,你应该根据应用的需求和品牌风格,设计合适的样式和主题,提升应用的视觉效果和用户体验。
在接下来的章节中,我们将学习 Flutter 的常用组件进阶,掌握更多实用的组件和功能。
