各位少侠、小伙伴们大家好!
how old are you ? 没错又是我!
在 Flutter 视图布局(一)中文章结束时留下了一个问题,大家有尝试去实现吗?
如果大家认真看文章的话,我觉得这并不是很难的东西。
当然如果有配合 github 项目的代码来看的话,一定会发现我也已经将实现好的代码也更新上去了,可以作为实现参考。
好,那么我们就废话不多说,这次我们就来说道说道 ListBody 和 ListView 这两个常用的布局 List Widget。
在此之前我们还是要说说 Flutter 的包管理方式,因为这是开发中必不可少的绕不开的一部分。
在 MyApp 项目目录下有个 pubspec.yaml 文件,这个文件主要是 Flutter 用于管理外部依赖项。
YAML 是一个标记性语言,它对大小写敏感,由于不像其他类型文件的数据格式拥有明显的父、子级标记而是默认使用空格缩进(2个空格)代表层级,比如用“- ”(中划线+空格)来表示列表。
当然,在在默认的文件中也有示例说明,这就需要你自己去打开文件看一看啦。
在默认的文件情况下我们可以看到一级分类由以下类型组成。现在我们从上到下来分别解释一下这些东西到底是干什么的:
然后现在我们先在 dependencies 中加入 english_words,这个英文单词的包主要是用于后续的例子中,可以先考虑引入。
english_words: ^3.1.0
在添加完新的依赖包后,当你进行保存时 VS Code 会自动进行依赖包的更新和下载,还是比较方便的,就不需要手动进行更新命令了。
flutter packages get
flutter pub get
ok,接下来我们可以说说 ListBody 和 ListView 了
配合文章一同食用的代码已同步更新到 Github 地址:
https://github.com/linxsbox/myapp.git
01 - ListBody
我们先来看看 ListBody 的源码部分
这不看都不知道,相比 Row、Column 来说简直是太简单了:
都看到这了,才三个属性,那还等什么当然是上手就干啊!(我的嘴角微微上翘,噼里啪啦一顿猛敲……)
看着代码完成了,也没有明显报错,这很OK,召唤控制台 - 输入 - R
这是怎么回事?发生了什么!?
冷静一下不要慌,让我们来看看源码。
看完之后发现,原来 ListBody 是一个可以设定轴方向的 多子元素列表,但是需要一个可以强制范围的容器来装载它。而且这是一个很少能够直接使用的 Widget,如果需要的话应该优先选择 ListView,因为它有相同的布局方式以及提供了滚动行为。
(摸着下巴若有所思)OK,那我们就来把他放在 ListView 下。
这样就没什么问题了,正好顺便可以来说说 ListVIew。
02 - ListView
关于 ListView 还是要先认真看下源码,这次可不能那么鲁莽。
仔细一看,这属性还挺多。不着急,那我们分别都来看一看。
reverse
reverse 就是将列表的渲染方式是否是反向,垂直方向从底部开始,水平方向从右边开始
controller
关于滚动事件,如果真要说的话,那么篇幅就太长了,所以这里暂时不讲,后续会将一些 Widget 的事件 整理出来。
如果各位少侠小伙伴们有兴趣的,可以先看看这个滚动事件参考:
https://book.flutterchina.club/chapter6/scroll_controller.html
https://api.flutter.dev/flutter/widgets/ScrollView/controller.html
当 primary 为 true 时 则会 喜提满屏红。
在源码中有这样一段:如果 primary 为 true 则 controller 必须为 null,controller 滚动事件,与 primary 互斥。
addAutomaticKeepAlives
是否将子项都装在 AutomaticKeepAlive 中,默认为 true。
addAutomaticKeepAlives 源码部分说明
简单来说(翻译一下),通常列表是懒惰的,将子类元素装在 AutomaticKeepAlive 中,以便其子级元素可以使用 KeepAliveNotification 来保留状态,否则它们在屏幕外将被回收。
如果需要手动维护子类元素的子级元素那么就必须禁用此功能(false)(以及 addRepaintBoundaries 设为 false)。
再简单来说,就是子元素可以超出屏幕之外还继续保留,但是这个状态的保留由框架负责。如果你需要自己决定如何保留子元素的状态,那么就把 addAutomaticKeepAlives 和 addRepaintBoundaries 关了自己写去。
addRepaintBoundaries
是否将子项都装在 RepaintBoundary 中,默认为 true。
简单来说(翻译一下),通常在可滚动列表的容器中子项都会被装在重绘边界之内,以便列表在滚动时不需要将它们进行重绘。如果是简单的子项内容(纯色块或者短文本),则关闭addRepaintBoundaries(false)让其重绘子项可能会更有效率。
简单来说,不能再简单了,请少侠自己思考。
addSemanticIndexes
是否将子项都装在 IndexedSemantics 中,默认依然为 true。
cacheExtent
在视图可见区域之外有一个区域(即垂直是上下部分,水平是左右部分),用于缓存滚动即进入可见区域的子类。
进入此缓存区域的子项在即使未在可见视图内也是可见的,即是进入可见区域后就会被布局渲染,cacheExtent 主要是用于描述该区域所延伸的大小。
physics
physics 主要是 滚动的物理效果
AlwaysScrollableScrollPhysics 和 NeverScrollableScrollPhysics 就不用演示效果了,毕竟这个意思和 CSS 中 overflow 的 scroll 和 hidden 一个意思。
ClampingScrollPhysics 我也不知道为什么要用 Clamping,可能是像钳子一样拥有最大张合度吧。在默认情况下,如果列表子元素不足以超出可视范围则不会产生可滚动行为。如超出可视范围则到达列表尽头时会停留并有水波样式出现。
BouncingScrollPhysics 的话就是大家都熟悉的回弹效果了,当操作列表到达可视范围尽头时还可以继续超出一定的空间,当失去焦点后回到尽头的位置,这样就能给予用户一个良好的使用体验。一般来说都会在下拉刷新上拉加载这样的场景里使用。
FixedExtentScrollPhysics 是类似拨轮的效果,怎么说呢,这个用文字还真不好描述效果,看一张实物图大概就能理解了。
以上就是 ListView 属性的使用说明了,但是你可能会问了,这些子元素你写那么多不现实啊,真正使用到的时候肯定都是按需生成的,不然如果有很多子元素不可能都 copy paste一遍吧?
03 - 无线滚动例子
很好,我很佩服你提问的勇气!不过没关系,Flutter 让然也知道这个问题,那么我们就来看看它有哪些相关的方法可以使用。
不用多说,我们还是来先看源码。
源码中说到 ListView 有4中设置子元素的方式:
第一种 List<Widget> 就不用多说了,我们常用的直接写在列表里的方式。另外的三种方式就需要我们编码去实现了。
需要编码的三个构造函数都拥有相同的属性这也是最常用的属性:
ListView.builder
首先还是要翻译一下源码里是怎么解释这个方法的:
使用了 indexedWidgetBuilder 它可以按需生成子元素,此构造函数适用于列表需要大量或者无限子元素生成,因为其调用了元素生成器,所以仅在实际可视范围中显示。
Ok,那我们就来看看代码是如何实现的。
当 itemCount 设置为 null 时就可以实现无限下拉列表。少侠小伙伴们可以在代码中尝试修改一下看看效果。
ListView.separated
首先还是要翻译一下源码里是怎么解释这方法的:
使用了两个 indexedWidgetBuilder 来处理子元素,itembuilder 是按需生成子元素,separatorbuilder 是根据子元素来生成子元素之间的分隔符元素。此构造函数只能适用于子级数量确定的列表视图。
Ok,那我们就来看看代码是如何实现的。
其实 separated 和 builder 差别并不大,这里我只做了简单的修改就实现了分割线。
ListView.custom
没错还是要翻译一下源码里是怎么解释这方法的:
构造函数接受一个 sliverChildDelegate,它提供自定义子模型其他方面的功能。例如:sliverchildDelegate 可以控制用于估计实际不可见子级大小的算法。
ListView.custom 要实现起来的话较为麻烦,但还是可以简单实现一下。
主要实现方式有 SliverChildListDelegate 列表方式 和 SliverChildBuilderDelegate 编码方式。
最终效果的话,少侠小伙伴们,可以自己更新修改代码尝试哟。
配合文章一同食用的代码已同步更新到 Github 地址:
https://github.com/linxsbox/myapp.git
结语
ListView Widget 的内容其实并不难,列表的使用都有对应的场景,只要熟悉了列表的渲染特征后,碰见相应的场景自然就不用纠结到底使用哪一个更合适了。其中的难点还是在于 ListView.custom 的实现上,他需要你自己去实现列表相关的所有东西:监听滚动、渲染子元素的方式、销毁子元素等等。
最后总结
参考来源:
《Flutter实战》: https://book.flutterchina.club/chapter6/scroll_controller.html Flutter 官网 API: https://api.flutter.dev/flutter/widgets/ScrollView/controller.html
相关文章
感谢大家的喜欢!
欢迎 关注、留言、分享、转发、在看。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。