GridView
GridView
可以构建一个二维网格列表,其默认构造函数定义如下:
GridView({
Key? key,
Axis scrollDirection = Axis.vertical,//滚动方向
bool reverse = false,//组件反向排序
ScrollController? controller,//滚动监听
bool? primary,//内容不足不可滑动,值为true,内容不足可以尝试滑动。
ScrollPhysics? physics,//滑动类型设置
bool shrinkWrap = false,//内容适配
EdgeInsetsGeometry? padding,//内边距
required this.gridDelegate, //代理,设置行列数量
bool addAutomaticKeepAlives = true,//缓存相关
bool addRepaintBoundaries = true,//渲染边界,性能相关
double? cacheExtent, //设置预渲染区域
List<Widget> children = const <Widget>[],//子组件
...
})
我们可以看到,GridView
和ListView
的大多数参数都是相同的,它们的含义也都相同的。我们唯一需要关注的是gridDelegate
参数,类型是SliverGridDelegate
,它的作用是控制GridView
子组件如何排列(layout)。
SliverGridDelegate
是一个抽象类,定义了GridView Layout
相关接口,子类需要通过实现它们来实现具体的布局算法。Flutter中提供了两个SliverGridDelegate
的子类SliverGridDelegateWithFixedCrossAxisCount
和SliverGridDelegateWithMaxCrossAxisExtent
,我们可以直接使用,下面我们分别来介绍一下它们。
SliverGridDelegateWithFixedCrossAxisCount
该子类实现了一个横轴为固定数量子元素的layout算法,其构造函数为:
SliverGridDelegateWithFixedCrossAxisCount({
@required double crossAxisCount,
double mainAxisSpacing = 0.0,
double crossAxisSpacing = 0.0,
double childAspectRatio = 1.0,
})
- crossAxisCount:横轴子元素的数量。此属性值确定后子元素在横轴的长度就确定了,即ViewPort横轴长度除以crossAxisCount的商。
- mainAxisSpacing:主轴方向的间距。
- crossAxisSpacing:横轴方向子元素的间距。
- childAspectRatio:子元素在横轴长度和主轴长度的比例。由于crossAxisCount指定后,子元素横轴长度就确定了,然后通过此参数值就可以确定子元素在主轴的长度。
可以发现,子元素的大小是通过crossAxisCount
和childAspectRatio
两个参数共同决定的。注意,这里的子元素指的是子组件的最大显示空间,注意确保子组件的实际大小不要超出子元素的空间。
例子:
GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,//横轴三个子widget
childAspectRatio: 1.0,//子widget宽高比例
),
children: const [
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast)
],
)
运行效果:
GridView.count
GridView.count
构造函数内部使用了SliverGridDelegateWithFixedCrossAxisCount
,我们通过它可以快速的创建横轴固定数量子元素的GridView
,上面的示例代码等价于:
GridView.count(
crossAxisCount: 3,
childAspectRatio: 1.0,
children: const [
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast),
],
)
SliverGridDelegateWithMaxCrossAxisExtent
该子类实现了一个横轴子元素为固定最大长度的layout算法,其构造函数为:
SliverGridDelegateWithMaxCrossAxisExtent({
double maxCrossAxisExtent,
double mainAxisSpacing = 0.0,
double crossAxisSpacing = 0.0,
double childAspectRatio = 1.0,
})
maxCrossAxisExtent为子元素在横轴上的最大长度,之所以是“最大”长度,是因为横轴方向每个子元素的长度仍然是等分的,举个例子,如果ViewPort的横轴长度是450,那么当maxCrossAxisExtent的值在区间(450/4,450/3)内的话,子元素最终实际长度都为112.5,而childAspectRatio所指的子元素横轴和主轴的长度比为最终的长度比。其它参数和SliverGridDelegateWithFixedCrossAxisCount相同。
例子:
GridView(
padding: EdgeInsets.zero,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 120.0,
childAspectRatio: 2.0 //宽高比为2
),
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast),
],
);
运行效果:
GridView.extent
GridView.extent构造函数内部使用了SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建纵轴子元素为固定最大长度的的GridView,上面的示例代码等价于:
GridView.extent(
maxCrossAxisExtent: 120.0,
childAspectRatio: 2.0,
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast),
],
);
GridView.builder
上面我们介绍的GridView都需要一个widget数组作为其子元素,这些方式都会提前将所有子widget都构建好,所以只适用于子widget数量比较少时,当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。GridView.builder 必须指定的参数有两个:
GridView.builder(
...
required SliverGridDelegate gridDelegate,
required IndexedWidgetBuilder itemBuilder,
)
其中itemBuilder
为子widget构建器。
假设我们需要从一个异步数据源(如网络)分批获取一些Icon
,然后用GridView
来展示:
import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/material.dart';
/// @Author wywinstonwy
/// @Date 2022/1/21 8:48 上午
/// @Description:
class MyGridViewPage extends StatefulWidget {
const MyGridViewPage({Key? key}) : super(key: key);
@override
_MyGridViewPageState createState() => _MyGridViewPageState();
}
class _MyGridViewPageState extends State<MyGridViewPage> {
List<IconData> _icons = []; //保存Icon数据
@override
void initState() {
// TODO: implement initState
super.initState();
_retrieveIcons();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: getAppBar('GridView'),
body: _buildGridBuilderView(),
);
}
_buildGridView(){
return GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,//横轴三个子widget
childAspectRatio: 1.0,//子widget宽高比例
),
children: const [
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast)
],
);
}
_buildGridCountView(){
return GridView.count(
crossAxisCount: 3,
childAspectRatio: 1.0,
children: const [
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast),
],
);
}
_buildGridView1(){
return GridView(
padding: EdgeInsets.zero,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 120.0,
childAspectRatio: 2.0 //宽高比为2
),
children: const <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast),
],
);
}
_buildGridBuilderView(){
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1.0
),
itemCount: _icons.length,
itemBuilder: (context,index){
//如果显示到最后一个并且Icon总数小于200时继续获取数据
if(index == _icons.length-1 && _icons.length<200){
_retrieveIcons();
}
return Icon(_icons[index]);
});
}
_retrieveIcons(){
Future.delayed(Duration(milliseconds: 200)).then((value){
setState(() {
_icons.addAll([
Icons.ac_unit,
Icons.airport_shuttle,
Icons.all_inclusive,
Icons.beach_access,
Icons.cake,
Icons.free_breakfast,
]);
});
});
}
}
- _retrieveIcons():在此方法中我们通过Future.delayed来模拟从异步数据源获取数据,每次获取数据需要200毫秒,获取成功后将新数据添加到_icons,然后调用setState重新构建。
- 在
itemBuilder
中,如果显示到最后一个时,判断是否需要继续获取数据,然后返回一个Icon。 运行效果:
GridView官方api文档:api.flutter-io.cn/flutter/wid…
今天的文章35、Flutter之GridView组件详解分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18666.html