文章目錄
下面我們來介紹下Flutter中的滑動控件
SingleChildScrollView
、列表ListView
和表格GridView
。
1. SingleChildScrollView
SingleChildScrollView
類似於Android中的ScrollView
,我使用的較淺,在我目前看來,他和ScrollView
的唯一區別就是它還可以橫向滾動。
我們先來看下他的定義:
SingleChildScrollView({
this.scrollDirection = Axis.vertical, //滾動方向,默認是垂直方向
this.reverse = false,
this.padding,
bool primary,
this.physics,
this.controller,
this.child,
})
scrollDirection
:設定滾動的方向,可以設定Axis.vertical
或者Axis.horizon
;reverse
:是否按照閱讀方向的反方向滑動,emmm這個可能有點覺得莫名其妙,但是如阿拉伯語言地區,他們閱讀和我國古時候一樣是從右向左的,所以如果reverse
爲true
,且滾動方向是水平滾動的話,如果系統時阿拉伯語等從右向左閱讀的語言時,方向是從右向左的;padding
:留白的大小,和Padding
的用法一樣,通過EdgeInsets
來設定,具體可以看前幾章將Flutter基礎Widget;primary
:指是否使用widget樹中默認的PrimaryScrollController
;當滑動方向爲垂直方向(scrollDirection
值爲Axis.vertical
)並且沒有指定controller
時,primary
默認爲true
;physics
:用於控制滾動方式,這個等會重點講解;controller
:用於滾動監聽及控制;child
:子Widget。
1.2 physics
這個參數是用於控制滾動方式,有幾種參數:
NeverScrollablePhysics
:呈現不可滾動狀態;BouncingScrollPhysics
:當列表滑動結束時,會回彈列表,類似於iOS的列表滑動效果;
ClampingScrollPhysics
:滑動結束時會顯示水波紋陰影,類似於Android的列表滑動效果;
FixedExtentScrollPhysics
:可以自己製作滑動效果,但是我也不會,所以在此不做解釋?。
2. ListView
ListView
可以沿一個方向上線性排布所有子組件(不僅侷限於豎直方向)。
讓我們來看下他的定義:
ListView({
...
//可滾動widget公共參數
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
EdgeInsetsGeometry padding,
//ListView各個構造函數的共同參數
double itemExtent,
bool shrinkWrap = false,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
double cacheExtent,
//子widget列表
List<Widget> children = const <Widget>[],
})
公共屬性我們就不講了,上面SingleChildScrollView
已經講過了,我們現在只講他特有的:
itemExtent
:用於控制ListView
的長度,如果不爲null
,則強制所有子Widget合起來的長度小於設定的值:如果ListView
是橫向的,則所有子Widget橫向長度的和小於它;如果ListView
是縱向的,則所有子Widget縱向長度的和小於它;shrinkWrap
:該屬性表示是否根據子組件的總長度來設置ListView
的長度,默認值爲false
。默認情況下,ListView
的會在滾動方向儘可能多的佔用空間。當ListView
在一個無邊界(滾動方向上)的容器中時,shrinkWrap
必須爲true
;addAutomaticKeepAlives
:該屬性表示是否將列表項(子組件)包裹在AutomaticKeepAlive
組件中;典型地,在一個懶加載列表中,如果將列表項包裹在AutomaticKeepAlive
中,在該列表項滑出視口時它也不會被GC(垃圾回收)
,它會使用KeepAliveNotification
來保存其狀態。如果列表項自己維護其KeepAlive
狀態,那麼此參數必須置爲false
;addRepaintBoundaries
:該屬性表示是否將列表項(子組件)包裹在RepaintBoundary
組件中。當可滾動組件滾動時,將列表項包裹在RepaintBoundary
中可以避免列表項重繪,但是當列表項重繪的開銷非常小(如一個顏色塊,或者一個較短的文本)時,不添加RepaintBoundary
反而會更高效。和addAutomaticKeepAlive
一樣,如果列表項自己維護其KeepAlive
狀態,那麼此參數必須置爲false
;cacheExtent
:設定緩存大小。
默認情況下一個一個設定children
很麻煩,所以爲了方便,Flutter還提供了一個builder
構造方法:
2.1 ListView.builder
ListView.builder({
// ListView公共參數已省略
...
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
...
})
itemCount
:是需要加載子Widget的長度;itemBuilder
:列表項的構造器,當列表滾動到具體的index
位置時,會調用該構建器構建列表項。
看例子:
ListView.builder(
itemCount: _provinces.length,
itemBuilder: (context, index) {
return GestureDetector(
child: ListTile(
title: Text("$index"),
),
onTap: () {}));
},
);
},
)
2.2 ListView.separated
用於添加分割線。相較於ListView.builder
多了一個separatorBuilder
參數,該參數是一個分割組件生成器。
下面我們看一個例子:奇數行添加一條藍色下劃線,偶數行添加一條綠色下劃線。
class ListView3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
//下劃線widget預定義以供複用。
Widget divider1=Divider(color: Colors.blue,);
Widget divider2=Divider(color: Colors.green);
return ListView.separated(
itemCount: 100,
//列表項構造器
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("$index"));
},
//分割器構造器
separatorBuilder: (BuildContext context, int index) {
return index%2==0?divider1:divider2;
},
);
}
}
3. GridView
GridView
可以構造一個網格列表,定義如下:
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>[],
})
大部分參數和ListView
都相同,我們只關注gridDelegate
這個參數:
gridDelegate
作用是控制GridView
子組件如何排列,Flutter中提供了兩個類SliverGridDelegateWithFixedCrossAxisCount
和SliverGridDelegateWithMaxCrossAxisExtent
,我們可以直接使用,下面我們分別來介紹一下它們。
3.1 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
指定後,子元素橫軸長度就確定了,然後通過此參數值就可以確定子元素在主軸的長度。
3.2 SliverGridDelegateWithMaxCrossAxisExtent
該子類實現了一個橫軸子元素爲固定最大長度的layout算法,其構造函數爲:
SliverGridDelegateWithMaxCrossAxisExtent({
double maxCrossAxisExtent,
double mainAxisSpacing = 0.0,
double crossAxisSpacing = 0.0,
double childAspectRatio = 1.0,
})
maxCrossAxisExtent
爲子元素在橫軸上的最大長度,之所以是“最大”長度,是因爲橫軸方向每個子元素的長度仍然是等分的。其它參數和SliverGridDelegateWithFixedCrossAxisCount
相同。
3.3 GridView.builder
和ListView
一樣,當子Widget數量較多時,也提供了builder
方法:
GridView.builder(
...
@required SliverGridDelegate gridDelegate,
@required IndexedWidgetBuilder itemBuilder,
)
這個就不在這舉例了,gridDelegate
和前面一樣的,itemBuilder
和ListView
的一樣的。