Flutter列表
一起從0開始學習Flutter!
基本上的組件學的差不多了,我們開始一起來學習日常用的最多的列表功能。列表我們一般常用的有ScrollView,ListView,和GridView,在Flutter中也是有一一對應的組件,在Flutter裏ScrollView是抽象類無法直接被實例化,我們可以使用它的子類,如NestedScrollView,BoxScrollView,在Flutter比較特殊ListView,GridView也是ScrollView的子類。我們依次看下。
1.NestedScrollView
這裏的NestedScrollView跟Android中的意義不一樣,在Android中是直接一個可以滑動的列表,我們將子View放到ScrollView下的ViewGroup中就可以實現一個頁面的滾動,而這裏的NestedScrollView是做了一個包含TabBar的一個封裝,我們可以利用它輕鬆的實現向上滑動的時候頂部的摺疊。
const NestedScrollView({
Key key,
this.controller,//滾動操作的控制器,給我們一個默認值_NestedScrollController,如果需要修改可以模仿來做更改
this.scrollDirection = Axis.vertical, //滾動的方向,Axis.vertical豎向滾動,horizontal橫向滾動
this.reverse = false,//是否頁面做翻轉,如果是True則bar在下面,滾動的在上面
this.physics,//當用戶停止滑動,滑動到頂部時的動作
@required this.headerSliverBuilder,//參照下面的詳細說明
@required this.body,//參照下面的詳細說明
this.dragStartBehavior = DragStartBehavior.start,//拖拽開始的狀態
})
headerSliverBuilder
向上滑動的時候的摺疊區域,可以傳入一組的控件 List,如果我們在向上滑動的時候可以摺疊的話我們需要返回一個SliverOverlapAbsorber,SliverOverlapAbsorber稍後我們做詳細解釋。
body
傳入一個可以滑動的佈局,比如我們可以傳入一個CustomScrollView,我們則可以通過CustomScrollView來實現頁面的滑動,也可以傳入SliverList,SliverGrid讓頁面滾動起來。
先來看下上面提到的SliverOverlapAbsorber。
2.SliverOverlapAbsorber
使用SliverOverlapAbsorber包裹SliverAppBar讓在滑動的時候可以進行通知頭部,控制AppBar的收放。還是先看下構造函數:
const SliverOverlapAbsorber({
Key key,
@required this.handle, //參照下面的詳細說明
Widget child,//需要控制的組件,一般使用SliverAppBar
})
handle
作爲一個必選參數來控制堆疊時的控件高度,我們一般使用下面NestedScrollView.sliverOverlapAbsorberHandleFor來創建一個默認的操作。
handle:NestedScrollView.sliverOverlapAbsorberHandleFor(context)
3.SliverAppBar
跟AppBar有很多共通的參數,我們可以拿出來它與AppBar的不同之處來作解釋:
const SliverAppBar({
Key key,
this.flexibleSpace,//我們需要顯示的標題欄裏的內容,可以根據需要進行自己的設置,比如一個Text
this.forceElevated = false,//是否保留SliverAppBar下面的陰影,True不管是滾動還是停止都有陰影,False則都不顯示
this.expandedHeight,//標題欄和文字說明直接的間距
this.floating = false,//和snap配合使用
this.pinned = false,//頂部的Title欄是否是固定的,False則不顯示title欄,True則會滑動時保留title欄
this.snap = false,//和floating配合使用,兩個都是True則滑動到頂再下向滑動時首先是標題欄先滑下來,然後再是列表的向下滾動。
this.stretch = false,//是否拉伸以充滿滑動區域,沒有試出來它的效果
this.stretchTriggerOffset = 100.0,//設定調用onStretchTrigger的滑動距離
this.onStretchTrigger,//設定的回調
...
})
設置還是比較簡單,可以根據我們是否需要滾動,是否滾動的時候是否固定頭部來進行設置。
4.ListView
作爲一個線性排布所有子控件的容器,它其實比較像在Android中認識的ScrollView,但是我們可以通過itemBuilder來實現Android中的ListView的形式。先看下ListView的構造方法,先省略NestedScrollView裏面共通的參數:
ListView({
Key key,
bool shrinkWrap = false,//是否根據子組件的總長度來設置ScrollView的長度,如果ScrollView的父容器是一個無邊際的的容器則設置爲True。
EdgeInsetsGeometry padding,//設置ListView的內填充大小
this.itemExtent,//如果不爲空則會強制children的長度爲itemExtent的值。
bool addAutomaticKeepAlives = true,//是否將列表項放到AutomaticKeepAlive組件中,在懶加載的時候如果設置爲True則滑出窗口視圖的時候不會被回收,由KeepAliveNotification來保存狀態
bool addRepaintBoundaries = true,//是否將列表項放到RepaintBoundary組件中,設置爲True在列表滾動的時候可以避免重繪,但是如果每個Item都很簡單比較小的時候如果設置爲True會更高效。
bool addSemanticIndexes = true,//設置是否將列表項添加到用位置來表示的語義控件中,還是原來說到的輔助功能使用的
double cacheExtent,//緩存的長度
List<Widget> children = const <Widget>[],//參照下面的詳細說明
int semanticChildCount,//語義表達的列表項的數量,還是輔助功能使用。
...
})
children
這裏用來存放滑動的內容,我們可以創建一組Text爲了測試滑動比如:
ListView(
children: <Widget>[
Text("Hello"),
Text("Hello"),
Text("Hello"),
Text("Hello"),
],
)
如果要是顯示一組內容相同的列表我們可以使用ListView的建造者模式的方法ListView.builder()
,其他的參數同ListView只是多了一個
@required IndexedWidgetBuilder itemBuilder,
我們可以通過它來創建一組數據的列表比如:
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text("Hello" + index.toString());
},
padding: EdgeInsets.all(30),
)
常用的還有ListView.separated()只是比ListView.builder()多了一個分割線的設置,不再贅述,可以自己試一下。
5.GridView
跟ListView的參數有很大的相似度,它的功能就是將豎向列表在橫向也可以按照指定的塊數顯示。我們看下它的構造方法,跟ListView類似的不再說明:
GridView({
Key key,
@required this.gridDelegate,//參照下面的詳細說明
...
})
gridDelegate
我們看到需要傳入一個SliverGridDelegate,但是該類是一個抽象類,我們需要傳入一個實現類,找到了SliverGridDelegateWithFixedCrossAxisCount,我們將其傳入,來看下它有哪些參數
const SliverGridDelegateWithFixedCrossAxisCount({
@required this.crossAxisCount,//要劃分的塊數
this.mainAxisSpacing = 0.0,//跟主要滑動方向一致的每塊間隔大小
this.crossAxisSpacing = 0.0,//另外一個方向上每塊間隔大小
this.childAspectRatio = 1.0,//滑動方向和另一方向塊的大小比例
})
一個簡單的使用:
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:3,
mainAxisSpacing:10,
crossAxisSpacing: 10,
),
children: <Widget>[
Text("Hello",style: TextStyle(backgroundColor: Colors.green),),
Text("Hello"),
Text("Hello"),
Text("Hello"),
],
),
在GridView中也有builder()和separated()方法,跟ListView的方法一致。
6.SliverList
可以理解爲我們可以將多個佈局按照一個順序來進行的排列,每個都是單獨的個體。它的構造比較簡單,我們看下:
const SliverList({
Key key,
@required SliverChildDelegate delegate,//參照下面的詳細說明
})
delegate
就只需要傳入一個代理,SliverChildDelegate是一個抽象類,我們還需要找到它的實現SliverChildListDelegate,來看下SliverChildListDelegate的構造:
SliverChildListDelegate(
this.children, {
this.addAutomaticKeepAlives = true,
this.addRepaintBoundaries = true,
this.addSemanticIndexes = true,
this.semanticIndexCallback = _kDefaultSemanticIndexCallback,
this.semanticIndexOffset = 0,
})
跟List基本上一樣的參數,只是children是一組組件,我們需要一個個的實現,SliverChildDelegate下面還有一個實現是SliverChildBuilderDelegate,這個可以幫助我們快速的創建一組列表與ListView相同的略過:
const SliverChildBuilderDelegate(
this.builder, //這裏創建了一個構造器,下面詳細說明
{this.findChildIndexCallback,//構造一個返回當前Item的Index的方法
this.childCount,//想要顯示的Item的數量
...
})
builder
可以看到它的定義是比較有意思的,是定義了一個方法:
typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index);
我們需要傳一個函數進去,可以簡單的試一下:
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.red,
child: Text("position is $index",style: TextStyle(fontSize: 14,color: Colors.black),),
);
}
)
這樣就構造了一個我想要顯示的每一個條目的樣式,然後控制數量和緩存機制就可以了。
7.SliverGrid
跟GridView是一樣的顯示形式,只是也是進行了分塊,我們還是看下構造方法:
const SliverGrid({
Key key,
@required SliverChildDelegate delegate,
@required this.gridDelegate,
})
只是比上面的SliverList多了一個gridDelegate,我們只看下gridDelegate,看到它需要傳入SliverGridDelegate,但是也是一個抽象類,還是看下它的實現SliverGridDelegateWithFixedCrossAxisCount,嗯,是的,跟GridView中的是一樣的,我們可以直接去看GridView中的說明。這樣進行設置後一個可以分割的Grid就完成了。
8.CustomScrollView
跟ScrollView也不是一樣的,它比較像是一個粘合劑的作用,如果我們的列表顯示多個列表的組合那麼可以放置到CustomScrollView裏面,來保證它們的滑動事件的統一,裏面也可以放置像ListView和GridView這樣子的組件,但是需要注意如果我們需要讓他們聯合滾動需要不能使用ListView和GridView,我們需要一種已經幫我們做好分割的SliverList和SliverGrid,還是先看下他的構造方法,有部分同NestedScrollView直接去掉了:
const CustomScrollView({
Key key,
bool primary,//如果爲True則會讓它的Controller創建一個PrimaryScrollController的實體,不能再自定義Controller。
bool shrinkWrap = false,//是否根據子組件的總長度來設置ScrollView的長度,如果ScrollView的父容器是一個無邊際的的容器則設置爲True。
Key center,
this.slivers = const <Widget>[],//參照下面的詳細說明
...
})
slivers
這裏我們就要放入可分裂的組件了,我們可以將上面的SliverList或者SliverGrid放入其中,可以混合放入,這樣就成了一個混合列表。
滾動頁面的內容比較複雜,不是很好理解,還是建議多去試一試,這樣可以加深我們的記憶。