基本上的组件学的差不多了,我们开始一起来学习日常用的最多的列表功能。列表我们一般常用的有ScrollView,ListView,和GridView,在Flutter中也是有一一对应的组件,在Flutter里ScrollView是抽象类无法直接被实例化,我们可以使用它的子类,如NestedScrollView,BoxScrollView,在Flutter比较特殊ListView,GridView也是ScrollView的子类。我们依次看下。
这里的NestedScrollView跟Android中的意义不一样,在Android中是直接一个可以滑动的列表,我们将子View放到ScrollView下的ViewGroup中就可以实现一个页面的滚动,而这里的NestedScrollView是做了一个包含TabBar的一个封装,我们可以利用它轻松的实现向上滑动的时候顶部的折叠。
const NestedScrollView({
Key key,
this.controller,//滚动操作的控制器,给我们一个默认值_NestedScrollController,如果需要修改可以模仿来做更改
this.scrollDirection = Axis.vertical, //滚动的方向,Axis.vertical竖向滚动,horizontal横向滚动
this.reverse = false,//是否页面做翻转,如果是True则bar在下面,滚动的在上面
this.physics,//当用户停止滑动,滑动到顶部时的动作
@required this.headerSliverBuilder,//参照下面的详细说明
@required this.body,//参照下面的详细说明
this.dragStartBehavior = DragStartBehavior.start,//拖拽开始的状态
})
headerSliverBuilder
向上滑动的时候的折叠区域,可以传入一组的控件 List,如果我们在向上滑动的时候可以折叠的话我们需要返回一个SliverOverlapAbsorber,SliverOverlapAbsorber稍后我们做详细解释。
body
传入一个可以滑动的布局,比如我们可以传入一个CustomScrollView,我们则可以通过CustomScrollView来实现页面的滑动,也可以传入SliverList,SliverGrid让页面滚动起来。
先来看下上面提到的SliverOverlapAbsorber。
使用SliverOverlapAbsorber包裹SliverAppBar让在滑动的时候可以进行通知头部,控制AppBar的收放。还是先看下构造函数:
const SliverOverlapAbsorber({
Key key,
@required this.handle, //参照下面的详细说明
Widget child,//需要控制的组件,一般使用SliverAppBar
})
handle
作为一个必选参数来控制堆叠时的控件高度,我们一般使用下面NestedScrollView.sliverOverlapAbsorberHandleFor来创建一个默认的操作。
handle:NestedScrollView.sliverOverlapAbsorberHandleFor(context)
跟AppBar有很多共通的参数,我们可以拿出来它与AppBar的不同之处来作解释:
const SliverAppBar({
Key key,
this.flexibleSpace,//我们需要显示的标题栏里的内容,可以根据需要进行自己的设置,比如一个Text
this.forceElevated = false,//是否保留SliverAppBar下面的阴影,True不管是滚动还是停止都有阴影,False则都不显示
this.expandedHeight,//标题栏和文字说明直接的间距
this.floating = false,//和snap配合使用
this.pinned = false,//顶部的Title栏是否是固定的,False则不显示title栏,True则会滑动时保留title栏
this.snap = false,//和floating配合使用,两个都是True则滑动到顶再下向滑动时首先是标题栏先滑下来,然后再是列表的向下滚动。
this.stretch = false,//是否拉伸以充满滑动区域,没有试出来它的效果
this.stretchTriggerOffset = 100.0,//设定调用onStretchTrigger的滑动距离
this.onStretchTrigger,//设定的回调
...
})
设置还是比较简单,可以根据我们是否需要滚动,是否滚动的时候是否固定头部来进行设置。
作为一个线性排布所有子控件的容器,它其实比较像在Android中认识的ScrollView,但是我们可以通过itemBuilder来实现Android中的ListView的形式。先看下ListView的构造方法,先省略NestedScrollView里面共通的参数:
ListView({
Key key,
bool shrinkWrap = false,//是否根据子组件的总长度来设置ScrollView的长度,如果ScrollView的父容器是一个无边际的的容器则设置为True。
EdgeInsetsGeometry padding,//设置ListView的内填充大小
this.itemExtent,//如果不为空则会强制children的长度为itemExtent的值。
bool addAutomaticKeepAlives = true,//是否将列表项放到AutomaticKeepAlive组件中,在懒加载的时候如果设置为True则滑出窗口视图的时候不会被回收,由KeepAliveNotification来保存状态
bool addRepaintBoundaries = true,//是否将列表项放到RepaintBoundary组件中,设置为True在列表滚动的时候可以避免重绘,但是如果每个Item都很简单比较小的时候如果设置为True会更高效。
bool addSemanticIndexes = true,//设置是否将列表项添加到用位置来表示的语义控件中,还是原来说到的辅助功能使用的
double cacheExtent,//缓存的长度
List<Widget> children = const <Widget>[],//参照下面的详细说明
int semanticChildCount,//语义表达的列表项的数量,还是辅助功能使用。
...
})
children
这里用来存放滑动的内容,我们可以创建一组Text为了测试滑动比如:
ListView(
children: <Widget>[
Text("Hello"),
Text("Hello"),
Text("Hello"),
Text("Hello"),
],
)
如果要是显示一组内容相同的列表我们可以使用ListView的建造者模式的方法ListView.builder()
,其他的参数同ListView只是多了一个
@required IndexedWidgetBuilder itemBuilder,
我们可以通过它来创建一组数据的列表比如:
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text("Hello" + index.toString());
},
padding: EdgeInsets.all(30),
)
常用的还有ListView.separated()只是比ListView.builder()多了一个分割线的设置,不再赘述,可以自己试一下。
跟ListView的参数有很大的相似度,它的功能就是将竖向列表在横向也可以按照指定的块数显示。我们看下它的构造方法,跟ListView类似的不再说明:
GridView({
Key key,
@required this.gridDelegate,//参照下面的详细说明
...
})
gridDelegate
我们看到需要传入一个SliverGridDelegate,但是该类是一个抽象类,我们需要传入一个实现类,找到了SliverGridDelegateWithFixedCrossAxisCount,我们将其传入,来看下它有哪些参数
const SliverGridDelegateWithFixedCrossAxisCount({
@required this.crossAxisCount,//要划分的块数
this.mainAxisSpacing = 0.0,//跟主要滑动方向一致的每块间隔大小
this.crossAxisSpacing = 0.0,//另外一个方向上每块间隔大小
this.childAspectRatio = 1.0,//滑动方向和另一方向块的大小比例
})
一个简单的使用:
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:3,
mainAxisSpacing:10,
crossAxisSpacing: 10,
),
children: <Widget>[
Text("Hello",style: TextStyle(backgroundColor: Colors.green),),
Text("Hello"),
Text("Hello"),
Text("Hello"),
],
),
在GridView中也有builder()和separated()方法,跟ListView的方法一致。
可以理解为我们可以将多个布局按照一个顺序来进行的排列,每个都是单独的个体。它的构造比较简单,我们看下:
const SliverList({
Key key,
@required SliverChildDelegate delegate,//参照下面的详细说明
})
delegate
就只需要传入一个代理,SliverChildDelegate是一个抽象类,我们还需要找到它的实现SliverChildListDelegate,来看下SliverChildListDelegate的构造:
SliverChildListDelegate(
this.children, {
this.addAutomaticKeepAlives = true,
this.addRepaintBoundaries = true,
this.addSemanticIndexes = true,
this.semanticIndexCallback = _kDefaultSemanticIndexCallback,
this.semanticIndexOffset = 0,
})
跟List基本上一样的参数,只是children是一组组件,我们需要一个个的实现,SliverChildDelegate下面还有一个实现是SliverChildBuilderDelegate,这个可以帮助我们快速的创建一组列表与ListView相同的略过:
const SliverChildBuilderDelegate(
this.builder, //这里创建了一个构造器,下面详细说明
{this.findChildIndexCallback,//构造一个返回当前Item的Index的方法
this.childCount,//想要显示的Item的数量
...
})
builder
可以看到它的定义是比较有意思的,是定义了一个方法:
typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index);
我们需要传一个函数进去,可以简单的试一下:
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.red,
child: Text("position is $index",style: TextStyle(fontSize: 14,color: Colors.black),),
);
}
)
这样就构造了一个我想要显示的每一个条目的样式,然后控制数量和缓存机制就可以了。
跟GridView是一样的显示形式,只是也是进行了分块,我们还是看下构造方法:
const SliverGrid({
Key key,
@required SliverChildDelegate delegate,
@required this.gridDelegate,
})
只是比上面的SliverList多了一个gridDelegate,我们只看下gridDelegate,看到它需要传入SliverGridDelegate,但是也是一个抽象类,还是看下它的实现SliverGridDelegateWithFixedCrossAxisCount,嗯,是的,跟GridView中的是一样的,我们可以直接去看GridView中的说明。这样进行设置后一个可以分割的Grid就完成了。
跟ScrollView也不是一样的,它比较像是一个粘合剂的作用,如果我们的列表显示多个列表的组合那么可以放置到CustomScrollView里面,来保证它们的滑动事件的统一,里面也可以放置像ListView和GridView这样子的组件,但是需要注意如果我们需要让他们联合滚动需要不能使用ListView和GridView,我们需要一种已经帮我们做好分割的SliverList和SliverGrid,还是先看下他的构造方法,有部分同NestedScrollView直接去掉了:
const CustomScrollView({
Key key,
bool primary,//如果为True则会让它的Controller创建一个PrimaryScrollController的实体,不能再自定义Controller。
bool shrinkWrap = false,//是否根据子组件的总长度来设置ScrollView的长度,如果ScrollView的父容器是一个无边际的的容器则设置为True。
Key center,
this.slivers = const <Widget>[],//参照下面的详细说明
...
})
slivers
这里我们就要放入可分裂的组件了,我们可以将上面的SliverList或者SliverGrid放入其中,可以混合放入,这样就成了一个混合列表。
滚动页面的内容比较复杂,不是很好理解,还是建议多去试一试,这样可以加深我们的记忆。