网格布局在移动开发中也经常使用,Flutter 给我们提供了GridView供我们使用,下面我们来看看GridView的使用方法
继承关系
GridView({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required this.gridDelegate,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
List children = const [],
int semanticChildCount,
})
属性
属性 | 值类型 | 说明 |
---|---|---|
scrollDirection | Axis | 设置滚动的方向,horizontal(水平)或vertical(垂直) |
reverse | bool | 是否翻转 |
controller | ScrollController | 用来控制滚动位置及监听滚动事件 |
shrinkWrap | bool | 是否根据子widget的总长度来设置GridView的长度 |
padding | EdgeInsetsGeometry | 间距 |
gridDelegate | SliverGridDelegate | 控制子Widget如何进行布局 |
children | List | 子控件 |
常用属性比较易懂,这里我们主要看一下gridDelegate
gridDelegate
该属性接收一个SliverGridDelegate类型的值,主要是用来控制子Widget如何进行布局。
他有如下两个实现类
SliverGridDelegateWithMaxCrossAxisExtent和SliverGridDelegateWithFixedCrossAxisCount
SliverGridDelegateWithMaxCrossAxisExtent
创建一个具有交叉轴最大值的一个网格布局,对主轴和交叉轴不太明白的可以看Flutter主轴交叉轴详解
构造方法:
const SliverGridDelegateWithMaxCrossAxisExtent({
@required this.maxCrossAxisExtent, //子控件的最大宽度,实际宽度是根据交叉轴的值进行平分,也就是说最大宽度并不一定是实际宽度,很有可能子控件的实际宽度要小于设置的最大宽度
this.mainAxisSpacing = 0.0, //主轴之间的间距
this.crossAxisSpacing = 0.0,//交叉轴之间的间距
this.childAspectRatio = 1.0,//子控件的宽高比
}
下面我们来简单用一用
GridView(
scrollDirection: Axis.vertical,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100, //子控件最大宽度为100
childAspectRatio: 0.5,//宽高比为1:2
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
padding: EdgeInsets.all(10),
children: List.generate(
20,
(index) {
return Box(index + 1);
},
),
);
显示效果:
看了效果图我们可能会有疑问,我最大宽度设置的是110,那子控件为什么是4个呢
首先我们先来看子控件的个数:
子控件的个数实际上就是交叉轴的最大宽度除以我们设置的最大值得出的值,如果该值为整数,那个该值就是子控件的个数,如果不是整数,那么就舍掉小数点后面的值加上一后就是子控件的个数
举个例子:
假如交叉轴最大值为360,我们设置的最大值为89,那么子控件的个数就是5,如果我们设置的最大值为90,那么子控件的个数就是4,如果我们设置的最大值为91,那么子控件的个数也是4
如果我们想明确的指定子控件的个数,我们可以这样写:
maxCrossAxisExtent: MediaQuery.of(context).size.width/4,
MediaQuery.of(context).size.width就是屏幕的宽度,除以4,就是子控件的最大值,这样一来我们就可以确定要显示的子控件的个数了
例如,我们更改一下滚动方向为横向滚动,此时交叉轴为垂直方向,那么最大值就是屏幕的高度。我们想让子控件个数为5,就可以这么写:
maxCrossAxisExtent: MediaQuery.of(context).size.height/5,
示例代码
GridView(
scrollDirection: Axis.horizontal,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: MediaQuery.of(context).size.height/5,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
children: List.generate(
20,
(index) {
return Box(index + 1);
},
),
);
SliverGridDelegateWithFixedCrossAxisCount
理解了上面那个这个就很好理解了,就是设置交叉轴上子控件的个数
构造方法:
const SliverGridDelegateWithFixedCrossAxisCount({
@required this.crossAxisCount, //交叉轴上子控件的个数
this.mainAxisSpacing = 0.0,
this.crossAxisSpacing = 0.0,
this.childAspectRatio = 1.0,
})
示例代码:
GridView(
scrollDirection: Axis.horizontal,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 6,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
children: List.generate(
20,
(index) {
return Box(index + 1);
},
),
);
除了传统的构造方法外,GridView给我们提供更加方便的方法供我们使用
没什么好说的,跟上面的SliverGridDelegateWithFixedCrossAxisCount雷同
示例代码:
GridView.count(
padding: EdgeInsets.all(10),
crossAxisSpacing: 10,
crossAxisCount: 3,
mainAxisSpacing: 10,
children: List.generate(
20,
(index) {
return Box(index + 1);
},
),
);
跟SliverGridDelegateWithMaxCrossAxisExtent类似
GridView.extent(
scrollDirection: Axis.horizontal,
maxCrossAxisExtent: MediaQuery.of(context).size.height/9,
children: List.generate(
20,
(index) {
return Box(index + 1);
},
),
);
跟构造方法使用方式差不多,主要是用来做异步数据加载的,前面几种方式都是在数据确定的情况下,实际上,我们的数据基本上都是从网络上获取的,有分页获取的需求,这个时候就用到GridView.builder了。
首先看看源码:
GridView.builder({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required this.gridDelegate,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
int semanticChildCount,
})
属性跟构造方法中的属性差不多,我们主要来看看itemCount和itemBuilder
itemCount表示列表的数量,一般都是集合的长度
itemBuilder是列表项构造器,返回一个Widget
示例代码:
import 'package:flutter/material.dart';
/*
*
* 网格布局
* */
class GridViewWidget extends StatefulWidget {
@override
State createState() {
return _GridViewVBuilder();
}
}
class _GridViewVBuilder extends State {
List indexs = List.generate(100, (index) {
return index;
});
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5),
itemCount: indexs.length,
itemBuilder: (context, index) {
/*当数据加载完毕时 追加数据*/
if (index == indexs.length - 1 && indexs.length < 200) {
_addIndex();
}
return Text(
"$index",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.red,
fontSize: 20,
),
);
},
);
}
void _addIndex() {
/*这里要延时加载 否则会抱The widget on which setState() or markNeedsBuild() was called was:错误*/
Future.delayed(Duration(milliseconds: 200)).then((e) {
setState(() {
indexs.add(indexs.length + 1);
});
});
}
}
效果图如下:
好了,GridView基本用法大概就是这样。
如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可。也可以关注我的 Flutter 博客专栏,我会不定期的更新,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!