W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
GridView
可以構(gòu)建一個(gè)二維網(wǎng)格列表,其默認(rèn)構(gòu)造函數(shù)定義如下:
GridView({
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required SliverGridDelegate gridDelegate, //控制子widget layout的委托
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
double cacheExtent,
List<Widget> children = const <Widget>[],
})
我們可以看到,GridView
和ListView
的大多數(shù)參數(shù)都是相同的,它們的含義也都相同的,如有疑惑讀者可以翻閱 ListView 一節(jié),在此不再贅述。我們唯一需要關(guān)注的是gridDelegate
參數(shù),類型是SliverGridDelegate
,它的作用是控制GridView
子組件如何排列(layout)。
SliverGridDelegate
是一個(gè)抽象類,定義了GridView
Layout相關(guān)接口,子類需要通過實(shí)現(xiàn)它們來實(shí)現(xiàn)具體的布局算法。Flutter 中提供了兩個(gè)SliverGridDelegate
的子類SliverGridDelegateWithFixedCrossAxisCount
和SliverGridDelegateWithMaxCrossAxisExtent
,我們可以直接使用,下面我們分別來介紹一下它們。
該子類實(shí)現(xiàn)了一個(gè)橫軸為固定數(shù)量子元素的 layout 算法,其構(gòu)造函數(shù)為: JavaScriptdart SliverGridDelegateWithFixedCrossAxisCount({ @required double crossAxisCount, double mainAxisSpacing = 0.0, double crossAxisSpacing = 0.0, double childAspectRatio = 1.0, })
- `crossAxisCount`:橫軸子元素的數(shù)量。此屬性值確定后子元素在橫軸的長(zhǎng)度就確定了,即ViewPort橫軸長(zhǎng)度除以`crossAxisCount`的商。
- `mainAxisSpacing`:主軸方向的間距。
- `crossAxisSpacing`:橫軸方向子元素的間距。
- `childAspectRatio`:子元素在橫軸長(zhǎng)度和主軸長(zhǎng)度的比例。由于`crossAxisCount`指定后,子元素橫軸長(zhǎng)度就確定了,然后通過此參數(shù)值就可以確定子元素在主軸的長(zhǎng)度。
可以發(fā)現(xiàn),子元素的大小是通過`crossAxisCount`和`childAspectRatio`兩個(gè)參數(shù)共同決定的。注意,這里的子元素指的是子組件的最大顯示空間,注意確保子組件的實(shí)際大小不要超出子元素的空間。
下面看一個(gè)例子:
?```JavaScript
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //橫軸三個(gè)子widget
childAspectRatio: 1.0 //寬高比為1時(shí),子widget
),
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.count
構(gòu)造函數(shù)內(nèi)部使用了SliverGridDelegateWithFixedCrossAxisCount
,我們通過它可以快速的創(chuàng)建橫軸固定數(shù)量子元素的GridView
,上面的示例代碼等價(jià)于:
GridView.count(
crossAxisCount: 3,
childAspectRatio: 1.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),
],
);
該子類實(shí)現(xiàn)了一個(gè)橫軸子元素為固定最大長(zhǎng)度的 layout 算法,其構(gòu)造函數(shù)為:
SliverGridDelegateWithMaxCrossAxisExtent({
double maxCrossAxisExtent,
double mainAxisSpacing = 0.0,
double crossAxisSpacing = 0.0,
double childAspectRatio = 1.0,
})
maxCrossAxisExtent
為子元素在橫軸上的最大長(zhǎng)度,之所以是“最大”長(zhǎng)度,是因?yàn)闄M軸方向每個(gè)子元素的長(zhǎng)度仍然是等分的,舉個(gè)例子,如果 ViewPort 的橫軸長(zhǎng)度是450,那么當(dāng)maxCrossAxisExtent
的值在區(qū)間[450/4,450/3)內(nèi)的話,子元素最終實(shí)際長(zhǎng)度都為112.5,而childAspectRatio
所指的子元素橫軸和主軸的長(zhǎng)度比為最終的長(zhǎng)度比。其它參數(shù)和SliverGridDelegateWithFixedCrossAxisCount
相同。
下面我們看一個(gè)例子:
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 構(gòu)造函數(shù)內(nèi)部使用了 SliverGridDelegateWithMaxCrossAxisExtent,我們通過它可以快速的創(chuàng)建縱軸子元素為固定最大長(zhǎng)度的的 GridView,上面的示例代碼等價(jià)于:
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 都需要一個(gè) widget 數(shù)組作為其子元素,這些方式都會(huì)提前將所有子 widget 都構(gòu)建好,所以只適用于子 widget 數(shù)量比較少時(shí),當(dāng)子 widget 比較多時(shí),我們可以通過GridView.builder
來動(dòng)態(tài)創(chuàng)建子 widget。GridView.builder
必須指定的參數(shù)有兩個(gè):
GridView.builder(
...
@required SliverGridDelegate gridDelegate,
@required IndexedWidgetBuilder itemBuilder,
)
其中itemBuilder
為子 widget 構(gòu)建器。
假設(shè)我們需要從一個(gè)異步數(shù)據(jù)源(如網(wǎng)絡(luò))分批獲取一些Icon
,然后用GridView
來展示:
class InfiniteGridView extends StatefulWidget {
@override
_InfiniteGridViewState createState() => new _InfiniteGridViewState();
}
class _InfiniteGridViewState extends State<InfiniteGridView> {
List<IconData> _icons = []; //保存Icon數(shù)據(jù)
@override
void initState() {
// 初始化數(shù)據(jù)
_retrieveIcons();
}
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //每行三列
childAspectRatio: 1.0 //顯示區(qū)域?qū)捀呦嗟? ),
itemCount: _icons.length,
itemBuilder: (context, index) {
//如果顯示到最后一個(gè)并且Icon總數(shù)小于200時(shí)繼續(xù)獲取數(shù)據(jù)
if (index == _icons.length - 1 && _icons.length < 200) {
_retrieveIcons();
}
return Icon(_icons[index]);
}
);
}
//模擬異步獲取數(shù)據(jù)
void _retrieveIcons() {
Future.delayed(Duration(milliseconds: 200)).then((e) {
setState(() {
_icons.addAll([
Icons.ac_unit,
Icons.airport_shuttle,
Icons.all_inclusive,
Icons.beach_access, Icons.cake,
Icons.free_breakfast
]);
});
});
}
}
_retrieveIcons()
:在此方法中我們通過Future.delayed
來模擬從異步數(shù)據(jù)源獲取數(shù)據(jù),每次獲取數(shù)據(jù)需要200毫秒,獲取成功后將新數(shù)據(jù)添加到 _icons,然后調(diào)用 setState 重新構(gòu)建。
Flutter 的GridView
默認(rèn)子元素顯示空間是相等的,但在實(shí)際開發(fā)中,你可能會(huì)遇到子元素大小不等的情況,如下面這樣的布局:
Pub 上有一個(gè)包“flutter_staggered_grid_view” ,它實(shí)現(xiàn)了一個(gè)交錯(cuò) GridView 的布局模型,可以很輕松的實(shí)現(xiàn)這種布局,詳情讀者可以自行了解。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: