文中所有示例代码请点击: gitee.com/yumi0629/Fl…

今天呢,我小拉面主要想给大家讲一讲Flutter中的 Slivers 大家族的使用场景和方法。开发过列表布局的同学们应该对 Slivers 系列的控件不陌生,或多或少都用过这个库中的控件,来解决复杂的滑动嵌套布局。

比如之前讲Hero的时候提到的下面这个界面,使用普通的GridView的话是没法实现的,我们选择使用 CustomScrollView ,然后在 slivers 属性中添加子控件,在这个例子里,我们可以用SliverToBoxAdapter来做HeaderView,GridView来做主体布局,整体为一个CustomScrollView,完全不会出现任何滑动冲突的问题。

Flutter中的 Slivers 大家族基本都是配合 CustomScrollView 来实现的,除了上面提到的滑动布局嵌套,你还可以使用 Slivers

来实现页面头部展开/收起、 AppBar随手势变换等等功能。官方的Sliver库里面的控件很多,可以去Flutter API网站搜一下,这篇文章我只讲一些常用的控件。 OK, Let's start !!

SliverAppBar

如果你是一名 Android 开发者,一定使用过 CollapsingToolbarLayout 这个布局来实现AppBar展开/收起的功能,在Flutter里面则对应 SliverAppBar 控件。给 SliverAppBar 设置 flexibleSpace 和 expandedHeight 属性,就可以轻松完成AppBar展开/收起的功能:

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 即可:

SliverList

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 的区别:

  • 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]);;
}
);
复制代码

SliverPersistentHeader

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,
),
),
],
);
复制代码

SliverToBoxAdapter

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

Flutter之CustomView的更多相关文章

  1. iOS开发小技巧--获取自定义的BarButtonItem中的自定义View的方法(customView)

    如果BarButtonItem是通过[[UIBarButtonItem alloc] initWithCustomView:(nonnull UIView *)]方法设置的.某些情况下需要修改BarB ...

  2. Flutter 初尝:从 Java 无缝过渡

    准备阶段 下载 Flutter SDK 新建 Flutter 文件夹,克隆 Flutter SDK: git clone -b beta https://github.com/flutter/flut ...

  3. 编写第一个Flutter App(翻译)

    博客搬迁至http://blog.wangjiegulu.com RSS订阅:http://blog.wangjiegulu.com/feed.xml 以下代码 Github 地址:https://g ...

  4. 【译】Java、Kotlin、RN、Flutter 开发出来的 App 大小,你了解过吗?

    现在开发 App 的方式非常多,原生.ReactNative.Flutter 都是不错的选择.那你有没有关注过,使用不同的方式,编译生成的 Apk ,大小是否会有什么影响呢?本文就以一个最简单的 He ...

  5. 我花了 8 小时,"掌握"了一下 Flutter | Flutter 中文站上线

    Hi,大家好,我是承香墨影! 距离 Google 在 2018 世界移动大会上发布 Flutter 的 Beta 版本,Flutter 是 Google 用以帮助开发者在 Android 和 iOS ...

  6. flutter初体验

    flutter初体验 和flutter斗争了两个周末,基本弄清楚了这个玩意的布局和一些常用组件了. 在flutter里面,所有东西都是组件Widget.我们像拼接积木一样拼接Widget,拼接的关键词 ...

  7. Flutter 实现原理及在马蜂窝的跨平台开发实践

    一直以来,跨平台开发都是困扰移动客户端开发的难题. 在马蜂窝旅游 App 很多业务场景里,我们尝试过一些主流的跨平台开发解决方案, 比如 WebView 和 React Native,来提升开发效率和 ...

  8. Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget

    前言 上一篇我们对 Flutter UI 有了一个基本的了解. 这一篇我们通过自定义 Widget 来了解下如何写一个 Widget? 然而 Widget 有两个,StatelessWidget 和 ...

  9. Flutter 异常处理之图片篇

    背景 说到异常处理,你可能直接会认为不就是 try-catch 的事情,至于写一篇文章单独来说明吗? 如果你是这么想的,那么本篇说不定会给你惊喜哦~ 而且本篇聚焦在图片的异常处理. 场景 学以致用,有 ...

随机推荐

  1. .net 发布 web应用程序

    第一步:VS2015中发布 https://jingyan.baidu.com/article/7f41ecec58f7eb593c095c69.html (作用:分离开发代码和测试代码) 第二步:发 ...

  2. [Winfrom] 使用一个启动快捷方式,打开2个不同的窗体并且共用一个缓存空间

    之所以有这个功能,是不想再给后台和前台写一套通讯机制的情况下偷懒的办法! 之前发现在主函数里面写方法,第二次启动程序打开新窗体或是显示隐藏窗体!最后却发现在主函数里面打开的新窗体和原启动的程序并不是共 ...

  3. C# 在PDF中绘制动态图章

    我们知道,动态图章,因图章中的时间.日期可以动态的生成,因而具有较强的时效性.在本篇文章中将介绍通过C#编程在PDF中绘制动态图章的方法,该方法可自动获取当前系统登录用户名.日期及时间信息并生成图章. ...

  4. 36.QT-解决无边框界面拖动卡屏问题(附带源码)

    1.简介 看到很多才学QT的人都会问为啥无边框拖动为啥会花屏? 那是因为你每次拖动的过程中都一直在调用move()函数让QT重新绘制界面,如果资源过大,就会导致当前图形还未绘制完,便又重新改变坐标了, ...

  5. python3.6 pip 出现locations that require TLS/SSL异常解决方案

    在给CentOS服务器安装完Python3.6后,使用pip命令出现问题,提示说无法找到ssl模块. 上网查询后发现在安装Python3.6时没有安装openssl-devel依赖库,解决方案如下: ...

  6. python爬虫项目(scrapy-redis分布式爬取房天下租房信息)

    python爬虫scrapy项目(二) 爬取目标:房天下全国租房信息网站(起始url:http://zu.fang.com/cities.aspx) 爬取内容:城市:名字:出租方式:价格:户型:面积: ...

  7. css direction 属性简介与实际应用。

    目前正在用vue构建组件库.写到弹框的时候没想到按钮的顺序问题,但是在应用中,确实会有选项按钮顺序不同的情况发生,但是又想共用一个组件.那么问题就出现了.后来看到了这篇文章,才茅塞顿开. direct ...

  8. zabbix3.4 监控mysql 数据库连接数

    zabbix3.4 监控mysql 数据库连接数具体监控配置待定,近期即将发布!

  9. iOS---------- Safe Area Layout Guide before iOS 9.0

    如果你们的项目不做iOS9以下支持就打开main.storyboard    去除Use safe Area Layout 如果不考虑iOS9以下支持就按照下面的步骤 选中控制器,右边面板的Build ...

  10. adb部署及使用

    一 掌握adb部署&使用方法及常用命令 1.何为adb? sdk软件开发套件software development kit apk是安卓应用安装包 adb是android sdk的一个工具, ...