Flutter之CustomView

文中全部示例代碼請點擊: gitee.com/yumi0629/Fl…html

今天呢,我小拉麪主要想給你們講一講Flutter中的 Slivers 你們族的使用場景和方法。開發過列表佈局的同窗們應該對 Slivers 系列的控件不陌生,或多或少都用過這個庫中的控件,來解決複雜的滑動嵌套佈局。android

好比以前講Hero的時候提到的下面這個界面,使用普通的GridView的話是無法實現的,咱們選擇使用 CustomScrollView ,而後在 slivers 屬性中添加子控件,在這個例子裏,咱們能夠用SliverToBoxAdapter來作HeaderView,GridView來作主體佈局,總體爲一個CustomScrollView,徹底不會出現任何滑動衝突的問題。git

Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!Flutter中的  Slivers 你們族基本都是配合  CustomScrollView 來實現的,除了上面提到的滑動佈局嵌套,你還可使用  Slivers

來實現頁面頭部展開/收起、 AppBar隨手勢變換等等功能。官方的Sliver庫裏面的控件不少,能夠去Flutter API網站搜一下,這篇文章我只講一些經常使用的控件。 OK, Let's start !!程序員

SliverAppBar

若是你是一名 Android 開發者,必定使用過 CollapsingToolbarLayout 這個佈局來實現AppBar展開/收起的功能,在Flutter裏面則對應 SliverAppBar 控件。給 SliverAppBar 設置 flexibleSpace 和 expandedHeight 屬性,就能夠輕鬆完成AppBar展開/收起的功能:ide

CustomScrollView( slivers: <Widget>[ SliverAppBar( actions: <Widget>[ _buildAction(), ], title: Text('SliverAppBar'), backgroundColor: Theme.of(context).accentColor, expandedHeight: 200.0, flexibleSpace: FlexibleSpaceBar( background: Image.asset('images/food01.jpeg', fit: BoxFit.cover), ), // floating: floating, // snap: snap, // pinned: pinned, ), SliverFixedExtentList( itemExtent: 120.0, delegate: SliverChildListDelegate( products.map((product) { return _buildItem(product); }).toList(), ), ), ], ); 複製代碼
Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!若是設置  floating 屬性爲  true

,那麼AppBar會在你作出下拉手勢時就當即展開(即便ListView並無到達頂部),該展開狀態不顯示flexibleSpace:函數

Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!若是同時設置  floating 和  snap 屬性爲  true

,那麼AppBar會在你作出下拉手勢時就當即所有展開(即便ListView並無到達頂部),該展開狀態顯示flexibleSpace:佈局

Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!

若是不想AppBar消失,則設置 pinned 屬性爲 true 便可:flex

Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!

SliverList

SliverList 的使用很是簡單,只需設置 delegate 屬性便可,咱們通常使用 SliverChildBuilderDelegate ,注意記得設置 childCount ,不然Flutter無法知道怎麼繪製:優化

CustomScrollView( slivers: <Widget>[ SliverList( delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return _buildItem(context, products[index]); }, childCount: 3, ), ) ], ); 複製代碼
Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!

你也能夠經過下面的方式來設置childCount,若是不設置childCount,Flutter一旦發現delegate的某個index返回了null,就會認爲childCount就是這個index。網站

delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { if(index>products.length){ return null; } return _buildItem(context, products[index]); }, 複製代碼

你也可使用 SliverChildListDelegate 來構建delegate:

delegate: SliverChildListDelegate([ _buildItem(), _buildItem(), _buildItem(), ]), 複製代碼

SliverChildListDelegate 和 SliverChildBuilderDelegate 的區別:

  • SliverChildListDelegate通常用來構item建數量明確的列表,會提早build好全部的子item,因此在效率上會有問題,適合item數量很少的狀況(不超過一屏)。
  • SliverChildBuilderDelegate構建的列表理論上是能夠無限長的,由於使用來lazily construct優化。 (二者的區別有些相似於ListView和ListView.builder()的區別。)

SliverGrid

SliverGrid 有三個構造函數: SliverGrid.count() 、 SliverGrid.extent 和 SliverGrid() 。

  • SliverGrid.count() 指定了一行展現多少個item,下面的例子表示一行展現4個:
SliverGrid.count(children: scrollItems, crossAxisCount: 4) 複製代碼
  • SliverGrid.extent 能夠指定item的最大寬度,而後讓Flutter本身決定一行展現多少個item:
SliverGrid.extent(children: scrollItems, maxCrossAxisExtent: 90.0) 複製代碼
  • SliverGrid() 則是須要指定一個gridDelegate,它提供給了 程序員 一個自定義Delegate的入口,你能夠本身決定每個item怎麼排列:
SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: products.length, ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return _buildItem(products[index]);; } ); 複製代碼
Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!

SliverPersistentHeader

SliverPersistentHeader 顧名思義,就是給一個可滑動的視圖添加一個頭(實際上,在CustomScrollView的slivers列表中,header能夠出如今視圖的任意位置,不必定要是在頂部)。 這個Header會隨着滑動而展開/收起 ,使用 pinned 和 floating 屬性來控制收起時Header是否展現( pinned 和 floating 屬性不能夠同時爲 true ), pinned 和 floating 屬性的具體意義和SliverAppBar中相同,這裏就再也不次解釋了。

Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!
SliverPersistentHeader( pinned: pinned, floating: floating, delegate: _SliverAppBarDelegate( minHeight: 60.0, maxHeight: 180.0, child: Container(), ), ); 複製代碼

構建一個 SliverPersistentHeader 須要傳入一個delegate,這個delegate是SliverPersistentHeaderDelegate類型的,而SliverPersistentHeaderDelegate是一個abstract類,咱們不能直接new一個SliverPersistentHeaderDelegate出來,所以,咱們須要自定義一個delegate來實現SliverPersistentHeaderDelegate類:

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { _SliverAppBarDelegate({ @required this.minHeight, @required this.maxHeight, @required this.child, }); final double minHeight; final double maxHeight; final Widget child; @override double get minExtent => minHeight; @override double get maxExtent => math.max(maxHeight, minHeight); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return new SizedBox.expand(child: child); } @override bool shouldRebuild(_SliverAppBarDelegate oldDelegate) { return maxHeight != oldDelegate.maxHeight || minHeight != oldDelegate.minHeight || child != oldDelegate.child; } } 複製代碼

寫一個自定義SliverPersistentHeaderDelegate很簡單,只需重寫 build() 、 get maxExtent 、 get minExtent 和 shouldRebuild() 這四個方法,上面就是一個最簡單的SliverPersistentHeaderDelegate的實現。其中, maxExtent表示header徹底展開時的高度, minExtent 表示header在收起時的最小高度。所以,對於咱們上面的那個自定義Delegate,若是將 minHeight 和 maxHeight 的值設置爲相同時,header就不會收縮了,這樣的Header跟咱們日常理解的Header更像。

以前也提到了,實際使用時,header不必定要放在slivers列表的最前面,能夠隨意混搭,固然,通常來講不會有這種視覺需求的:

CustomScrollView( slivers: <Widget>[ _buildHeader(0), SliverGrid.count( crossAxisCount: 3, children: _products.map((product) { return _buildItemGrid(product); }).toList(), ), _buildHeader(1), SliverFixedExtentList( itemExtent: 100.0, delegate: SliverChildListDelegate( products.map((product) { return _buildItemList(product); }).toList(), ), ), _buildHeader(2), SliverGrid( gridDelegate: new SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200.0, mainAxisSpacing: 10.0, crossAxisSpacing: 10.0, childAspectRatio: 3.0, ), delegate: new SliverChildBuilderDelegate( (BuildContext context, int index) { return _buildItemGrid2(_products2[index]); }, childCount: _products2.length, ), ), ], ); 複製代碼

SliverToBoxAdapter

SliverPersistentHeader通常來講都是會展開/收起的(除非minExtent和maxExtent值相同),那麼若是想要在滾動視圖中添加一個普通的控件,那麼就可使用 SliverToBoxAdapter 來將各類視圖組合在一塊兒,放在CustomListView中。

Flutter:Slivers你們族,讓滑動視圖的組合變得很簡單!

上圖中框起來的部分所有都是SliverToBoxAdapter,結合SliverToBoxAdapter,滾動視圖能夠任意組合:

CustomScrollView( physics: ScrollPhysics(), slivers: <Widget>[ SliverToBoxAdapter( child: _buildHeader(), ), SliverGrid.count( crossAxisCount: 3, children: products.map((product) { return _buildItemGrid(product); }).toList(), ), SliverToBoxAdapter( child: _buildSearch(), ), SliverFixedExtentList( itemExtent: 100.0, delegate: SliverChildListDelegate( products.map((product) { return _buildItemList(product); }).toList(), ), ), SliverToBoxAdapter( child: _buildFooter(), ), ], ); 

 原文:https://www.codercto.com/a/34161.html

相關文章
相關標籤/搜索