一、SingleChildScrollView
SingleChildScrollView
类似于Android中的ScrollView
,它只能接收一个子组件。定义如下:
SingleChildScrollView({
this.scrollDirection = Axis.vertical, //滚动方向,默认是垂直方向
this.reverse = false,
this.padding,
bool primary,
this.physics,
this.controller,
this.child,
})
需要注意的是,通常SingleChildScrollView
只应在期望的内容不会超过屏幕太多时使用,这是因为SingleChildScrollView
不支持基于Sliver的延迟实例化模型,所以如果预计视口可能包含超出屏幕尺寸太多的内容时,那么使用SingleChildScrollView
将会非常昂贵(性能差),此时应该使用一些支持Sliver延迟加载的可滚动组件,如ListView
。
示例
下面是一个将大写字母A-Z沿垂直方向显示的例子,由于垂直方向空间会超过屏幕视口高度,所以我们使用SingleChildScrollView
:
class SingleChildScrollViewTestRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return Scrollbar( // 显示进度条
child: SingleChildScrollView(
padding: EdgeInsets.all(16.0),
child: Center(
child: Column(
//动态创建一个List<Widget>
children: str.split("")
//每一个字母都用一个Text显示,字体为原来的两倍
.map((c) => Text(c, textScaleFactor: 2.0,))
.toList(),
),
),
),
);
}
}
运行效果如图所示:
二、Listview
ListView是我们最常用的组件之一,用于展示大量数据的列表。
#构建方式
数据较少时,可以直接使用如下方式:
ListView(
children: <Widget>[
item,item1,item2,
],
)
这种方式一次加载所有的组件,没有“懒加载”,因此当有大量数据时,使用动态创建列表的方式:
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text('Item$index');
},
itemExtent: 50,
)
如果想在每一项中间增加分割线可以使用如下方式:
ListView.separated(
itemBuilder: (BuildContext context, int index) {
return Text('Item$index');
},
separatorBuilder: (BuildContext context, int index){
return Divider();
},
itemCount: 50,
)
一般上面的方式就够用了,如果以上都不能满足你的要求,还可以使用ListView.custom
,自定义SliverChildDelegate构建自己的ListView。
#基础属性
通过scrollDirection
参数控制滚动方向,默认是垂直方向,向上滚动,设置为水平方向:
ListView.builder(
scrollDirection: Axis.horizontal,
...
)
滚动方向如果是垂直方向,默认是向上滚动,通过reverse
参数设置其向下滚动,代码如下:
ListView.builder(
reverse: true,
...
)
controller
可以控制ListView的滚动,比如获取当前滚动的位置,或者代码直接滚动到指定位置,用法如下:
ScrollController controller;
@override
void initState() {
super.initState();
controller = ScrollController()
..addListener((){
print('${controller.position}');
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
controller:controller,
itemBuilder: (context, index) {
return Text('Item $index');
});
}
physics
参数控制滚动到物理特性,比如设置为不可滚动:
ListView.builder(
physics: NeverScrollableScrollPhysics(),
···
)
系统提供的ScrollPhysics有:
- AlwaysScrollableScrollPhysics:总是可以滑动
- NeverScrollableScrollPhysics:禁止滚动
- BouncingScrollPhysics :内容超过一屏 上拉有回弹效果
- ClampingScrollPhysics :包裹内容 不会有回弹
addAutomaticKeepAlives
参数表示当关闭屏幕时Item是否进行垃圾回收,默认为true。
三、GridView
GridView是一个可滚动的,2D数组控件。
基本用法如下:
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
children: [
_createGridViewItem(Colors.primaries[0]),
_createGridViewItem(Colors.primaries[1]),
_createGridViewItem(Colors.primaries[2]),
_createGridViewItem(Colors.primaries[3]),
_createGridViewItem(Colors.primaries[4]),
_createGridViewItem(Colors.primaries[5]),
_createGridViewItem(Colors.primaries[6]),
_createGridViewItem(Colors.primaries[7]),
],
)
_createGridViewItem(Color color){
return Container(
height: 80,
color: color,
);
}
效果如下:
gridDelegate
参数控制子控件的排列,有2个选择:
- SliverGridDelegateWithFixedCrossAxisCount:交叉轴方向上固定数量,对于垂直方向的GridView来说交叉轴方向指的是水平方向。
- SliverGridDelegateWithMaxCrossAxisExtent:交叉轴方向上尽量大,比如水平方上有500空间,指定此值为150,那么可以放3个,剩余一些空间,此时GridView将会缩小每一个Item,放置4个。
SliverGridDelegateWithFixedCrossAxisCount有属性介绍如下:
crossAxisCount
:交叉轴方向上个数。mainAxisSpacing
:主轴方向上2行之间的间隔。crossAxisSpacing
:交叉轴方向上之间的间隔。childAspectRatio
:子控件宽高比。
设置间隔如下:
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 2,
mainAxisSpacing: 4
)
...
)
效果如下:
scrollDirection`表示滚动方向,默认是垂直方向,可以设置为水平方向。
reverse
表示是否反转滚动方向,比如当前滚动方向是垂直方向,reverse
设置为true,滚动方向为从上倒下,设置为false,滚动方向为从下倒上。
用法如下:
GridView(
scrollDirection: Axis.horizontal,
reverse: true,
...
)
controller
表示滚动相关,可以通过ScrollController获取到当前滚动位置,或者指定滚动到某一位置,用法如下:
ScrollController _gridViewController;
@override
void initState() {
_gridViewController = ScrollController()..addListener(() {
print('${_gridViewController.position}');
});
}
GridView(
controller: _gridViewController,
...
)
physics
参数控制滚动到物理特性,比如设置为不可滚动:
GridView(
physics: NeverScrollableScrollPhysics(),
···
)
系统提供的ScrollPhysics有:
- AlwaysScrollableScrollPhysics:总是可以滑动
- NeverScrollableScrollPhysics:禁止滚动
- BouncingScrollPhysics :内容超过一屏 上拉有回弹效果
- ClampingScrollPhysics :包裹内容 不会有回弹
直接使用最开始的方法创建GridView是不推荐的,此方法不适合加载大量数据的情况,GridView提供了一些快速构建的方法,比如builder,用法如下:
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemBuilder: (context, index) {
return Container(
height: 80,
color: Colors.primaries[index % Colors.primaries.length],
);
},
itemCount: 50,
)
itemBuilder
是构建子控件,itemCount
指定数据个数。
使用GridView.custom
构建:
GridView.custom(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
childrenDelegate: SliverChildBuilderDelegate((context, index) {
return Container(
height: 80,
color: Colors.primaries[index % Colors.primaries.length]);
}, childCount: 50),
)
使用GridView.count
构建:
GridView.count(
crossAxisCount: 3,
children: List.generate(50, (i) {
return Container(
height: 80,
color: Colors.primaries[i % Colors.primaries.length],
);
}),
)
使用GridView.extent
构建:
GridView.extent(
maxCrossAxisExtent: 100,
children: List.generate(50, (i) {
return Container(
height: 80,
color: Colors.primaries[i % Colors.primaries.length],
);
}),
)