今天来学习flutter的几个基本组件

基础组件

Scaffold组件

1
2
3
4
5
6
7
8
9
10
11
import 'package:flutter/material.dart'; //导入Material包

void main() {
runApp(
MaterialApp(
title: "终末地AI群聊",
theme: ThemeData(scaffoldBackgroundColor: Colors.lightBlueAccent),
home: Scaffold(),
),
);
}

上一篇我们学到的这个里有个Scaffold组件

image-20260420132350772

这里我们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import 'package:flutter/material.dart';

void main() {
runApp(
MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
//头部
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
//中部
body: Container(child: Center(child: Text("终末地AI群聊"))),
//底部
bottomNavigationBar: Container(
height: 80.0,
child: Center(child: Text("终末地AI群聊")),
),
),
),
);
}

image-20260420135410738

  • MaterialApp包裹整个应用形成统一的Material Design风格
  • Scoffold组件可快速搭建页面骨架,如appBarbodybottomNavigationBar
  • Container用来作为容器,设置高度(height),child用来存放子组件
  • Text是用来显示文本的组件

自定义组件(Customwidget)

image-20260420142055618

其实

  • StatelessWidget = 静态组件(数据显示后自己不会变)
  • StatefulWidget = 动态组件(数据变了,界面会跟着变)

无状态组件(StatelessWidget)

创建一个新的类,继承StatelessWidget类并实现build方法

build返回一个Widget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

//无状态组件
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Container(child: Center(child: Text("终末地AI群聊"))),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}
}

image-20260420145629323

1
2
3
4
5
6
7
class Chatpage extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
}

我们把这个拆开来看

class Chatpage extends StatelessWidget继承 StatelessWidget,即定义了一个组件 Chatpage

Widget build(BuildContext context)必须重写 build(),这个的作用是返回要显示的UI,Flutter 会在 runApp();调用这个函数画界面

return .....;返回值是Widget类型,因为在flutter里面所有的组件都是widget类型

这里我们注意

“程序入口” = 应用从哪里开始跑 在flutter中就是runApp(这里必须是“根组件”)
“组件” = 页面里的一块积木,根组件就是MaterialApp

而所有组件必须在根组件里使用

main() → 启动
MyApp → 应用壳子
MaterialApp → App框架
Scaffold → 页面结构
Text / Button → UI组件

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
import 'package:flutter/material.dart';

void main() {
runApp(const MainPage());
}

// 无状态主页面
class MainPage extends StatelessWidget {
const MainPage({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: const Text("终末地AI群聊")),
body: const Center(child: MyText(title: "终末地AI群聊")),
bottomNavigationBar: Container(
height: 80,
alignment: Alignment.center,
child: const Text("底部栏"),
),
),
);//返回值是整个MaterialApp框架内所有东西
}
}

// 自定义无状态组件
class MyText extends StatelessWidget {
final String title;

const MyText({super.key, required this.title});

@override
Widget build(BuildContext context) {
return Text(title, style: const TextStyle(fontSize: 24)); //返回值是Text组件
}
}

image-20260420150951795

有状态组件(StatefulWidget)

有状态组件是构建动态交互界面的核心,能够管理变化的内部状态,当状态改变时,逐渐会更新显示内容

1
2
3
4
5
6
7
class MainPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
throw UnimplementedError();
}
}

class MainPage extends StatefulWidget 继承 StatelfulWidget,即定义了一个组件 Chatpage

Widget build(BuildContext context)必须重写 build(),这个的作用是返回要显示的UI,Flutter 会在 runApp();调用这个函数画界面

return .....;返回值是Widget类型,因为在flutter里面所有的组件都是widget类型

image-20260425122640439

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
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

class MainPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MainPageState();
}
}

class _MainPageState extends State<MainPage> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Container(child: Center(child: Text("终末地AI群聊"))),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}
}

快速创建无状态组件和有状态组件的方法

首先下载这仨插件

image-20260425123143670

然后我们在VScode中使用statelessWstatefulW按回车就可以快速创建

image-20260425123543708

这里补充一个知识,在VScode中批量变量名或者方法名的方式有以下几种

场景 推荐方法
少量变量 Ctrl + D
当前文件全部 Ctrl + Shift + L
整个项目 Ctrl + Shift + H
最安全(推荐) ⭐ F2
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
import 'package:flutter/material.dart';

void main() {
runApp(TestWidget());
}

class TestWidget extends StatefulWidget {
const TestWidget({super.key});

@override
State<TestWidget> createState() => _TestWidgetState();
}

class _TestWidgetState extends State<TestWidget> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Container(child: Center(child: Text("终末地AI群聊"))),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}
}

组件生命周期-无状态组件

无状态组件的生命周期只有一个阶段——build方法

这个阶段的过程是:

① 创建(构造函数)

Flutter 创建这个组件实例

1
MyWidget({super.key});

② build(构建 UI)

1
2
3
4
@override
Widget build(BuildContext context) {
return Text("Hello");
}

唯一核心生命周期方法

当组件被创建或者父组件状态变化导致其需要重新构建时,build方法会被调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

class MainPage extends StatelessWidget {
const MainPage({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Container(child: Center(child: Text("终末地AI群聊"))),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}
}

组件生命周期-有状态组件

image-20260425132140323

image-20260425132230255

有状态组件 = 可以随时间改变 UI 的组件

1
class MyWidget extends StatefulWidget

生命周期过程如下:创建 initState build(多次 setState → build)dispose

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
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

class MainPage extends StatefulWidget {
const MainPage({super.key});

//创建阶段 createState方法会被调用一次,创建一个状态对象
@override
State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
//初始化阶段 initState方法会被调用一次,进行一些初始化操作
@override
void initState() {
super.initState();
}

//依赖变化阶段 didChangeDependencies方法会被调用一次,进行一些依赖变化的操作
@override
void didChangeDependencies() {
super.didChangeDependencies();
}

//构建阶段 build方法会被调用多次,进行构建UI的操作
@override
Widget build(BuildContext context) {
return Container();
}

//更新阶段 didUpdateWidget方法会被调用多次,进行一些更新操作
@override
void didUpdateWidget(covariant MainPage oldWidget) {
super.didUpdateWidget(oldWidget);
}

//停用阶段 deactivate方法会被调用一次,进行一些停用操作
@override
void deactivate() {
super.deactivate();
}

//销毁阶段 dispose方法会被调用一次,进行一些销毁操作
@override
void dispose() {
super.dispose();
}
}
  • 无状态组件-build
  • 有状态组件(创建阶段):createState->initState->didchangeDependencies->build
  • 有状态组件(更新阶段):didUpdateWidget->build
  • 有状态组件(销毁阶段):deactivate->dispose
  • 执行一次函数:createState、initState、dispose
  • Inheritedwidget:专门用于在Widget树中自顶向下高效地共享数据,顶层组件提供数据,子孙节点直接获取

事件-点击事件GestureDetector

事件:用户与应用程序交互时触发的各种动作,比如触摸屏幕、滑动、点击等

点击事件:当点击某个元素触发的动作

常规方案:GestureDetector是Flutter中最常用、功能最丰富的手势检测组件

用法:使用GestureDetector包裹被点击的元素,传入onTap方法

image-20260425140015128

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

class MainPage extends StatefulWidget {
const MainPage({super.key});

//创建阶段 createState方法会被调用一次,创建一个状态对象
@override
State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
//初始化阶段 initState方法会被调用一次,进行一些初始化操作
@override
void initState() {
super.initState();
}

//依赖变化阶段 didChangeDependencies方法会被调用一次,进行一些依赖变化的操作
@override
void didChangeDependencies() {
super.didChangeDependencies();
}

//构建阶段 build方法会被调用多次,进行构建UI的操作
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Container(
child: Center(
//鼠标点击事件GestureDetector
child: GestureDetector(
//onTap就是单击事件,onDoubleTap就是双击事件
onTap: () {
// 处理点击事件
print("群聊按钮被单击");
},
onDoubleTap: () {
print("群聊按钮被双击");
},
child: Text("点击加入群聊"),
),
),
),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}

//更新阶段 didUpdateWidget方法会被调用多次,进行一些更新操作
@override
void didUpdateWidget(covariant MainPage oldWidget) {
super.didUpdateWidget(oldWidget);
}

//停用阶段 deactivate方法会被调用一次,进行一些停用操作
@override
void deactivate() {
super.deactivate();
}

//销毁阶段 dispose方法会被调用一次,进行一些销毁操作
@override
void dispose() {
super.dispose();
}
}

事件-组件点击事件

image-20260425140944928

image-20260425141623743

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

class MainPage extends StatefulWidget {
const MainPage({super.key});

//创建阶段 createState方法会被调用一次,创建一个状态对象
@override
State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
//初始化阶段 initState方法会被调用一次,进行一些初始化操作
@override
void initState() {
super.initState();
}

//依赖变化阶段 didChangeDependencies方法会被调用一次,进行一些依赖变化的操作
@override
void didChangeDependencies() {
super.didChangeDependencies();
}

//构建阶段 build方法会被调用多次,进行构建UI的操作
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Container(
child: Center(
//TextButton 文本按钮组件
child: TextButton(
onPressed: () {
setState(() {
//更新状态,触发重新构建UI
print("按钮被点击了");
});
},
child: Text("按钮"),
),
),
),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}

//更新阶段 didUpdateWidget方法会被调用多次,进行一些更新操作
@override
void didUpdateWidget(covariant MainPage oldWidget) {
super.didUpdateWidget(oldWidget);
}

//停用阶段 deactivate方法会被调用一次,进行一些停用操作
@override
void deactivate() {
super.deactivate();
}

//销毁阶段 dispose方法会被调用一次,进行一些销毁操作
@override
void dispose() {
super.dispose();
}
}

状态更新-setState

语法:数据的变化要更新UI视图,需要执行setState方法,setState方法会造成build的重新执行。

告诉 Flutter:数据变了,请重新调用 build() 刷新界面

例如我们写一个计数器

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
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

class MainPage extends StatefulWidget {
const MainPage({super.key});

@override
State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
// 计数器
int count = 0;

@override
Widget build(BuildContext context) {
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Center(
//Row就是让这三个组件(即"减"+"数字"+"加"排成一条线)
child: Row(
children: [
TextButton(
onPressed: () {
count -= 1;
print(count);
},
child: Text("减"),
),
//将count转换为字符串
Text(count.toString()),
//
TextButton(
onPressed: () {
count += 1;
print(count);
},
child: Text("加"),
),
],
),
),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}
}

此时我们发现点击加减号时中间的数字不会改变,这是因为我们没有添加setState状态监测

此时我们加上serState,然后点击加或者减就会看到中间的数字发生改变

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
59
60
61
62
63
64
65
66
import 'package:flutter/material.dart';

void main() {
runApp(MainPage());
}

class MainPage extends StatefulWidget {
const MainPage({super.key});

@override
State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
// 计数器
int count = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "终末地AI群聊",
home: Scaffold(
appBar: AppBar(centerTitle: true, title: Text("终末地AI群聊")),
body: Center(
child: Row(
children: [
TextButton(
onPressed: () {
//此时增加状态检测
setState(() {
count -= 1;
print(count);
});
//也可以这么写,因为这个是异步操作,setState为让程序重新执行build方法
//count -= 1;
//print(count);
//setState(() {});

},
child: Text("减"),
),
Text(count.toString()),
TextButton(
onPressed: () {
//此时增加状态监测
setState(() {
count += 1;
print(count);
});
//也可以这么写
//count -= 1;
//print(count);
//setState(() {});
},
child: Text("加"),
),
],
),
),
bottomNavigationBar: Container(
height: 80,
child: Center(child: Text("终末地AI群聊")),
),
),
);
}
}

image-20260425144108495