今天就来介绍下Flutter中的列表组件ListView和网格组件GirdView,嗯,果然是Google家的亲儿子,连名字都和Android里的一模一样。
好的吧,我们还是来看下这两个Widget的用法吧
ListView就是我们常见的列表组件,在平时的应用开发中十分的常见,无论你做的是什么类型的应用都会多多少少会用到ListView,所以要好好看下这篇文章哦
还是先来看下listView的构造方法:
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 children: const [],
})
那么,我们还是来看下具体的用法
我们还是按照惯例在Scaffold里放一个ListView
import 'package:flutter/material.dart';
class Routes extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('目录')),
body: new ListView(
children: [
ListTile(
title: Text('标题1'),
leading: Icon(Icons.build),
trailing: Text('尾巴'),
onTap: () {
showDialog(
context: context,
child: new SimpleDialog(
contentPadding: const EdgeInsets.all(10.0),
title: new Text("我是标题"),
children: [new Text("我是内容区域")],
));
},
),
ListTile(
title: Text('标题2'),
leading: Icon(Icons.print),
trailing: Text('尾巴'),
),
ListTile(
title: Text('标题3'),
leading: Icon(Icons.library_music),
trailing: Text('尾巴'),
),
ListTile(
title: Text('标题4'),
leading: Icon(Icons.accessibility_new),
trailing: Text('尾巴'),
),
],
),
);
}
}
children参数我们传入了4个ListTile,先介绍下:
ListTile是一个固定高度的行,通常包含一些文本,以及一个行前或行尾图标。
const ListTile({
Key key,
this.leading,
this.title,
this.subtitle,
this.trailing,
this.isThreeLine = false,
this.dense,
this.contentPadding,
this.enabled = true,
this.onTap,
this.onLongPress,
this.selected = false,
}) : assert(isThreeLine != null),
assert(enabled != null),
assert(selected != null),
assert(!isThreeLine || subtitle != null),
super(key: key);
当然,由于数据量过少它现在是不能滑动的。大家可以在下面多加几个Widget试试效果。
在Flutter中有三种构建ListView的方式,刚才介绍的是最简单的一种,但是却不是最常用的,因为它仅仅适用于已知数量或者较少数量的Item的情况。如果有未知数量或者无限个Item的情况,再使用上述的方法将不再适用。
那么,我们可以尝试下ListView.builder()
和ListView.custom()
。
ListView.builder()和ListView.custom()的用法基本相同,只不过custom可以根据自己的需要控制Item显示方式,如Item显示大小。
我们今天来看下ListView.builder()
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,
double cacheExtent,
})
相比于new ListView()只不过多出了两个参数而已,一个是itemCount指定item的数量,一个是itemBuilder,用来构建Item。
看下用法
import 'package:flutter/material.dart';
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),
);
}
}
class Routes extends StatefulWidget {
@override
State createState() {
return RouteState();
}
}
class RouteState extends State<Routes> {
final List listData = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 20; i++) {
listData.add(ListItem("我是测试标题$i", Icons.cake));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('列表'),
),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListItemWidget(listData[index]);
},
itemCount: listData.length,
),
);
}
}
我们首先新建了一个ListItem对象,icon和title两个属性
我们新建了一个一个Widget,需要传入ListItem对象,借助于ListItem对象的属性初始化ListTitle。
然后在initState方法中初始化listData,创建了20个ListItem对象。
在itemBuilder中返回指定的的Listitem到ListItemWidget对象中,返回指定的ListItemWidget对象。
通过这种方法,我们不需要关注Item的数量,因为我们每个Item都是自动构建的,并且大大减少重复代码的数量。
下面来看下GridView
GirView的用法和ListView类似,只不过由于GridView可以在一列或者一行显示多个Item,所以在构造方法中就多了个参数
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,
double cacheExtent,
List children = const [],
})
看下gridDelegate参数
可以传入SliverGridDelegateWithFixedCrossAxisCount
对象和SliverGridDelegateWithMaxCrossAxisExtent
对象。
其中SliverGridDelegateWithFixedCrossAxisCount
可以直接指定每行(列)显示多少个Item,SliverGridDelegateWithMaxCrossAxisExtent
会根据GridView的宽度和你设置的每个的宽度来自动计算没行显示多少个Item
国际惯例,我们还是只介绍一个,那就SliverGridDelegateWithFixedCrossAxisCount吧。
看下代码,怎么用
import 'package:flutter/material.dart';
class GridViewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GridView'),
),
body: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, //每行2个
mainAxisSpacing: 10.0, //主轴(竖直)方向间距
crossAxisSpacing: 10.0, //纵轴(水平)方向间距
childAspectRatio: 1.0 //纵轴缩放比例
),
children: [
Container(
alignment: Alignment.center,
color: Colors.green,
child: Image.asset("images/pic1.jpg"),
),
Container(
alignment: Alignment.center,
color: Colors.green,
child: Image.asset("images/pic1.jpg"),
),
Container(
alignment: Alignment.center,
color: Colors.green,
child: Image.asset("images/pic1.jpg"),
),
Container(
alignment: Alignment.center,
color: Colors.green,
child: Image.asset("images/pic1.jpg"),
),
Container(
alignment: Alignment.center,
color: Colors.green,
child: Image.asset("images/pic1.jpg"),
),
Container(
alignment: Alignment.center,
color: Colors.green,
child: Image.asset("images/pic1.jpg"),
),
Container(
alignment: Alignment.center,
color: Colors.green,
child: Image.asset("images/pic1.jpg"),
),
],
),
);
}
}
和ListView类似,我们在GridView的children中新增了7个图片并给它设置背景并居中,另外我们根据gridDelegate属性设置每行显示2个Item,并且设置Item间隔为10像素。
效果如下:
当然,GridView你也可以使用builder()和custom()的方式实现
import 'package:flutter/material.dart';
class GridViewPage extends StatefulWidget {
@override
State createState() {
return GridViewState();
}
}
class GridViewState extends State<GridViewPage> {
final List 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 Scaffold(
appBar: AppBar(
title: Text('GridView'),
),
body: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, //每行2个
mainAxisSpacing: 10.0, //主轴(竖直)方向间距
crossAxisSpacing: 10.0, //纵轴(水平)方向间距
childAspectRatio: 1.0 //纵轴缩放比例
),
itemCount: listData.length,
itemBuilder: (BuildContext context, int index) {
return ListItemWidget(listData[index]);
},
),
);
}
}
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.green,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Icon(
listItem.iconData,
size: 50.0,
color: Colors.white,
),
new Text(
listItem.title,
style: TextStyle(color: Colors.white),
)
],
),
),
onTap: () {
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text(listItem.title),
));
},
);
}
}
和上面ListView的用类似,只不过我们现在是一行显示多个Item而已。并且我们给每个Item设置上了点击事件,每次点击Item就会弹出相应的标题。
ListView就是我们常用的列表视图
GridView就是我们常用的宫格视图
ListView和GridView都可以使用new 或者builder()和custom()方法来创建对象