Flutter GridView
網格佈局在移動開發中也經常使用,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<Widget> children = const <Widget>[],
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給我們提供更加方便的方法供我們使用
GridView.count
沒什麼好說的,跟上面的SliverGridDelegateWithFixedCrossAxisCount雷同
示例代碼:
GridView.count(
padding: EdgeInsets.all(10),
crossAxisSpacing: 10,
crossAxisCount: 3,
mainAxisSpacing: 10,
children: List.generate(
20,
(index) {
return Box(index + 1);
},
),
);
GridView.extent
跟SliverGridDelegateWithMaxCrossAxisExtent類似
GridView.extent(
scrollDirection: Axis.horizontal,
maxCrossAxisExtent: MediaQuery.of(context).size.height/9,
children: List.generate(
20,
(index) {
return Box(index + 1);
},
),
);
Flutter GridView異步加載/加載更多(GridView.builder)
跟構造方法使用方式差不多,主要是用來做異步數據加載的,前面幾種方式都是在數據確定的情況下,實際上,我們的數據基本上都是從網絡上獲取的,有分頁獲取的需求,這個時候就用到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<StatefulWidget> createState() {
return _GridViewVBuilder();
}
}
class _GridViewVBuilder extends State<GridViewWidget> {
List<int> 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 博客專欄,我會不定期的更新,如果文中有什麼錯誤的地方,還望指正,轉載請註明轉自喻志強的博客 ,謝謝!