本章将深入讲解待办事项应用中使用的三个关键技术:Material Design 3、SharedPreferences 和 Provider。
8.1 Material Design 3
什么是 Material Design 3?
Material Design 3(简称 M3)是 Google 最新的设计语言,相比 M2 有以下改进:
- 更现代的视觉风格 - 圆角更大、颜色更柔和
- 动态颜色 - 可以从壁纸提取主题色
- 更好的可访问性 - 对比度更高
- 更灵活的组件 - 更多自定义选项
启用 Material Design 3
MaterialApp(
theme: ThemeData(
useMaterial3: true, // 启用 M3
colorScheme: ColorScheme.fromSeed(
seedColor: Color(0xFF6750A4), // 主题种子色
),
),
)ColorScheme(颜色方案)
ColorScheme 定义了应用的颜色系统:
ColorScheme(
primary: Color(0xFF6750A4), // 主色
onPrimary: Colors.white, // 主色上的文字
primaryContainer: Color(0xFFEADDFF), // 主色容器
onPrimaryContainer: Color(0xFF21005D), // 主色容器上的文字
secondary: Color(0xFF625B71), // 次色
onSecondary: Colors.white,
surface: Colors.white, // 表面色(卡片背景)
onSurface: Color(0xFF1C1B1F), // 表面上的文字
error: Color(0xFFB3261E), // 错误色
onError: Colors.white,
outline: Color(0xFF79747E), // 边框色
)使用 ColorScheme
final colorScheme = Theme.of(context).colorScheme;
Container(
color: colorScheme.primaryContainer,
child: Text(
'Hello',
style: TextStyle(color: colorScheme.onPrimaryContainer),
),
)主题配置完整示例
ThemeData _buildLightTheme() {
return ThemeData(
useMaterial3: true,
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
),
// AppBar 主题
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
// 卡片主题
cardTheme: CardThemeData(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
// 输入框主题
inputDecorationTheme: InputDecorationTheme(
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
),
// 浮动按钮主题
floatingActionButtonTheme: FloatingActionButtonThemeData(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
);
}8.2 SharedPreferences
什么是 SharedPreferences?
SharedPreferences 是一个轻量级的本地存储方案,适合存储简单的键值对数据:
- ✅ 适合存储:用户设置、小量数据、缓存
- ❌ 不适合存储:大量数据、复杂查询、敏感信息
添加依赖
1dependencies:
2 shared_preferences: ^2.2.2基本使用
import 'package:shared_preferences/shared_preferences.dart';
// 获取实例
final prefs = await SharedPreferences.getInstance();
// 存储数据
await prefs.setString('username', '张三');
await prefs.setInt('age', 25);
await prefs.setBool('isLoggedIn', true);
await prefs.setStringList('tags', ['flutter', 'dart']);
// 读取数据
final username = prefs.getString('username');
final age = prefs.getInt('age');
// 删除数据
await prefs.remove('username');
// 清空所有数据
await prefs.clear();存储任务列表
import 'dart:convert';
class StorageService {
static const String _tasksKey = 'tasks';
/// 保存任务列表
static Future saveTasks(List tasks) async {
final prefs = await SharedPreferences.getInstance();
// 1. 将 Task 列表转换为 JSON 列表
final tasksJson = tasks.map((task) => task.toJson()).toList();
// 2. 将 JSON 列表编码为字符串
final tasksString = jsonEncode(tasksJson);
// 3. 存储字符串
await prefs.setString(_tasksKey, tasksString);
}
/// 加载任务列表
static Future> loadTasks() async {
final prefs = await SharedPreferences.getInstance();
// 1. 读取字符串
final tasksString = prefs.getString(_tasksKey);
if (tasksString == null || tasksString.isEmpty) {
return [];
}
// 2. 解码字符串为 JSON 列表
final tasksJson = jsonDecode(tasksString) as List;
// 3. 将 JSON 列表转换为 Task 列表
return tasksJson
.map((json) => Task.fromJson(json as Map))
.toList();
}
}数据流向
Task 对象列表
│
▼
toJson() 转换
│
▼
JSON 列表 (List)
│
▼
jsonEncode() 编码
│
▼
字符串 (String)
│
▼
SharedPreferences 存储8.3 Provider 深入
Provider 的几种类型
| Provider 类型 | 用途 |
|---|---|
Provider |
提供不可变对象 |
ChangeNotifierProvider |
提供可通知变化的对象 |
FutureProvider |
提供异步数据 |
StreamProvider |
提供流数据 |
MultiProvider |
组合多个 Provider |
MultiProvider(多个 Provider)
当应用需要多个 Provider 时:
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => TaskProvider()),
ChangeNotifierProvider(create: (_) => UserProvider()),
ChangeNotifierProvider(create: (_) => SettingsProvider()),
],
child: MyApp(),
)ProxyProvider(依赖其他 Provider)
当一个 Provider 依赖另一个 Provider 时:
ChangeNotifierProxyProvider(
create: (_) => StatsProvider(),
update: (_, taskProvider, statsProvider) {
return statsProvider!..updateTasks(taskProvider.tasks);
},
)性能优化
1. 使用 const 构造函数
// ❌ 每次重建都创建新对象
return Container(
child: Text('Hello'),
);
// ✅ 使用 const,复用对象
return const Container(
child: Text('Hello'),
);2. 使用 Selector 精确监听
// ❌ 任务数量变化时整个组件重建
final provider = context.watch();
return Text('${provider.totalTaskCount}');
// ✅ 只监听 totalTaskCount 的变化
Selector(
selector: (_, provider) => provider.totalTaskCount,
builder: (_, count, __) => Text('$count'),
)3. 合理使用 Consumer 的 child 参数
Consumer(
builder: (context, provider, child) {
return Stack(
children: [
// 这个组件不会重建
child!,
// 这个组件会重建
Text('${provider.totalTaskCount}'),
],
);
},
// 传入不需要重建的组件
child: ExpensiveWidget(),
)8.4 异步编程
Future 和 async/await
// 定义异步方法
Future loadData() async {
// 等待异步操作完成
final data = await fetchData();
// 继续执行
processData(data);
}
// 调用异步方法
void initState() {
super.initState();
loadData(); // 不需要 await
}错误处理
Future loadData() async {
try {
final data = await fetchData();
processData(data);
} catch (e) {
// 处理错误
print('加载失败: $e');
} finally {
// 无论成功失败都会执行
setLoading(false);
}
}多个异步操作
// 串行执行
Future loadAll() async {
await loadTasks();
await loadSettings();
await loadUser();
}
// 并行执行
Future loadAll() async {
await Future.wait([
loadTasks(),
loadSettings(),
loadUser(),
]);
}8.5 生命周期
StatefulWidget 生命周期
constructor
│
▼
createState()
│
▼
initState() ───────▶ 初始化(只执行一次)
│
▼
didChangeDependencies()
│
▼
build() ───────────▶ 构建 UI(可能执行多次)
│
▼
didUpdateWidget() ─▶ 父组件重建时调用
│
▼
deactivate()
│
▼
dispose() ─────────▶ 销毁(清理资源)常用生命周期方法
class _MyWidgetState extends State {
@override
void initState() {
super.initState();
// 初始化:加载数据、设置监听器
loadData();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 依赖变化时调用
}
@override
void didUpdateWidget(covariant MyWidget oldWidget) {
super.didUpdateWidget(oldWidget);
// 父组件重建时调用
}
@override
void dispose() {
// 清理资源:取消订阅、释放控制器
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container();
}
}8.6 小结
| 技术 | 用途 |
|---|---|
| Material Design 3 | 现代美观的 UI 设计 |
| SharedPreferences | 本地数据持久化 |
| Provider | 状态管理和数据共享 |
| async/await | 异步编程 |
| 生命周期 | 管理组件的创建和销毁 |
下一步:第九章:常见问题排查