摘要:本文是Flutter进阶开发指南,深入讲解路由与导航、网络请求、动画系统、自定义组件、主题与国际化等核心主题。通过本文档,你将掌握Flutter开发的中高级技能,能够构建复杂的商业应用。
关键词:Flutter、路由导航、网络请求、动画、自定义组件、主题、国际化、HTTP
适合人群:已掌握Flutter基础的开发者、想深入学习进阶技能的工程师
阅读时间:约 50 分钟
版本信息:Flutter 3.x | Dart 3.x | 支持 Android/iOS/Web
更新日期:2026-09-03
文章目录
- [1. 路由与导航](#1. 路由与导航)
-
- [1.1 基础路由](#1.1 基础路由)
- [1.2 命名路由](#1.2 命名路由)
- [1.3 路由传参](#1.3 路由传参)
- [1.4 路由返回数据](#1.4 路由返回数据)
- [2. 网络请求](#2. 网络请求)
-
- [2.1 http 包基础用法](#2.1 http 包基础用法)
- [2.2 GET 请求](#2.2 GET 请求)
- [2.3 POST 请求](#2.3 POST 请求)
- [2.4 错误处理](#2.4 错误处理)
- [3. 动画系统](#3. 动画系统)
-
- [3.1 隐式动画](#3.1 隐式动画)
- AnimatedContainer
- AnimatedOpacity
- AnimatedPositioned
- [3.2 显式动画](#3.2 显式动画)
- [3.3 Hero 动画](#3.3 Hero 动画)
- [4. 自定义组件](#4. 自定义组件)
-
- [4.1 组合现有组件](#4.1 组合现有组件)
- [4.2 CustomPaint 自定义绘制](#4.2 CustomPaint 自定义绘制)
- [5. 主题与样式](#5. 主题与样式)
-
- [5.1 ThemeData 配置](#5.1 ThemeData 配置)
- [5.2 动态主题切换](#5.2 动态主题切换)
- [6. 国际化](#6. 国际化)
-
- [6.1 配置国际化](#6.1 配置国际化)
- [6.2 使用多语言](#6.2 使用多语言)
- [💡 综合实战案例](#💡 综合实战案例)
- [❓ 常见问题 FAQ](#❓ 常见问题 FAQ)
-
- [1. 如何在页面跳转时传递复杂对象?](#1. 如何在页面跳转时传递复杂对象?)
- [2. 网络请求失败如何重试?](#2. 网络请求失败如何重试?)
- [3. 如何优化列表滚动性能?](#3. 如何优化列表滚动性能?)
- [4. 动画卡顿如何优化?](#4. 动画卡顿如何优化?)
- [5. 如何全局管理用户登录状态?](#5. 如何全局管理用户登录状态?)
- [📝 总结](#📝 总结)
- [📚 参考资料](#📚 参考资料)
1. 路由与导航
1.1 基础路由
Flutter 使用 Navigator 管理页面跳转。
dart
// 跳转到新页面
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const DetailPage()),
);
// 返回上一页
Navigator.pop(context);
效果说明:
Navigator.push将新页面压入导航栈MaterialPageRoute提供平台特定的页面过渡动画Navigator.pop弹出当前页面,返回上一页
1.2 命名路由
通过路由名称跳转,便于统一管理。
dart
// 在 MaterialApp 中配置路由
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const HomePage(),
'/detail': (context) => const DetailPage(),
'/settings': (context) => const SettingsPage(),
},
);
// 使用命名路由跳转
Navigator.pushNamed(context, '/detail');
// 返回上一页
Navigator.pop(context);
效果说明:
routes定义路由映射表pushNamed通过路由名称跳转- 适合中大型项目,便于路由管理
1.3 路由传参
跳转时传递数据到新页面。
dart
// 方式一:构造函数传参
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailPage(itemId: 123, title: '商品详情'),
),
);
// 接收参数
class DetailPage extends StatelessWidget {
final int itemId;
final String title;
const DetailPage({
super.key,
required this.itemId,
required this.title,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: Text('商品ID: $itemId'),
);
}
}
效果说明:
- 通过构造函数传递参数是最常用的方式
- 使用
required标记必填参数 - 参数类型可以是任意类型(int、String、对象等)
1.4 路由返回数据
从新页面返回数据到上一页。
dart
// 上一页:等待返回结果
void _navigateAndGetValue() async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const InputPage()),
);
if (result != null) {
print('返回值: $result');
}
}
// 新页面:返回数据
class InputPage extends StatelessWidget {
const InputPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('输入页面')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context, '返回的数据');
},
child: const Text('返回'),
),
),
);
}
}
效果说明:
Navigator.pop(context, data)第二个参数为返回值- 使用
await等待页面返回 - 返回值可以是任意类型
2. 网络请求
2.1 http 包基础用法
Flutter 官方推荐使用 http 包进行网络请求。
安装依赖:
在 pubspec.yaml 中添加:
yaml
dependencies:
flutter:
sdk: flutter
http: ^1.1.0
运行命令:
bash
flutter pub get
2.2 GET 请求
dart
import 'package:http/http.dart' as http;
import 'dart:convert';
class ApiService {
static const String baseUrl = 'https://jsonplaceholder.typicode.com';
// 获取用户列表
static Future<List<dynamic>> getUsers() async {
final response = await http.get(Uri.parse('$baseUrl/users'));
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('获取用户列表失败');
}
}
// 获取单个用户
static Future<Map<String, dynamic>> getUser(int id) async {
final response = await http.get(Uri.parse('$baseUrl/users/$id'));
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('获取用户失败');
}
}
}
效果说明:
http.get发送 GET 请求response.statusCode检查响应状态码json.decode将 JSON 字符串解析为 Dart 对象- 200 表示请求成功,其他状态码表示失败
2.3 POST 请求
dart
class ApiService {
// 创建用户
static Future<Map<String, dynamic>> createUser(Map<String, dynamic> data) async {
final response = await http.post(
Uri.parse('$baseUrl/users'),
headers: {'Content-Type': 'application/json'},
body: json.encode(data),
);
if (response.statusCode == 201) {
return json.decode(response.body);
} else {
throw Exception('创建用户失败');
}
}
// 更新用户
static Future<Map<String, dynamic>> updateUser(int id, Map<String, dynamic> data) async {
final response = await http.put(
Uri.parse('$baseUrl/users/$id'),
headers: {'Content-Type': 'application/json'},
body: json.encode(data),
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('更新用户失败');
}
}
// 删除用户
static Future<void> deleteUser(int id) async {
final response = await http.delete(Uri.parse('$baseUrl/users/$id'));
if (response.statusCode != 200) {
throw Exception('删除用户失败');
}
}
}
效果说明:
http.post发送 POST 请求headers设置请求头,Content-Type: application/json表示 JSON 格式json.encode将 Dart 对象编码为 JSON 字符串- 201 表示创建成功,200 表示更新成功
2.4 错误处理
完整的网络请求应包含错误处理。
dart
class ApiService {
static Future<List<dynamic>> fetchUsers() async {
try {
final response = await http.get(
Uri.parse('$baseUrl/users'),
).timeout(const Duration(seconds: 10));
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('请求失败: ${response.statusCode}');
}
} on http.ClientException catch (e) {
throw Exception('网络错误: $e');
} on TimeoutException catch (e) {
throw Exception('请求超时: $e');
} catch (e) {
throw Exception('未知错误: $e');
}
}
}
效果说明:
timeout设置请求超时时间try-catch捕获不同类型的异常ClientException网络错误TimeoutException超时错误
3. 动画系统
3.1 隐式动画
Flutter 提供了一系列隐式动画组件,只需改变属性值即可自动播放动画。
AnimatedContainer
dart
class AnimatedContainerExample extends StatefulWidget {
const AnimatedContainerExample({super.key});
@override
State<AnimatedContainerExample> createState() => _AnimatedContainerExampleState();
}
class _AnimatedContainerExampleState extends State<AnimatedContainerExample> {
bool _expanded = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_expanded = !_expanded;
});
},
child: Center(
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: _expanded ? 200.0 : 100.0,
height: _expanded ? 200.0 : 100.0,
color: _expanded ? Colors.blue : Colors.red,
alignment: _expanded ? Alignment.center : Alignment.topLeft,
child: const Text('点击我'),
),
),
);
}
}
效果说明:
duration动画持续时间curve动画曲线(缓入缓出、线性等)- 属性值改变时自动播放过渡动画
- 支持 width、height、color、alignment 等属性
AnimatedOpacity
dart
AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: const Duration(milliseconds: 500),
child: const Text('淡入淡出'),
)
AnimatedPositioned
dart
Stack(
children: [
AnimatedPositioned(
duration: const Duration(milliseconds: 300),
top: _moved ? 100.0 : 50.0,
left: _moved ? 100.0 : 50.0,
child: const Text('移动动画'),
),
],
)
3.2 显式动画
需要更精细控制时使用显式动画。
dart
class ExplicitAnimationExample extends StatefulWidget {
const ExplicitAnimationExample({super.key});
@override
State<ExplicitAnimationExample> createState() => _ExplicitAnimationExampleState();
}
class _ExplicitAnimationExampleState extends State<ExplicitAnimationExample>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = Tween<double>(
begin: 0.0,
end: 300.0,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: 100,
color: Colors.blue,
);
},
),
ElevatedButton(
onPressed: () {
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
},
child: const Text('播放动画'),
),
],
);
}
}
效果说明:
AnimationController控制动画播放Tween定义动画值的变化范围CurvedAnimation添加动画曲线AnimatedBuilder监听动画值变化并重建 UIforward()正向播放,reverse()反向播放
3.3 Hero 动画
Hero 动画实现页面间组件的平滑过渡。
dart
// 第一页
class FirstPage extends StatelessWidget {
const FirstPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondPage()),
);
},
child: Hero(
tag: 'image-hero',
child: Image.network(
'https://example.com/image.jpg',
width: 100,
height: 100,
),
),
),
);
}
}
// 第二页
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Hero(
tag: 'image-hero',
child: Image.network(
'https://example.com/image.jpg',
width: 300,
height: 300,
),
),
),
);
}
}
效果说明:
Hero组件的tag必须相同- 跳转时图片会从小图平滑过渡到大图
- 适合图片预览、卡片展开等场景
4. 自定义组件
4.1 组合现有组件
通过组合现有组件创建可复用的自定义组件。
dart
class CustomCard extends StatelessWidget {
final String title;
final String description;
final VoidCallback onTap;
const CustomCard({
super.key,
required this.title,
required this.description,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Card(
elevation: 4,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
description,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
),
),
),
);
}
}
// 使用自定义组件
CustomCard(
title: '卡片标题',
description: '卡片描述内容',
onTap: () => print('卡片被点击'),
)
效果说明:
- 使用
final声明组件属性 required标记必填参数- 组合 Card、InkWell、Padding 等现有组件
- 提供回调函数处理交互
4.2 CustomPaint 自定义绘制
使用 CustomPaint 绘制自定义图形。
dart
class CustomPaintExample extends StatelessWidget {
const CustomPaintExample({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: CustomPaint(
size: const Size(200, 200),
painter: MyPainter(),
),
);
}
}
class MyPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
// 绘制圆形
canvas.drawCircle(
Offset(size.width / 2, size.height / 2),
size.width / 2,
paint,
);
// 绘制矩形
paint.color = Colors.red;
canvas.drawRect(
Rect.fromLTWH(50, 50, 100, 100),
paint,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
效果说明:
CustomPaint需要配合CustomPainter使用paint方法中执行绘制操作Canvas提供绘制 API(drawCircle、drawRect 等)Paint设置画笔样式(颜色、填充模式等)
5. 主题与样式
5.1 ThemeData 配置
全局配置应用主题。
dart
MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
appBarTheme: const AppBarTheme(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
textTheme: const TextTheme(
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
bodyLarge: TextStyle(fontSize: 16),
),
),
home: const HomePage(),
)
效果说明:
primarySwatch设置主色调colorScheme定义颜色方案appBarTheme统一配置 AppBar 样式textTheme配置全局文字样式
5.2 动态主题切换
支持亮色/暗色主题切换。
dart
class ThemeApp extends StatefulWidget {
const ThemeApp({super.key});
@override
State<ThemeApp> createState() => _ThemeAppState();
}
class _ThemeAppState extends State<ThemeApp> {
bool _isDarkMode = false;
void _toggleTheme() {
setState(() {
_isDarkMode = !_isDarkMode;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: _isDarkMode ? ThemeData.dark() : ThemeData.light(),
home: Scaffold(
appBar: AppBar(
title: const Text('主题切换'),
actions: [
IconButton(
icon: Icon(_isDarkMode ? Icons.light_mode : Icons.dark_mode),
onPressed: _toggleTheme,
),
],
),
body: const Center(child: Text('点击图标切换主题')),
),
);
}
}
效果说明:
ThemeData.dark()和ThemeData.light()提供预设主题- 通过状态管理切换主题
- 切换后整个应用的主题会自动更新
6. 国际化
6.1 配置国际化
添加依赖:
yaml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
配置 MaterialApp:
dart
MaterialApp(
supportedLocales: const [
Locale('en', 'US'),
Locale('zh', 'CN'),
],
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: const Locale('zh', 'CN'),
home: const HomePage(),
)
6.2 使用多语言
创建语言文件:
dart
// lib/l10n/app_localizations.dart
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}
Map<String, String> get _localizedValues {
return {
'en_US': {
'title': 'Home',
'welcome': 'Welcome',
},
'zh_CN': {
'title': '首页',
'welcome': '欢迎',
},
}[locale.toString()]!;
}
String get title => _localizedValues['title']!;
String get welcome => _localizedValues['welcome']!;
}
使用多语言:
dart
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context);
return Scaffold(
appBar: AppBar(title: Text(localizations.title)),
body: Center(child: Text(localizations.welcome)),
);
}
}
效果说明:
supportedLocales定义支持的语言列表localizationsDelegates提供本地化资源- 通过
AppLocalizations.of(context)获取当前语言的文字
💡 综合实战案例
新闻列表应用
结合路由、网络请求、动画等知识,实现一个完整的新闻列表应用。
dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(const NewsApp());
}
class NewsApp extends StatelessWidget {
const NewsApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '新闻列表',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const NewsListPage(),
);
}
}
class NewsItem {
final String title;
final String description;
final String imageUrl;
final String url;
NewsItem({
required this.title,
required this.description,
required this.imageUrl,
required this.url,
});
factory NewsItem.fromJson(Map<String, dynamic> json) {
return NewsItem(
title: json['title'] ?? '',
description: json['description'] ?? '',
imageUrl: json['urlToImage'] ?? '',
url: json['url'] ?? '',
);
}
}
class NewsListPage extends StatefulWidget {
const NewsListPage({super.key});
@override
State<NewsListPage> createState() => _NewsListPageState();
}
class _NewsListPageState extends State<NewsListPage> {
List<NewsItem> _newsList = [];
bool _isLoading = true;
String _errorMessage = '';
@override
void initState() {
super.initState();
_fetchNews();
}
Future<void> _fetchNews() async {
try {
setState(() {
_isLoading = true;
_errorMessage = '';
});
final response = await http.get(
Uri.parse('https://newsapi.org/v2/top-headlines?country=cn&apiKey=YOUR_API_KEY'),
).timeout(const Duration(seconds: 10));
if (response.statusCode == 200) {
final data = json.decode(response.body);
final List<dynamic> articles = data['articles'] ?? [];
setState(() {
_newsList = articles
.map((json) => NewsItem.fromJson(json))
.where((item) => item.title.isNotEmpty)
.toList();
_isLoading = false;
});
} else {
setState(() {
_errorMessage = '加载失败: ${response.statusCode}';
_isLoading = false;
});
}
} catch (e) {
setState(() {
_errorMessage = '网络错误: $e';
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('新闻列表'),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _fetchNews,
),
],
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: _errorMessage.isNotEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_errorMessage),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _fetchNews,
child: const Text('重试'),
),
],
),
)
: RefreshIndicator(
onRefresh: _fetchNews,
child: ListView.builder(
itemCount: _newsList.length,
itemBuilder: (context, index) {
final news = _newsList[index];
return NewsCard(news: news);
},
),
),
);
}
}
class NewsCard extends StatelessWidget {
final NewsItem news;
const NewsCard({super.key, required this.news});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewsDetailPage(news: news),
),
);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (news.imageUrl.isNotEmpty)
Image.network(
news.imageUrl,
width: double.infinity,
height: 200,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
height: 200,
color: Colors.grey[300],
child: const Icon(Icons.broken_image, size: 50),
);
},
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
news.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
Text(
news.description,
style: const TextStyle(fontSize: 14, color: Colors.grey),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
);
}
}
class NewsDetailPage extends StatelessWidget {
final NewsItem news;
const NewsDetailPage({super.key, required this.news});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('新闻详情')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (news.imageUrl.isNotEmpty)
Hero(
tag: news.imageUrl,
child: Image.network(
news.imageUrl,
width: double.infinity,
height: 250,
fit: BoxFit.cover,
),
),
const SizedBox(height: 16),
Text(
news.title,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Text(
news.description,
style: const TextStyle(fontSize: 16),
),
],
),
),
);
}
}
效果说明:
- 使用
http包获取新闻数据 - 使用
ListView.builder展示新闻列表 - 使用
RefreshIndicator实现下拉刷新 - 使用
Hero动画实现图片平滑过渡 - 包含完整的错误处理和加载状态
❓ 常见问题 FAQ
1. 如何在页面跳转时传递复杂对象?
解答 :
直接传递对象实例即可:
dart
class User {
final String name;
final int age;
User(this.name, this.age);
}
// 跳转
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailPage(user: user),
),
);
// 接收
class DetailPage extends StatelessWidget {
final User user;
const DetailPage({super.key, required this.user});
}
2. 网络请求失败如何重试?
解答 :
使用 try-catch 和循环实现重试:
dart
Future<T> retryRequest<T>(
Future<T> Function() request,
int maxRetries,
) async {
for (int i = 0; i < maxRetries; i++) {
try {
return await request();
} catch (e) {
if (i == maxRetries - 1) rethrow;
await Future.delayed(Duration(seconds: i + 1));
}
}
throw Exception('重试失败');
}
3. 如何优化列表滚动性能?
解答:
- 使用
ListView.builder代替ListView - 图片使用
cacheWidth和cacheHeight限制尺寸 - 避免在
itemBuilder中创建复杂组件
dart
Image.network(
url,
cacheWidth: 400,
cacheHeight: 300,
)
4. 动画卡顿如何优化?
解答:
- 使用
const组件减少重建 - 避免在
build方法中执行耗时操作 - 使用
RepaintBoundary隔离重绘区域
dart
RepaintBoundary(
child: AnimatedContainer(...),
)
5. 如何全局管理用户登录状态?
解答 :
使用 ValueNotifier 或第三方状态管理库:
dart
final userNotifier = ValueNotifier<User?>(null);
// 监听
ValueListenableBuilder<User?>(
valueListenable: userNotifier,
builder: (context, user, child) {
return user != null ? HomePage() : LoginPage();
},
)
📝 总结
本文介绍了 Flutter 进阶开发的核心技能:
知识点回顾
| 模块 | 核心内容 | 重要程度 |
|---|---|---|
| 路由导航 | push/pop、命名路由、传参 | ⭐⭐⭐⭐⭐ |
| 网络请求 | http、GET/POST、错误处理 | ⭐⭐⭐⭐⭐ |
| 动画系统 | 隐式动画、显式动画、Hero | ⭐⭐⭐⭐ |
| 自定义组件 | 组合组件、CustomPaint | ⭐⭐⭐⭐ |
| 主题与国际化 | ThemeData、多语言 | ⭐⭐⭐ |
学习建议
- 多实践:网络请求和动画需要大量练习
- 看源码:学习官方组件的实现方式
- 性能优化:关注列表滚动和动画性能
- 错误处理:完善的错误处理是商业应用的必备条件
下一步学习
- 状态管理进阶(Provider、Riverpod、Bloc)
- 本地存储(SharedPreferences、SQLite)
- 表单验证
- 测试与调试