Flutter开发者

ListView&GirdView

2018-03-30

上期回顾

在前面的的文章中我们了解了Flutter中操作提示的用法,包括SnackBar、Dialog、以及BottomSheet,通过这些Widget我们可以很方便的实现对应用操作的提示。

在本篇文章中,我们会进一步对Flutter中常用的Widget进行介绍,有印象的童鞋可能还记得,在前面的文章中我们分享了Row和Colunm的用法,我们也使用这两个Widget完成了一些类似列表的操作,但是大家肯定也知道,如果在数据量还小的页面还好,如果数据量过多,再使用这两个控件来布局就会显得十分的麻烦。

那么我们今天就来介绍下Flutter中的列表组件ListView和网格组件GirdView,嗯,果然是Google家的亲儿子,连名字都和Android里的一模一样。

好的吧,我们还是来看下这两个Widget的用法吧

ListView

ListView就是我们常见的列表组件,在平时的应用开发中十分的常见,无论你做的是什么类型的应用都会多多少少会用到ListView,所以要好好看下这篇文章哦

还是先来看下listView的构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ListView({
Key key,
Axis scrollDirection: Axis.vertical,//滚动方向
bool reverse: false,//十分反向显示数据
ScrollController controller,
bool primary,
ScrollPhysics physics,//物理滚动
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
this.itemExtent,//item有效范围
bool addAutomaticKeepAlives: true,//自动保存视图缓存
bool addRepaintBoundaries: true,//添加重绘边界
List<Widget> children: const <Widget>[],
})

那么,我们还是来看下具体的用法

我们还是按照惯例在Scaffold里放一个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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import 'package:flutter/material.dart';

void main() {
runApp(
new MaterialApp(home: new MyApp()),
);
}

class MyApp extends StatelessWidget {

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("ListView"),
),
body: new ListView(
children: <Widget>[
new ListTile(
leading: new Icon(
Icons.cake,
),
title: new Text("我是标题"),
), new ListTile(
leading: new Icon(
Icons.android,
),
title: new Text("我是标题"),
), new ListTile(
leading: new Icon(
Icons.apps,
),
title: new Text("我是标题"),
), new ListTile(
leading: new Icon(
Icons.account_circle,
),
title: new Text("我是标题"),
)
],
),
);
}
}

children参数我们传入了4个lsitTitle,来看下效果

当然,由于数据量过少它现在是不能滑动的。大家可以在下面多加几个Widget试试效果。

在Flutter中有三种构建ListView的方式,刚才介绍的是最简单的一种,但是却不是最常用的,因为它仅仅适用于已知数量或者较少数量的Item的情况。如果有未知数量或者无限个Item的情况,再使用上述的方法将不再适用。

那么,我们可以尝试下ListView.builder()和ListView.custom()。

ListView.builder()和ListView.custom()的用法基本相同,只不过custom可以根据自己的需要控制Item显示方式,如Item显示大小。

我们今天来看下ListView.builder()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ListView.builder({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
this.itemExtent,
@required IndexedWidgetBuilder itemBuilder,//item构建者
int itemCount,//item数量
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
})

相比于new ListView()只不过多出了两个参数而已,一个是itemCount指定item的数量,一个是itemBuilder,用来构建Item。

看下用法:

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

void main() {
runApp(new MaterialApp(
home: new MyApp(),
));
}

class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new MyAppState();
}
}

class MyAppState extends State<MyApp> {
final List<ListItem> listData = [];

@override
void initState() {
super.initState();
for (int i = 0; i < 20; i++) {
listData.add(new ListItem("我是测试标题$i", Icons.cake));
}
}

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("ListView"),
),
body: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new ListItemWidget(listData[index]);
},
itemCount: listData.length,
),
);
}
}

class ListItem {
final String title;
final IconData iconData;

ListItem(this.title, this.iconData);
}

class ListItemWidget extends StatelessWidget {
final ListItem listItem;

ListItemWidget(this.listItem);

@override
Widget build(BuildContext context) {
return new ListTile(
leading: new Icon(listItem.iconData),
title: new Text(listItem.title),
);
}
}

我们首先新建了一个ListItem对象,icon和title两个属性
然后在initState方法中初始化listData,创建了20个ListItem对象。

我们新建了一个一个Widget,需要传入ListItem对象,借助于ListItem对象的属性初始化ListTitle。
在itemBuilder中返回指定的的Listitem到ListItemWidget对象中,返回指定的ListItemWidget对象。

通过这种方法,我们不需要关注Item的数量,因为我们每个Item都是自动构建的,并且大大减少吗重复代码的数量。

其实也是非常简单的,因为很多东西我们在之前的文章中都多少提过。

下面来看下GridView

GridView

GirView的用法和ListView类似,只不过由于GridView可以在一列或者一行显示多个Item,所以在构造方法中就多了个参数来配置一行(列)有几个Item和Item的间隔

构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GridView({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
@required this.gridDelegate,//没错,它就是控制GridView的
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
List<Widget> children: const <Widget>[],
})

看下gridDelegate参数

可以传入SliverGridDelegateWithFixedCrossAxisCount对象和SliverGridDelegateWithMaxCrossAxisExtent对象。

其中SliverGridDelegateWithFixedCrossAxisCount可以直接指定每行(列)显示多少个Item,SliverGridDelegateWithMaxCrossAxisExtent会根据GridView的宽度和你设置的每个的宽度来自动计算没行显示多少个Item

国际惯例,我们还是只介绍一个,那就SliverGridDelegateWithFixedCrossAxisCount吧。

看下代码,怎么用

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import 'package:flutter/material.dart';

void main() {
runApp(
new MaterialApp(home: new MyApp()),
);
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("GridView"),
),
body: new GridView(
children: <Widget>[
new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),
new Container(

child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),new Container(
child: new Icon(
Icons.cake,
size: 50.0,
),
color: Colors.blue,
),
],
reverse: false,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0),
),
);
}
}

和ListView类似,我们在GridView的children中新增了10个Icon并给它设置背景并居中,另外我们根据gridDelegate属性设置每行显示2个Item,并且设置Item间隔为10像素。

效果如下:

当然,GridView你也可以使用builder()和custom()的方式实现

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

void main() {
runApp(new MaterialApp(
home: new MyApp(),
));
}

class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new MyAppState();
}
}

class MyAppState extends State<MyApp> {
final List<ListItem> listData = [];

@override
void initState() {
super.initState();
for (int i = 0; i < 20; i++) {
listData.add(new ListItem("我是测试标题$i", Icons.cake));
}
}

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("ListView"),
),
body: new GridView.builder(
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0),
itemBuilder: (BuildContext context, int index) {
return new ListItemWidget(listData[index]);
},
itemCount: listData.length,
),
);
}
}

class ListItem {
final String title;
final IconData iconData;

ListItem(this.title, this.iconData);
}

class ListItemWidget extends StatelessWidget {
final ListItem listItem;

ListItemWidget(this.listItem);

@override
Widget build(BuildContext context) {
return new GestureDetector(
child: new Container(
color: Colors.blue,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Icon(listItem.iconData, size: 50.0),
new Text(listItem.title)
],
),
),
onTap: () {
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text(listItem.title),
));
},
);
}
}

和上面ListView的用类似,只不过我们现在是一行显示多个Item而已。并且我们给每个Item设置上了点击事件,每次点击Item就会弹出相应的标题。

小结

  • ListView就是我们常用的列表视图
  • GridView就是我们常用的宫格视图
  • ListView和GridView都可以使用new 或者builder()和custom()方法来创建对象
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

打赏请备注姓名或者昵称,方便我后期统计哦

关注公众号,及时查阅最新文章