Flutter入门
# 创建应用
Set up and test drive Flutter (opens new window)
# 构建界面
# widget
# StatelessWidget - 无状态组件
纯展示型组件,没有用户交互操作
class MainPage extends StatelessWidget {
const MainPage({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Demo Home Page'),
),
body: Center(
child: Text('Hello, World!'),
),
),
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 生命周期
无状态组件 ‑ 唯一阶段 build 方法
当组件被创建或父组件状态变化导致其需要重新构建时,build 方法会被调用
# StatefulWidget - 有状态组件
有状态组件是构建动态交互界面的核心,能够管理变化的内部状态,当状态改变时,组件会更新显示内容
// 第一个类对外
class Main1 extends StatefulWidget {
State<StatefulWidget> createState() {
return _Main1State();
}
}
// 第二个类对内 负责管理数据 处理业务逻辑 并渲染视图
class _Main1State extends State<Main1> {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(title: Text('有状态组件')),
body: Center(child: Text('Hello, World!')),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
IconButton(icon: Icon(Icons.home), onPressed: () {}),
],
),
),
),
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 生命周期
| 生命周期阶段 | 函数名 | 调用时机与核心任务 |
|---|---|---|
| 创建阶段 | createState() | Widget 初始化调用,创建 State 对象,仅执行一次 |
| 创建阶段 | initState() | State 对象插入 Widget 树立刻执行,仅执行一次 |
| 创建阶段 | didChangeDependencies() | initState 后立刻执行,当所依赖的 InheritedWidget 更新时调用,可能多次 |
| 构建与更新阶段 | build() | 构建 UI 方法,初始化或更新后多次调用 |
| 构建与更新阶段 | didUpdateWidget() | 父组件传入新配置时调用,用于比较新旧配置 |
| 销毁阶段 | deactiveate() | 当 State 对象从树中暂时移除时调用 |
| 销毁阶段 | dispose() | 当 State 对象被永久移除时调用,释放资源,仅执行一次 |
import 'package:flutter/material.dart';
void main() {
runApp(Main1());
}
class Main1 extends StatefulWidget {
const Main1({super.key});
State<Main1> createState() {
print("createState called");
return _Main1State();
}
}
class _Main1State extends State<Main1> {
void initState() {
print("initState called");
// TODO: implement initState
super.initState();
}
void didChangeDependencies() {
print("didChangeDependencies called");
// TODO: implement didChangeDependencies
super.didChangeDependencies();
}
void didUpdateWidget(covariant Main1 oldWidget) {
print("didUpdateWidget called");
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
}
void deactivate() {
// TODO: implement deactivate
print("deactivate called");
super.deactivate();
}
void dispose() {
// TODO: implement dispose
print("dispose called");
super.dispose();
}
Widget build(BuildContext context) {
print("build called");
return const Placeholder();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# Material
- MaterialApp Material风格
- Scaffold 骨架
- 组件
# 点击事件
// GestureDetector
body: GestureDetector(
onTap: () {
print("Navigating to second page");
},
child: Center(child: Text('Tap to go to second page')),
),
// TextButton
body: TextButton(
onPressed: () {
print("Navigating to second page");
},
child: Center(child: Text('Tap to go to second page')),
),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| 组件类别 | 核心组件 | 主要特点 / 使用场景 |
|---|---|---|
| 专用按钮组件 | ElevatedButton、TextButton、OutlineButton、FloatingActionButton | 内置点击动画和样式,通过 onPressed 参数处理点击逻辑 |
| 视觉反馈组件 | InkWell | 提供点击事件 (onTap),有 MaterialDesign 风格的水纹扩散效果 |
| 其他交互组件 | IconButton、Switch、Checkbox | 具有特定功能的交互式控件、点击事件 (onPressed) |
# 状态更新
class MainPage extends StatefulWidget {
const MainPage({super.key});
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int count = 0;
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(title: Text('Flutter Demo Home Page')),
body: Center(
child: Row(
children: [
TextButton(onPressed: () {
setState(() {
count -= 1;
});
}, child: Text("-")),
Text(count.toString()),
TextButton(onPressed: () {
setState(() {
count += 1;
});
}, child: Text("+")),
],
),
)
),
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 组件
| 组件类别 | 核心组件 | 主要特点 / 使用场景 |
|---|---|---|
| 基础容器 | Container、Center、Align、Padding | 提供装饰、对齐、边距等基础样式和布局控制,是使用频率极高的组件 |
| 线性布局 | Row、Column | 在水平或垂直方向线性排列子组件,是构建界面的基础 |
| 弹性布局 | Flex, Expanded, Flexible | 按照比例分配剩余空间,实现自适应布局,常与 Row 和 Column 配合使用 |
| 层叠布局 | Stack, Positioned | 让子组件重叠堆叠,用于实现如图片上叠加文字、悬浮按钮等效果 |
| 流式布局 | Wrap, Flow | 当主轴空间不足时自动换行或换列,常用于标签、滤镜等动态宽高内容的排列 |
| 滚动布局 | ListView, GridView | 提供可滚动的列表或网格视图,高效展示大量数据 |
# 组件通信
父传子
// 父组件
Child(
name:"Tom",
)
// 子组件接收:
class Child extends StatelessWidget {
final String name;
const Child({
required this.name
});
Widget build(BuildContext context){
return Text(name);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
子传父
// 父
Child(
onTap:(value){
print(value);
}
)
// 子
class Child extends StatelessWidget{
final Function(String) onTap;
Child({
required this.onTap
});
void click(){
onTap("hello");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 网络请求
Flutter 常用网络库:dio
# GET请求
import 'package:dio/dio.dart';
Dio dio = Dio();
void getData() async {
Response response = await dio.get(
"https://api.xxx.com/user"
);
print(response.data);
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
请求参数
dio.get(
"/user",
queryParameters:{
"id":1
}
);
1
2
3
4
5
6
2
3
4
5
6
请求Header
dio.get(
"/user",
options:Options(
headers:{
"Authorization":
"Bearer token"
}
)
);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# POST请求
dio.post(
"/login",
data:{
"username":"admin",
"password":"123456"
}
);
1
2
3
4
5
6
7
2
3
4
5
6
7
封装 Dio 工具
lib
|
├── network
│
├── dio_client.dart
│
├── api.dart
│
└── interceptor.dart
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# Dio拦截器
请求拦截
dio.interceptors.add(
InterceptorsWrapper(
onRequest:(options,handler){
options.headers["token"]
="xxxx";
handler.next(options);
}
)
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
响应拦截
onResponse:
(response,handler){
print(response.data);
handler.next(response);
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
错误拦截
onError:(error,handler){
if(error.response?.statusCode==401){
//跳登录
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
跨域提示错误
默认情况下,flutter 运行 web 端加载网络资源会报跨域提示错误
补充提醒:修改 flutter 源码只适合本地开发调试,打包上线 web 不能依赖这个方案,上线要后端配置 CORS 跨域。
在 flutter/packages/flutter_tools/lib/src/web/chrome.dart;如下图位置添加
'--disable‑web‑security','--disable‑extensions', '--disable‑popup‑blocking', '--bwsi', '--no‑first‑run', '--no‑default‑browser‑check', '--disable‑default‑apps', '--disable‑translate', '--disable‑web‑security', // Remove the search‑engine‑choice screen. It's irrelevant // debugging purposes. // See: https://github.com/flutter/flutter/issues/153928 '--disable‑search‑engine‑choice‑screen', '--no‑sandbox',1
2
3
4
5
6
7
8
9
10
11
12
13删除 flutter/bin/cache/ 下
flutter_tools.snapshot和flutter_tools.stamp执行
flutter doctor -v然后重新运行项目
# 路由管理
MaterialApp(
home:HomePage()
)
1
2
3
4
5
2
3
4
5
跳转
Navigator.push(
context,
MaterialPageRoute(
builder:(context){
return DetailPage();
}
)
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
返回
Navigator.pop(context);
1
命名路由
MaterialApp(
routes:{
"/home": (context)=>HomePage(),
"/detail": (context)=>DetailPage()
}
)
Navigator.pushNamed(
context,
"/detail"
);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
命名路由传参数
Navigator.pushNamed(
context,
"/detail",
arguments:{
"id":100
}
);
var args =
ModalRoute.of(context)!
.settings
.arguments;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
基本路由传参
Navigator.push(
context,
MaterialPageRoute(
builder:(context){
return DetailPage(
id:100
);
}
)
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
高级路由控制
可以使用:
- GetX
- GoRouter
404路由
MaterialApp(
onUnknownRoute:(settings){
return MaterialPageRoute(
builder:(context){
return NotFoundPage();
}
);
}
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上次更新: 2026/09/10, 02:28:42