文中全部示例代码请点击: gitee.com/yumi0629/Fl…html
今天呢,我小拉面主要想给你们讲一讲Flutter中的 Slivers
你们族的使用场景和方法。开发过列表布局的同窗们应该对 Slivers
系列的控件不陌生,或多或少都用过这个库中的控件,来解决复杂的滑动嵌套布局。android
好比以前讲Hero的时候提到的下面这个界面,使用普通的GridView的话是无法实现的,咱们选择使用 CustomScrollView
,而后在 slivers
属性中添加子控件,在这个例子里,咱们能够用SliverToBoxAdapter来作HeaderView,GridView来作主体布局,总体为一个CustomScrollView,彻底不会出现任何滑动冲突的问题。git
Slivers
你们族基本都是配合
CustomScrollView
来实现的,除了上面提到的滑动布局嵌套,你还可使用
Slivers
来实现页面头部展开/收起、 AppBar随手势变换等等功能。官方的Sliver库里面的控件不少,能够去Flutter API网站搜一下,这篇文章我只讲一些经常使用的控件。 OK, Let's start !!程序员
若是你是一名 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(), ), ), ], ); 复制代码
floating
属性为
true
,那么AppBar会在你作出下拉手势时就当即展开(即便ListView并无到达顶部),该展开状态不显示flexibleSpace:函数
floating
和
snap
属性为
true
,那么AppBar会在你作出下拉手势时就当即所有展开(即便ListView并无到达顶部),该展开状态显示flexibleSpace:布局
若是不想AppBar消失,则设置 pinned
属性为 true
便可:flex
SliverList
的使用很是简单,只需设置 delegate
属性便可,咱们通常使用 SliverChildBuilderDelegate
,注意记得设置 childCount
,不然Flutter无法知道怎么绘制:优化
CustomScrollView( slivers: <Widget>[ SliverList( delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return _buildItem(context, products[index]); }, childCount: 3, ), ) ], ); 复制代码
你也能够经过下面的方式来设置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
的区别:
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]);; } ); 复制代码
SliverPersistentHeader
顾名思义,就是给一个可滑动的视图添加一个头(实际上,在CustomScrollView的slivers列表中,header能够出如今视图的任意位置,不必定要是在顶部)。 这个Header会随着滑动而展开/收起 ,使用 pinned
和 floating
属性来控制收起时Header是否展现( pinned
和 floating
属性不能够同时为 true
), pinned
和 floating
属性的具体意义和SliverAppBar中相同,这里就再也不次解释了。
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, ), ), ], ); 复制代码
SliverPersistentHeader通常来讲都是会展开/收起的(除非minExtent和maxExtent值相同),那么若是想要在滚动视图中添加一个普通的控件,那么就可使用 SliverToBoxAdapter
来将各类视图组合在一块儿,放在CustomListView中。
上图中框起来的部分所有都是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