外观
Flutter 核心开发指南
约 3382 字大约 11 分钟
2025-08-24
1. 基础概念
1.1 Flutter 简介
Flutter 是 Google 开发的开源 UI 框架,用于构建高性能、跨平台的应用程序。使用单一代码库可同时开发:
- iOS 和 Android 移动应用
- Web 应用
- Windows、macOS 和 Linux 桌面应用
核心优势:高性能渲染引擎、热重载、丰富的组件库、单一代码库多平台部署
1.2 核心理念:一切皆 Widget
在 Flutter 中,所有 UI 元素都是 Widget,包括布局、控件、动画等。Widget 分为两类:
- StatelessWidget:无状态的静态 UI 元素
- StatefulWidget:有状态的动态 UI 元素
// StatelessWidget 示例
class GreetingWidget extends StatelessWidget {
final String name;
const GreetingWidget({required this.name, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text('Hello, $name!');
}
}
// StatefulWidget 示例
class CounterWidget extends StatefulWidget {
const CounterWidget({Key? key}) : super(key: key);
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Increment'),
),
],
);
}
}最佳实践:优先使用 StatelessWidget,仅在需要管理状态时使用 StatefulWidget
2. 开发环境搭建
2.1 安装 Flutter
- 下载 Flutter SDK:Flutter 官网下载页面
- 解压并添加到系统路径
- 运行
flutter doctor检查环境(会自动提示需要安装的依赖)
2.2 配置 IDE
VS Code(推荐):
- 安装 VS Code
- 安装 Flutter 和 Dart 扩展
- 按
Ctrl+Shift+P输入 "Flutter" 可查看所有 Flutter 命令
Android Studio:
- 安装 Android Studio
- 安装 Flutter 和 Dart 插件
- 使用菜单中的 Flutter 选项创建和管理项目
2.3 创建和运行项目
# 创建新项目
flutter create my_app
# 进入项目目录
cd my_app
# 连接设备或启动模拟器
flutter devices
# 运行应用
flutter run开发技巧:
- 使用
flutter run -d chrome在浏览器中运行 Web 应用- 按
r键进行热重载(保持状态)- 按
R键进行完全重启
3. 基础组件(最常用 20 个)
3.1 文本与容器
| 组件 | 用途 | 示例 |
|---|---|---|
Text | 显示文本 | Text('Hello Flutter', style: TextStyle(fontSize: 20)) |
Container | 通用容器 | Container(padding: EdgeInsets.all(16), color: Colors.grey, child: Text('Content')) |
SizedBox | 指定尺寸的空白 | SizedBox(height: 20) |
Padding | 添加内边距 | Padding(padding: EdgeInsets.all(8), child: Text('With padding')) |
3.2 按钮组件
| 组件 | 用途 | 示例 |
|---|---|---|
ElevatedButton | 带阴影的按钮 | ElevatedButton(onPressed: () {}, child: Text('Click')) |
TextButton | 文本按钮 | TextButton(onPressed: () {}, child: Text('Text Button')) |
IconButton | 图标按钮 | IconButton(icon: Icon(Icons.add), onPressed: () {}) |
FloatingActionButton | 悬浮操作按钮 | FloatingActionButton(onPressed: () {}, child: Icon(Icons.add)) |
3.3 布局组件
| 组件 | 用途 | 示例 |
|---|---|---|
Column | 垂直布局 | Column(children: [Text('Top'), Text('Bottom')]) |
Row | 水平布局 | Row(children: [Text('Left'), Text('Right')]) |
Stack | 堆叠布局 | Stack(children: [Container(color: Colors.red), Positioned(top: 10, child: Icon(Icons.star))]) |
Expanded | 扩展填充空间 | Row(children: [Expanded(child: Text('Takes all space'))]) |
ListView | 滚动列表 | ListView(children: [ListTile(title: Text('Item 1'))]) |
GridView | 网格布局 | GridView.count(crossAxisCount: 2, children: [Text('1'), Text('2')]) |
3.4 表单组件
| 组件 | 用途 | 示例 |
|---|---|---|
TextField | 文本输入 | TextField(decoration: InputDecoration(labelText: 'Name')) |
Form | 表单容器 | Form(key: _formKey, child: TextFormField(...)) |
Checkbox | 复选框 | Checkbox(value: _isChecked, onChanged: (v) => setState(() => _isChecked = v!)) |
Radio | 单选按钮 | Radio(value: 1, groupValue: _selected, onChanged: (v) => setState(() => _selected = v!)) |
最佳实践:
- 优先使用 Material 组件(ElevatedButton 而不是 RaisedButton)
- 使用
const构造函数优化性能:const Text('Hello')- 避免过度嵌套,使用
SizedBox代替空 Container
4. 布局系统(核心)
4.1 Flex 布局(Column & Row)
Flutter 的布局系统基于 Flex 布局,类似于 CSS 的 Flexbox。
Column(
mainAxisAlignment: MainAxisAlignment.center, // 主轴对齐方式
crossAxisAlignment: CrossAxisAlignment.stretch, // 交叉轴对齐方式
children: [
Text('Top'),
const SizedBox(height: 10), // 间距
Expanded( // 占据剩余空间
child: Container(color: Colors.blue),
),
Text('Bottom'),
],
)常用属性:
mainAxisAlignment:主轴对齐方式(start,center,end,spaceBetween,spaceAround,spaceEvenly)crossAxisAlignment:交叉轴对齐方式mainAxisSize:主轴大小(min最小,max最大)Expanded:扩展子项以填充剩余空间Flexible:类似 Expanded,但可设置 flex 因子
4.2 Stack 布局
用于创建堆叠效果,子组件可以重叠:
Stack(
alignment: Alignment.center, // 所有子项的对齐方式
children: [
Container(
width: 200,
height: 200,
color: Colors.red,
),
Positioned( // 精确控制位置
top: 20,
right: 20,
child: Icon(Icons.star, size: 40),
),
Positioned(
bottom: 20,
left: 20,
child: Text('Bottom Left'),
),
],
)4.3 常用布局技巧
// 1. 创建响应式布局
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return _buildWideLayout();
} else {
return _buildNarrowLayout();
}
},
)
// 2. 创建卡片式布局
Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Image.network('https://example.com/image.jpg'),
Text('Card Title', style: Theme.of(context).textTheme.headline6),
Text('Card content goes here...'),
],
),
),
)
// 3. 创建列表项
ListTile(
leading: CircleAvatar(child: Text('K')),
title: Text('Kimi'),
subtitle: Text('Flutter Developer'),
trailing: Icon(Icons.arrow_forward),
onTap: () => print('Tapped'),
)5. 状态管理(核心重点)
5.1 StatefulWidget 基础
最简单的状态管理方式,适用于组件内部状态:
class CounterPage extends StatefulWidget {
const CounterPage({Key? key}) : super(key: key);
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text('$_counter', style: Theme.of(context).textTheme.headline4),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}限制:仅适用于单一组件内部状态,不适合跨组件共享状态
5.2 Provider(最推荐的第三方方案)
Provider 是官方推荐的状态管理方案,简单易用且功能强大。
1. 添加依赖 (pubspec.yaml):
dependencies:
flutter:
sdk: flutter
provider: ^6.0.52. 创建状态模型:
class CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 通知监听者更新
}
}3. 在应用顶层提供状态:
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: const MyHomePage(),
);
}
}4. 消费状态:
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Consumer<CounterModel>(
builder: (context, counterModel, child) {
return Text(
'${counterModel.count}',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterModel>().increment(),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}关键方法:
context.watch<T>():监听状态变化并重建 UIcontext.read<T>():读取状态但不监听变化context.select<T, R>(R cb(T value)):仅监听状态的部分属性
5.3 Riverpod(现代替代方案)
Riverpod 是 Provider 的改进版,解决了 Provider 的一些限制,如无法在 initState 中使用等。
1. 添加依赖:
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.3.62. 创建状态提供器:
final counterProvider = StateProvider<int>((ref) => 0);3. 在应用顶层设置:
void main() {
runApp(
const ProviderScope( // 注意:使用 ProviderScope 而不是 ChangeNotifierProvider
child: MyApp(),
),
);
}4. 使用状态:
class MyHomePage extends ConsumerWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider).state;
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text(
'$counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider).state++,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}最佳实践:
- 小型应用:使用 StatefulWidget
- 中型应用:使用 Provider
- 大型应用或新项目:使用 Riverpod
- 避免过度使用全局状态,只将需要共享的状态提升
6. 路由与导航
6.1 基本页面导航
// 导航到新页面
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondScreen()),
);
},
child: const Text('Go to Second Screen'),
)
// 返回上一页
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Go Back'),
)6.2 传递参数
// 传递参数到新页面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserDetailsScreen(userId: 123),
),
);
// 在目标页面接收参数
class UserDetailsScreen extends StatelessWidget {
final int userId;
const UserDetailsScreen({required this.userId, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('User Details')),
body: Center(child: Text('User ID: $userId')),
);
}
}6.3 返回数据
// 从目标页面返回数据
ElevatedButton(
onPressed: () {
Navigator.pop(context, 'Data from second screen');
},
child: const Text('Return Data'),
)
// 接收返回的数据
void _navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondScreen()),
);
if (result != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Popped value: $result')),
);
}
}6.4 命名路由(推荐用于中大型应用)
// 1. 定义路由表
final routes = <String, Widget Function(BuildContext)>{
'/': (_) => const HomeScreen(),
'/user': (_) => const UserListScreen(),
'/user/:id': (_) => const UserDetailsScreen(),
'/settings': (_) => const SettingsScreen(),
};
// 2. 在 MaterialApp 中配置
MaterialApp(
initialRoute: '/',
routes: routes,
)
// 3. 使用命名路由导航
Navigator.pushNamed(context, '/user/123');
// 4. 从命名路由获取参数(使用 go_router 或 fluro 等包更简单)
// 但基础版可以这样:
String? userId = ModalRoute.of(context)?.settings.name?.split('/').last;最佳实践:
- 小型应用:使用基本路由
- 中大型应用:使用命名路由
- 复杂应用:使用 go_router 包(官方推荐的路由解决方案)
7. 网络请求与数据处理
7.1 使用 http 包
1. 添加依赖:
dependencies:
http: ^0.13.62. 发起 GET 请求:
Future<String> fetchQuote() async {
final response = await http.get(
Uri.parse('https://api.quotable.io/random'),
);
if (response.statusCode == 200) {
return response.body;
} else {
throw Exception('Failed to load quote');
}
}3. 在 UI 中使用:
class QuoteScreen extends StatelessWidget {
const QuoteScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Quotes')),
body: FutureBuilder<String>(
future: fetchQuote(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
// 处理 JSON 数据
final quote = json.decode(snapshot.data!);
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
quote['content'],
style: const TextStyle(fontSize: 24),
),
const SizedBox(height: 20),
Text('- ${quote['author']}'),
],
),
);
}
},
),
);
}
}7.2 使用 dio 包(更强大的替代方案)
dependencies:
dio: ^5.3.3final dio = Dio();
Future<Map<String, dynamic>> fetchUser(int userId) async {
final response = await dio.get(
'https://jsonplaceholder.typicode.com/users/$userId',
);
return response.data;
}
// 使用拦截器处理请求和响应
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 添加认证头
options.headers['Authorization'] = 'Bearer token';
return handler.next(options);
},
onResponse: (response, handler) {
// 处理响应
return handler.next(response);
},
onError: (error, handler) {
// 处理错误
return handler.next(error);
},
));7.3 JSON 序列化
1. 使用 json_serializable 包:
dependencies:
json_annotation: ^4.8.1
dev_dependencies:
build_runner: ^2.4.8
json_serializable: ^6.7.02. 创建数据模型:
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}3. 生成代码:
flutter pub run build_runner build4. 使用:
// 解析 JSON
final user = User.fromJson(json.decode(response.body));
// 生成 JSON
final json = user.toJson();最佳实践:
- 简单项目:使用 http + 手动 JSON 处理
- 中大型项目:使用 dio + json_serializable
- 使用 FutureBuilder 或 StreamBuilder 处理异步数据
- 考虑使用 Repository 模式分离数据获取逻辑
8. 数据持久化
8.1 shared_preferences(简单键值存储)
1. 添加依赖:
dependencies:
shared_preferences: ^2.2.22. 使用示例:
// 保存数据
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', 'kimi');
await prefs.setInt('age', 25);
await prefs.setBool('isLoggedIn', true);
// 读取数据
String? username = prefs.getString('username');
int age = prefs.getInt('age') ?? 0;
bool isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
// 删除数据
await prefs.remove('username');8.2 Hive(轻量级数据库)
1. 添加依赖:
dependencies:
hive: ^2.2.5
hive_flutter: ^1.1.02. 初始化 Hive:
void main() async {
await Hive.initFlutter();
Hive.registerAdapter(UserAdapter()); // 注册适配器
await Hive.openBox<User>('users');
runApp(MyApp());
}3. 创建数据模型:
import 'package:hive/hive.dart';
part 'user.g.dart';
@HiveType(typeId: 0)
class User {
@HiveField(0)
final int id;
@HiveField(1)
final String name;
User({required this.id, required this.name});
}4. 生成适配器:
flutter packages pub run build_runner build5. 使用示例:
// 获取 box
var usersBox = Hive.box<User>('users');
// 添加数据
usersBox.add(User(id: 1, name: 'Kimi'));
// 查询数据
User user = usersBox.get(0)!;
List<User> allUsers = usersBox.values.toList();
// 更新数据
usersBox.put(0, User(id: 1, name: 'Updated Name'));
// 删除数据
usersBox.delete(0);最佳实践:
- 简单数据:shared_preferences
- 结构化数据:Hive
- 复杂关系型数据:考虑 drift (原 moor) 或 sqflite
9. 常用工具与技巧
9.1 异步处理技巧
// 顺序执行多个异步操作
Future<void> sequentialProcess() async {
try {
final data1 = await fetchFirst();
final data2 = await fetchSecond(data1);
print('$data1, $data2');
} catch (e) {
print('Error: $e');
}
}
// 并行执行多个异步操作
Future<void> parallelProcess() async {
try {
final results = await Future.wait([
fetchFirst(),
fetchSecond(),
fetchThird(),
]);
print(results);
} catch (e) {
print('Error: $e');
}
}9.2 常用扩展方法
// 在项目中创建 extensions.dart 文件
extension StringExtensions on String {
bool get isNumeric => int.tryParse(this) != null;
String capitalize() => '${this[0].toUpperCase()}${substring(1)}';
}
extension ListExtensions<T> on List<T> {
T? get safeFirst => isEmpty ? null : first;
T? get safeLast => isEmpty ? null : last;
}
// 使用示例
print('123'.isNumeric); // true
print('hello'.capitalize()); // Hello
print([1, 2, 3].safeFirst); // 19.3 调试技巧
// 1. 使用 debugPrint 代替 print(避免日志被截断)
import 'package:flutter/foundation.dart';
debugPrint('This is a debug message');
// 2. 使用 Flutter DevTools
void main() {
debugPaintSizeEnabled = true; // 显示布局边界
debugPaintBaselinesEnabled = true; // 显示基线
runApp(MyApp());
}
// 3. 使用 widget inspector
// 在 DevTools 中点击 "Inspect Widget" 按钮9.4 性能优化技巧
// 1. 使用 const 构造函数
Widget build(BuildContext context) {
return const Column( // 注意 const
children: [
Text('Hello'), // 如果 Text 也是 const
SizedBox(height: 8), // const
],
);
}
// 2. 使用 ListView.builder 替代 ListView
ListView.builder(
itemCount: 1000,
itemBuilder: (context, index) {
return const ListTile( // 注意 const
title: Text('Item'),
);
},
)
// 3. 避免在 build 方法中创建新对象
@override
Widget build(BuildContext context) {
// 错误:每次构建都创建新对象
// return Text(DateTime.now().toString());
// 正确:在 state 中保存
// return Text(_currentTime);
}10. 常见问题与解决方案
10.1 状态管理选择困惑
- 小型应用:使用 StatefulWidget 的 setState
- 中型应用:使用 Provider
- 大型应用:使用 Riverpod 或 Bloc
- 简单共享数据:使用 InheritedWidget 或 GetX
10.2 布局溢出问题
// 解决 Overflowed by X pixels on the bottom/right 问题
Scaffold(
body: SingleChildScrollView( // 添加 SingleChildScrollView
child: Column(
children: [
// 长内容
],
),
),
)
// 或者使用 Expanded
Column(
children: [
Expanded( // 让 ListView 占据剩余空间
child: ListView(
children: [...],
),
),
],
)10.3 异步数据加载状态管理
enum LoadingState { idle, loading, success, error }
class DataScreen extends StatefulWidget {
const DataScreen({Key? key}) : super(key: key);
@override
State<DataScreen> createState() => _DataScreenState();
}
class _DataScreenState extends State<DataScreen> {
LoadingState _state = LoadingState.idle;
String? _data;
String? _error;
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
setState(() => _state = LoadingState.loading);
try {
final data = await fetchData();
setState(() {
_state = LoadingState.success;
_data = data;
});
} catch (e) {
setState(() {
_state = LoadingState.error;
_error = e.toString();
});
}
}
@override
Widget build(BuildContext context) {
switch (_state) {
case LoadingState.idle:
case LoadingState.loading:
return const Center(child: CircularProgressIndicator());
case LoadingState.success:
return Text(_data!);
case LoadingState.error:
return Center(child: Text('Error: $_error'));
}
}
}11. 总结
本文涵盖了 Flutter 开发中最核心、最常用的 80% 知识点,包括:
- 基础概念:Widget 系统、StatelessWidget 与 StatefulWidget
- 基础组件:最常用的 20 个 UI 组件
- 布局系统:Column、Row、Stack 等核心布局
- 状态管理:StatefulWidget、Provider、Riverpod
- 路由与导航:页面跳转与参数传递
- 网络请求:http 和 dio 包的使用
- 数据持久化:shared_preferences 和 Hive
- 实用技巧:异步处理、调试、性能优化
掌握这些内容足以开发大多数 Flutter 应用,特别是移动端应用。随着经验增长,可以按需学习更高级的主题,如复杂动画、自定义渲染、高级状态管理等。
