十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
ListView的基础创建使用有三种方式:
目前创新互联建站已为超过千家的企业提供了网站建设、域名、网页空间、网站托管运营、企业网站设计、武义网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
通过默认构造函数来创建列表,应用场景 = 短列表
这种方式创建的列表存在一个问题:对于那些长列表或者需要较昂贵渲染开销的子组件,即使还没有出现在屏幕中但仍然会被ListView所创建,这将是一项较大的开销,使用不当可能引起性能问题甚至卡顿。
长列表
列表子项之间需要分割线
ListView的进阶使用主要包括:下拉刷新 上拉加载
在Flutter中,ListView结合RefreshIndicator组件实现下拉刷新
通过包裹一层RefreshIndicator,自定义onRefresh回调方法实现
方式有两种:
通过ListView.controller属性可以判断ListView是否滑动到了底部,再进行上拉加载
NotificationListener是一个Widget,可监听子Widget发出的Notification
ListView在滑动时中会发出ScrollNotification类型的通知,可通过监听该通知得到ListView的滑动状态,判断是否滑动到了底部,从而进行上拉加载
NotificationListener有一个onNotification属性,定义了监听的回调方法,通过它来处理加载更多逻辑
不定期分享关于 安卓开发 的干货,追求 短、平、快 ,但 却不缺深度 。
要实现上面的效果,每个种类的标签横向滚动,实现的方式,最外层的大分类标签一个ListView,每个分类的标签也是ListView 设置横向滚动结合Wrap组件就能实现。
基本和AppBar一样,只是他只能在CustomScrollView中使用,应该很常见,滑动的时候固定appbar,就需要用到他.
大部分和appbar一样,主要说下重要的几个:
是否将导航栏部分固定在appbar的位置.这个需求在实际中很常用. 看看效果图.
当 pinned = false:
可以看到appbar并没有固定在最上面,而是根据内容划出了界面.
当 pinned = true :
这个应该是需求中经常用到的效果了.
当floating = false :
当floating = true:
仔细看 ,区别是在列表整体向下滑动时,appbar开始显示的位置不同.
当为false时 ,向下滑动时,会先降列表内容滑动顶部,然后appbar会跟着列表滑动显示出来.如上图
当为true时, 向下滑动时,appbar会先跟着列表滑动显示出来. 然后继续列表的滑动. 如上图
不能单独使用要配合 ****floating 和 ****pinned
具体效果看官网地址
是否展开,默认false,直接看值为true的效果图,就明白了.
可以再里面添加扩展的内容:
通过测试发现 **后面不是 FlexibleSpaceBar 的话, stretch = true 无效. **
和Padding一样.子控件是 sliver 类型...
上图中在padding中添加了一个背景色为青色的容器widget
里面可以设置不是 sliver 类型的widget。如上图中的 padding中添加的 container
就两个协议,一个是布局协议一个展示协议.基本和GridView一样.也有count和extext... 不设置个数默认无数个
SliverChildListDelegate 这种方式前提是知道cell个数,比较少,好搭建
SliverChildBuilderDelegate 这种方式,可以根据数组去创建,不知道cell个数
和listview差不多.也是协议 不设置个数默认无数个
这是领苗确认记录详情页需要展示给用户的内容,大家可以看到这个页面要承载很多的信息,要向下滚动一段很长的距离才能展示完,想要实现的效果是在页面的顶部有一个TabBar,用户可以通过点击TabBar进行锚点(jumpTo到指定位置),AppBar下的整个页面是可以自由滚动的,在滚动过程中AppBar始终固定在顶部,TabBar在第一次进入详情页的时候不显示,只有在向下滑动的时候会由透明渐变为不透明并固定在顶部,同时当页面滑动到TabBar锚点位置的时候TabBar会切换到对应的下标,也就是要实现TabBar和ScrollView联动的双向控制,Tabbar的切换可以控制页面的跳转,页面的滑动又可以反过来控制TabBar的切换,类似与京东、淘宝的商品详情页效果。
SliverAppBar基本已经达到了我们想要的效果,但在界面顶部会有块空白区域试了很多方法怎么都去不掉,最后看了SliverAppBar这个控件的源码发现是它自带的初始高度。
这个没法设置或消除,不可能直接去改源码,所以后来换了一种实现思路,舍弃了SliverAppBar这个控件,以Stack的形式将TabBar置于ScrollView之上也能达到我们想要的效果,那么问题来了,如何实现TabBar的滚动渐变?很容易想到Opacity透明度控件,通过滚动监听来控制TabBar透明度的改变,借助Notificaion可以完美实现我们的需求。
Notification是Flutter中一个重要的机制,在Widget树中,每一个节点都可以分发通知(Notification)与父(包括祖先)Widget通信,通知会沿着当前节点(context)向上传递,所有父节点都可以通过NotificationListener来监听自己关注的通知,Flutter中称这种通知由子向父的传递为“通知冒泡”(Notification Bubbling)。
Flutter中很多地方使用了通知,如可滚动(Scrollable) Widget中滑动时就会分发ScrollNotification,而Scrollbar正是通过监听ScrollNotification来确定滚动条位置的。除了ScrollNotification,Flutter中还有SizeChangedLayoutNotification、KeepAliveNotification 、LayoutChangedNotification等。
通过NotificationListener监听滚动事件和通过ScrollController有两个主要的不同:
通过改造后,目前这个组件的原型已经实现并且可以满足我们的需求,最后就是对该demo进行完善使其能够完美接入我们的业务,做到技术赋能业务。
在一个页面滚动区域不是很长的情况下不建议使用,只有当页面足够长的情况下使用这个组件效果会比较好,因为如果一个页面过短,点击TabBar最后一栏进行锚点时,页面最后一个子模块内容无法置顶,只会将页面最后的内容推到屏幕范围内,并且由于TabBar监听到的是滚动的位置,会导致TabBar无法切换到对应的下标,看上去会像个bug,其实是因为底部已经没有内容了。
这个组件本身并没有太大的技术难度,但是有一些比较细节的小逻辑得处理好,并且从中衍生出来的很多琐碎的小的知识点都可以进行拓展。 在组件开发的过程中遇到问题时不局限于控件本身的设计模式,转变开发思维去找寻一些比较新颖的解决方案可能会有意外的收获。同时技术不能脱离于业务,技术赋能业务才能创造价值。
SingleChildScrollView 源码定义如下:
需要注意的是, 通常 SingleChildScrollView 只应在期望的内容不会超过屏幕太多时使用 ,这是因为 SingleChildScrollView 不支持基于 Sliver 的延迟加载模型,所以如果预计视口可能包含超出屏幕尺寸太多的内容时,那么使用 SingleChildScrollView 将会非常昂贵(性能差),此时应该使用一些支持Sliver延迟加载的可滚动组件,如 ListView 。
示例1
下面是一个将大写字母 A-Z 沿垂直方向显示的例子,由于垂直方向空间会超过屏幕视口高度,所以我们使用SingleChildScrollView:
示例2
示例3 - 横向滚动
Flutter 中有两种布局模型:
基于 RenderBox 的盒模型布局。
基于 Sliver ( RenderSliver ) 按需加载列表布局。
通常可滚动组件的子组件可能会非常多、占用的总高度也会非常大;如果要一次性将子组件全部构建出将会非常昂贵!为此,Flutter中提出一个Sliver(中文为“薄片”的意思)概念,Sliver 可以包含一个或多个子组件。Sliver 的主要作用是配合:加载子组件并确定每一个子组件的布局和绘制信息,如果 Sliver 可以包含多个子组件时,通常会实现按需加载模型。
只有当 Sliver 出现在视口中时才会去构建它,这种模型也称为“基于Sliver的列表按需加载模型”。可滚动组件中有很多都支持基于Sliver的按需加载模型,如 ListView 、 GridView ,但是也有不支持该模型的,如 SingleChildScrollView 。
Flutter 中的可滚动主要由三个角色组成: Scrollable 、 Viewport 和 Sliver :
具体布局过程:
比如有一个 ListView,大小撑满屏幕,假设它有 100 个列表项(都是RenderBox)且每个列表项高度相同,结构如图6-1所示:
图中白色区域为设备屏幕,也是 Scrollable 、 Viewport 和 Sliver 所占用的空间,三者所占用的空间重合,父子关系为:Sliver 父组件为 Viewport,Viewport的 父组件为 Scrollable 。注意ListView 中只有一个 Sliver,在 Sliver 中实现了子组件的按需加载。
其中顶部和底部灰色的区域为 cacheExtent,它表示预渲染的高度,需要注意这是在可视区域之外,如果 RenderBox 进入这个区域内,即使它还未显示在屏幕上,也是要先进行构建的,预渲染是为了后面进入 Viewport 的时候更丝滑。cacheExtent 的默认值是 250,在构建可滚动列表时我们可以指定这个值,这个值最终会传给 Viewport。
用于处理滑动手势,确定滑动偏移,滑动偏移变化时构建 Viewport,我们看一下其关键的属性:
在可滚动组件的坐标描述中,通常将滚动方向称为主轴,非滚动方向称为纵轴。由于可滚动组件的默认方向一般都是沿垂直方向,所以默认情况下主轴就是指垂直方向,水平方向同理。
Viewport 比较简单,用于渲染当前视口中需要显示 Sliver。
需要注意的是:
Sliver 主要作用是对子组件进行构建和布局,比如 ListView 的 Sliver 需要实现子组件(列表项)按需加载功能,只有当列表项进入预渲染区域时才会去对它进行构建和布局、渲染。
Sliver 对应的渲染对象类型是 RenderSliver,RenderSliver 和 RenderBox 的相同点是都继承自 RenderObject 类,不同点是在布局的时候约束信息不同。RenderBox 在布局时父组件传递给它的约束信息对应的是 BoxConstraints ,只包含最大宽高的约束;而 RenderSliver 在布局时父组件(列表)传递给它的约束是对应的是 SliverConstraints 。关于 Sliver 的布局协议,我们将在本章最后一节中介绍。
几乎所有的可滚动组件在构造时都能指定 scrollDirection (滑动的主轴)、 reverse (滑动方向是否反向)、 controller 、 physics 、 cacheExtent ,这些属性最终会透传给对应的 Scrollable 和 Viewport,这些属性我们可以认为是可滚动组件的通用属性,后续再介绍具体的可滚动组件时将不再赘述。
可滚动组件都有一个 controller 属性,通过该属性我们可以指定一个 ScrollController 来控制可滚动组件的滚动,比如可以通过ScrollController来同步多个组件的滑动联动。由于 ScrollController 是需要结合可滚动组件一起工作,所以本章中,我们会在介绍完 ListView 后详细介绍 ScrollController。
Scrollbar是一个Material风格的滚动指示器(滚动条),如果要给可滚动组件添加滚动条,只需将Scrollbar作为可滚动组件的任意一个父级组件即可,如:
Scrollbar 和 CupertinoScrollbar 都是通过监听滚动通知来确定滚动条位置的。关于的滚动通知的详细内容我们将在本章最后一节中专门介绍。
CupertinoScrollbar是 iOS 风格的滚动条,如果你使用的是Scrollbar,那么在iOS平台它会自动切换为CupertinoScrollbar