Flutter的目录结构

创建flutter项目,除了在Android studio中创建,还可以使用命令行进行创建。我们进入想要创建的目录,输入命令 flutter create flutter02 就创建了一个叫 flutter02 的flutter项目。

下面看一下项目的结构

Flutter的入口文件

Flutter的入口文件是 lib/main.dart , 入口方法是 main 函数,在这个函数中通过 runApp() 方法就可以调用内置组件或者我们写的组件来进行页面布局。

我们可以把这个文件中的内容都删掉然后自己写。

首先我们要引入库 import 'package:flutter/material.dart';,然后利用一些提供的组件进行编写

1
2
3
4
5
6
7
void main() {
runApp(const Center(
child: Text("你好Flutter",
textDirection: TextDirection.ltr,
style: TextStyle(color: Color.fromRGBO(212, 23, 23, 1), fontSize: 40)),
));
}

用MaterialApp 和 Scaffold两个组件来装饰App

MaterialApp

MaterialApp是一个方便的Widget,它封装了应用程序实现Material Design所需要的一些Widget。一般做顶层的widget使用

常用的属性

home: 主页
title: 标题
color: 颜色
theme: 主题
routes: 路由

Scaffold

Scaffold是Marterial Design布局结构的基本实现,此类提供了用于显示drawer、snackbar和底部sheet的API

Scaffold有下面几个主要属性

appBar:显示在界面顶部的一个AppBar
body:当前界面所显示的主要内容Widget
drawer:抽屉菜单控件

使用上面两个组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("你好Flutter")),
body: const Center(
child: Text("你好Flutter",
textDirection: TextDirection.ltr,
style:
TextStyle(color: Color.fromRGBO(212, 23, 23, 1), fontSize: 40)),
),
),
));
}

Flutter把内容抽离成单独一个组件

在Flutter中自定义组件就是一个类,这个类继承StatelesWidget/StatefulWidget

StatelessWidget是一个无状态组件,状态不可改变的widget

StatefulWidget是一个有状态组件,持有的状态可能在widget生命周期改变

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

void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("你好Flutter")), body: const MyApp()),
));
}

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

@override
Widget build(BuildContext context) {
return const Center(
child: Text("你好Flutter",
textDirection: TextDirection.ltr,
style:
TextStyle(color: Color.fromRGBO(212, 23, 23, 1), fontSize: 40)),
);
}
}

Flutter中的组件

Container容器组件

类似于html中的div

  1. height 容器高度

  2. width 容器宽度

  3. child 容器子元素

  4. margin 表示Container与外部其他组件的距离。Edgelnsets.all(20.0),

  5. padding 就是Container的内边距,指Containeri边缘与Child之间的距离, padding:Edgelnsets.all(10.0)

  6. alignment 用来设置container内部容器的位置。
    topCenter 顶部-居中
    topLeft 顶部-居左
    topRight 顶部-居右
    center 水平居中-垂直居中
    centerLeft 垂直居中-水平居左
    centerRight 垂直居中-水平居右
    bottomCenter 底部-居中
    bottomLeft 底部-居左
    bottomRight 底部-居右

  7. decoration 用来改变container的样式。边框,阴影,背景色等

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    decoration: BoxDecoration(
    color: const Color.fromARGB(255, 15, 9, 132), //背景色
    border: Border.all(
    color: const Color.fromARGB(255, 0, 0, 1),
    width: 2.0), //边框,也可以单独设置每个边框
    borderRadius: BorderRadius.circular((8)), //圆角
    boxShadow: const [
    BoxShadow(
    color: Colors.blue, // 阴影颜色
    offset: Offset(10.0, 12.0), // 阴影开始的位置
    blurRadius: 40 // 阴影强度
    )
    ],
    gradient: const LinearGradient(
    colors: [Colors.red, Colors.orange],
    ) // 背景颜色渐变 LinearGradient 线性渐变 RadialGradient 径向渐变
    )
  8. transform 让Container容易进些旋转之类的

    1
    2
    3
    transform: Matrix4.translationValues(10, 0, 0), //沿着x,y轴位移
    transform: Matrix4.rotationZ(0.5), //沿着z轴旋转,也可以沿着x,y
    transform: Matrix4.skewX(0.2), //沿着x倾斜,也可以沿y
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
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("你好Flutter")),
body: Column( //使用column来放多个组件,这个组件后面介绍
children: const [MyApp(), MyButton()],
)),
));
}

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

@override
Widget build(BuildContext context) {
return Center(
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.fromLTRB(0, 40, 0, 20),
// transform: Matrix4.translationValues(10, 0, 0), //沿着x,y轴位移
// transform: Matrix4.rotationZ(0.5), //沿着z轴旋转,也可以沿着x,y
// transform: Matrix4.skewX(0.2), //沿着x倾斜,也可以沿y
width: 100,
height: 200,
decoration: BoxDecoration(
color: const Color.fromARGB(255, 15, 9, 132), //背景色
border: Border.all(
color: const Color.fromARGB(255, 0, 0, 1),
width: 2.0), //边框,也可以单独设置每个边框
borderRadius: BorderRadius.circular((8)), //圆角
boxShadow: const [
BoxShadow(
color: Colors.blue, // 阴影颜色
offset: Offset(10.0, 12.0), // 阴影开始的位置
blurRadius: 40 // 阴影强度
)
],
gradient: const LinearGradient(
colors: [Colors.red, Colors.orange],
) // 背景颜色渐变 LinearGradient 线性渐变 RadialGradient 径向渐变
),
child: const Text(
"你好吗",
style: TextStyle(color: Color.fromRGBO(9, 251, 251, 1), fontSize: 20),
),
),
);
}
}

class MyButton extends StatelessWidget {
const MyButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
width: 200,
height: 40,
margin: const EdgeInsets.fromLTRB(0, 10, 0, 10),
decoration: BoxDecoration(
color: Colors.blue, borderRadius: BorderRadius.circular(20)),
child: const Text(
"按钮",
style: TextStyle(color: Colors.white, fontSize: 20),
),
);
}
}

Text组件

这个是文本组件

  1. textAlign 文本对齐方式(center,left,right,justfy)
  2. textDirection 文本方向(ltr从左到右,rtl从右到左)
  3. overflow 文字超出后的处理方式(clip裁剪,fade隐藏,ellipsis省略号)
  4. textScaleFactor 文字显示倍率
  5. maxLines 文字显示最大行数
  6. style 字体的样式
    TextStyle的参数
    • decoration 文字装饰线(none 没有线,lineThrough删除线,overline上划线,underline下划线)
    • decorationColor 文字装饰线颜色
    • decorationStyle 装饰线风格(dashed,dotted虚线,double两个线,solid实线,wavy波浪线)
    • wordSpacing 单词间隙(如果是负值会变紧凑)
    • letterSpacing 字母间隙
    • fontStyle 文字样式(italic斜体,normal正常体)
    • fontSize 文字大小
    • color 文字颜色
    • fontWeight 字体粗细(bold粗,normal正常)

图片组件

Flutter中,我们可以通过Image组件来加载并显示图片Image的数据源可以是asset、文件、内存以及网络。

Image.network 加载网络图片

  1. width和height 配合ClipOval才能看到效果
  2. alignment 图片在外部容器的位置
  3. color和colorBlendMode 设置图片的背景颜色,通常和colorBlendMode一起使用,这样可以是图片颜色和背景色混合。
  4. fit 控制图片的拉伸和挤压,根据父容器来
    BoxFit.fill 全图显示,图片会被拉伸,充满父容器
    BoxFit.contain 全图显示,显示原来的比例,可能父容器有空隙
    BoxFit.cover 显示可能拉伸,可能裁切,充满(图片充满整个容器,不变性)
    BoxFit.fitWidth 宽度充满
    BoxFit.fitHeight 高度充满
    BoxFit.scaleDown 效果和contain差不多,但是此属性不允许显示超过源图片大小,可小不可大
  5. repeat 平铺
    ImageRepeat.repeatX X轴平铺
    ImageRepeat.repeatY Y轴平铺
    ImageRepeat.repeat X和Y轴平铺
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ImgContainer extends StatelessWidget {
const ImgContainer({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Container(
height: 200,
width: 200,
decoration: const BoxDecoration(color: Colors.yellow),
child: Image.network(
"https://www.itying.com/themes/itying/images/ionic4.png",
scale: 2, //缩放
alignment: Alignment.bottomCenter, // 图片在外部容器中的位置
fit: BoxFit.fill,
),
);
}
}

Image.assets 加载本地图片

加载本地图片之前,需要进行下面的准备

本地图片这个属性没有什么差别,主要是要放在目录下并配置pubspec.yaml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class localImg extends StatelessWidget {
const localImg({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Container(
height: 150,
width: 150,
decoration: const BoxDecoration(color: Colors.yellow),
child: Image.asset(
"images/a.jpeg", // 这里直接写更目录的,然后引擎会根据不同的dpi去找对应文件夹中的图片
fit: BoxFit.cover,
),
);
}
}

实现圆形图片

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
// 利用Container背景图片写一个圆形图片
class Circular extends StatelessWidget {
const Circular({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Container(
height: 100,
width: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.yellow,
image: const DecorationImage(
image: NetworkImage(
"https://www.itying.com/themes/itying/images/ionic4.png",
),
fit: BoxFit.cover)),
);
}
}

// 利用ClipOval实现圆形图片

class ClipImg extends StatelessWidget {
const ClipImg({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return ClipOval(
child: Image.network(
"https://www.itying.com/themes/itying/images/ionic4.png",
scale: 2, //缩放
alignment: Alignment.bottomCenter, // 图片在外部容器中的位置
fit: BoxFit.fill,
width: 100,
height: 100,
),
);
}
}

// 利用CircleAvatar组件实现圆形图片

class CircleAvatarImg extends StatelessWidget {
const CircleAvatarImg({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return const CircleAvatar(
radius: 30, // 设置半径
backgroundImage: NetworkImage(
"https://www.itying.com/themes/itying/images/ionic4.png"));
}
}

// 可以通过在一个园里嵌套另一个圆达到给圆加边框的效果

class CircleAvatarImg extends StatelessWidget {
const CircleAvatarImg({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return const CircleAvatar(
radius: 30,
backgroundColor: Color.fromARGB(255, 56, 54, 54),
child: CircleAvatar(
radius: 25, // 设置半径
backgroundImage: NetworkImage(
"https://www.itying.com/themes/itying/images/ionic4.png")),
);
}
}

图标组件

内置图标

官方内置图标库,里面可以查看一些图标以及使用。

内置图标组件是Icon() 我们可以点进源码看有什么参数一般用法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class IconContainer extends StatelessWidget {
const IconContainer({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Column(
children: const [
Icon(
Icons.home, // 通过Icons 来调用内置的一些图标
size: 40, // 设置图标大小
color: Colors.red, // 设置图标颜色
),
Icon(Icons.drafts)
],
);
}
}

使用自定义图标

阿里巴巴图标库中有很多图标,方便我们选择和查找

  1. 首先我们在网站上选择并下载iconfont.ttf文件
  2. 在项目根目录创建 fonts 文件夹,并把.ttf 文件放进去
  3. pubspec.ymal 文件中进行配置
  4. 自定义字体的类,在 lib 目录下创建 .dart 文件放自己定义的图标类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import 'package:flutter/material.dart';
    class MyiconFont {
    static const IconData book =
    IconData(0x3447, fontFamily: "myiconFont", matchTextDirection: true);
    static const IconData weixin =
    IconData(0xf0106, fontFamily: "myiconFont", matchTextDirection: true);
    static const IconData shopcat =
    IconData(0xe73c, fontFamily: "myiconFont", matchTextDirection: true);
    }
  5. Icon()中使用
    1
    2
    3
    4
    5
    Icon(
    MyiconFont.book, // 直接使用自定义的类名和属性就可以了,其它的和内置的图标一样
    size: 50,
    color: Colors.green,
    ),

ListView 列表组件

列表布局是我们项目开发中最常用的一种布局方式。Flutter中我们可以通过ListView:来定义列表项,支持垂直和水平方向展示。通过一个属性就可以控制列表的显示方向。列表有以下分类:

  1. 垂直列表
  2. 垂直图文列表
  3. 水平列表
  4. 动态列表

列表组件常用参数:

  1. scrollDirection Axis.horizontal水平列表、Axis.vertical垂直列表
  2. padding 内边距
  3. resolve 组件反向排序
  4. children 列表元素

静态列表

ListView 一般会搭配LIstTile来使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ListView 一般会搭配LIstTile来使用,Divider组件就是一条线
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: const [
ListTile(
title: Text("我是一个列表"),
),
Divider(), // 就是一个线
ListTile(
title: Text("我是一个列表"),
),
Divider(), // 就是一个线
ListTile(
title: Text("我是一个列表"),
),
],
);
}
}

ListTile 还有一些别的属性,比如添加前后的图标,效果如下图,还可以绑定点击事件,这个后面再说

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
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: const [
ListTile(
leading: Icon(
Icons.home,
color: Colors.green,
), //列表前面的图标
title: Text("首页"),
trailing: Icon(Icons.chevron_right_sharp), // 列表后面的东西,
),
Divider(), // 就是一个线
ListTile(
leading: Icon(
MyiconFont.book,
color: Colors.yellow,
), //列表前面的图标
title: Text("读书"),
trailing: Icon(Icons.chevron_right_sharp), // 列表后面的东西,
),
Divider(), // 就是一个线
],
);
}
}
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
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: [
ListTile(
leading: Image.network(
"https://www.itying.com/themes/itying/images/ionic4.png"), // 前面的图片,也可以放在 trailing 中即放后面
title: const Text("profiler on P30 Pro is available at"),
subtitle: const Text(
"String data, {Key? key, TextStyle? style, StrutStyle? strutStyle, TextAlign? textAlign, TextDirection? textDirecti"), // 二级标题
),
const Divider(), // 就是一个线
ListTile(
leading: Image.network(
"https://www.itying.com/themes/itying/images/ionic4.png"),
title: const Text("profiler on P30 Pro is available at"),
subtitle: const Text(
"String data,Key? key, TextStyle? style, StrutStyle? strutStyle, TextAlign? textAlign, TextDirection? textDirectiPerforming hot restart.. Restarted application in 8"), // 二级标题
),
],
);
}
}

除了ListTileListView中还可以随意放其它的组件

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
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: [
Image.network("https://www.itying.com/images/flutter/1.png"),
Container(
padding: const EdgeInsets.fromLTRB(0, 6, 0, 0),
height: 44,
child: const Text("我是一个标题",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 22),
),
),
Image.network("https://www.itying.com/images/flutter/2.png"),
Container(
padding: const EdgeInsets.fromLTRB(0, 6, 0, 0),
height: 44, // 在垂直列表中直接加Container,宽度是自适应列表宽度的,配置是没有效果的
child: const Text("我是一个标题",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 22),
),
),
Image.network("https://www.itying.com/images/flutter/3.png"),
Container(
padding: const EdgeInsets.fromLTRB(0, 6, 0, 0),
height: 44,
child: const Text("我是一个标题",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 22),
),
),
],
);
}
}

除了上面垂直的,我们通过设置 scrollDirection 属性,可以将其配置水平列表,和垂直列表类似,水平列表中直接加Container组件,高度是自适应的,配置了也没用,想要给水平列表一个高度,一般是在ListView外包裹一个SizeBox组件,给SizeBox组件设置高度来限制ListView的高度

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
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 50,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
width: 200, // 水平列表的高度是自适应的,我们配置了也没用
decoration: const BoxDecoration(color: Colors.red),
),
Container(
width: 200,
decoration: const BoxDecoration(color: Colors.yellow),
),
Container(
width: 200,
decoration: const BoxDecoration(color: Colors.green),
),
],
));
}
}

动态列表

我们列表 ListView 组件的children属性需要的是一个 Widget 类型的List,所以我们动态生成这个list并传给ListView组件就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});

List<Widget> _initListData() {
List<Widget> list = [];
for (var i = 0; i < 10; i++) {
list.add(ListTile(
title: Text("我是一个列表-$i"),
));
}
return list;
}
@override
Widget build(BuildContext context) {
return ListView(children: _initListData());
}
}

下面模拟从服务器拿到了数据并渲染成动态列表。

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
List listData=[{
{
"title":"yjr1100 ",
"author":"yjr-1100",
"imageUrl":"https://www.itying.com/images/flutter/2.png"
},
{
"title":"yjr1100 ",
"author":"yjr-1100",
"imageUrl":"https://www.itying.com/images/flutter/1.png"
},
}]
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});

List<Widget> _initListData() {
var tempList = listData.map((value){
return ListTile(
leading: Image.network("${value["imageUrl"]}"),
title: Text("${value["title"]}"),
subtitle: Text("${value["author"]}"),
)
})
return tempList.toList();
}
@override
Widget build(BuildContext context) {
return ListView(children: _initListData());
}
}

使用listview.builder 来生成列表和遍历数据

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
class MyHomePage extends StatelessWidget {
List<String> list = [];
MyHomePage({super.key}) {
for (int i = 0; i < 20; i++) {
list.add("我是第$i条数据");
}
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(list[index]),
);
});
}
}

List listData=[{
{
"title":"yjr1100 ",
"author":"yjr-1100",
"imageUrl":"https://www.itying.com/images/flutter/2.png"
},
{
"title":"yjr1100 ",
"author":"yjr-1100",
"imageUrl":"https://www.itying.com/images/flutter/1.png"
},
}]

class MyHomePage2 extends StatelessWidget {
const MyHomePage2({super.key});
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: listData.length,
itemBuilder: (context, index) {
return ListTile(
leading:Image.network(listData[i]["imageUrl"]),
title: Text(listData[i]["title"]),
subtitle: Text(listData[i]["author"]),
);
});
}
}

GridView 网格布局组件

GridView创建网格列表主要有下面三种方式

  1. 通过GridView.count 实现网格布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class MyHomePage extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return GridView.count(
    crossAxisCount: 3, // 配置有多少个主轴
    scrollDirection: Axis.horizontal, // 可以改变主轴方向,默认竖着
    children: const [
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    ]);
    }
    }
  2. 通过GridView.extent 实现网格布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class MyHomePage extends StatelessWidget {
    const MyHomePage({super.key});

    @override
    Widget build(BuildContext context) {
    return GridView.extent(
    maxCrossAxisExtent: 360, //配置主轴垂直方向子元素的最大长度
    scrollDirection: Axis.horizontal, // 可以改变主轴方向,默认竖着
    children: const [
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.mail),
    Icon(Icons.home),
    Icon(Icons.home),
    Icon(Icons.home),
    ]);
    }
    }

    crossAxisSpacing 非主轴子元素之间的距离
    mainAxisSpacing 主轴子元素之间的距离
    padding 四周的间距
    childAspectRatio 子元素宽高比

  3. 通过GridView.builder 实现动态网格布局
    gridDelegate 属性有两个可选值

    • SliverGridDelegateWithFixedCrossAxisCount() 这个实现 GridView.count
    • SliverGridDelegateWithMaxCrossAxisExtent() 这个实现 GridView.extent

    itemBuilder 属性值是一个方法需要两个参数 context和index 在这个方法内部构造子元素
    itemCount 子元素的个数,也就是上面那个方法循环执行的次数

    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
    class MyHomePage extends StatelessWidget {
    const MyHomePage({super.key});

    @override
    Widget build(BuildContext context) {
    return GridView.builder(
    // scrollDirection: Axis.horizontal, // 可以改变主轴方向,默认竖着
    itemCount: 10,
    gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    crossAxisSpacing: 10,
    mainAxisSpacing: 5,
    ),
    // gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
    // maxCrossAxisExtent: 130, //配置主轴垂直方向子元素的最大长度
    // mainAxisSpacing: 10,
    // crossAxisSpacing: 5,
    // childAspectRatio: 0.9,
    // mainAxisExtent: 350,
    // ),
    itemBuilder: (context, index) {
    return Container(
    alignment: Alignment.center,
    decoration: const BoxDecoration(color: Colors.green),
    child: Text(
    "第$index个元素",
    style: const TextStyle(fontSize: 20),
    ),
    );
    },
    );
    }
    }