目录正文Scrollable主轴和纵轴ViewportSliver可滚动组件的通用配置ScrollController子节点缓存Scrollbar总结正文 当内容超过显示视口(Vie
当内容超过显示视口(ViewPort)时,如果没有特殊处理,Flutter则会提示Overflow错误。为此,Flutter提供了多种可滚动widget(Scrollable Widget)用于显示列表和长布局。
Flutter中有两种布局模型:
通常可滚动组件的子组件可能会非常多、占用的总高度也会非常大;如果要一次性将子组件全部构建出将会非常昂贵!为此,Flutter中提出一个Sliver(中文为“薄片”的意思)概念,Sliver 可以包含一个或多个子组件。Sliver 的主要作用是配合:加载子组件并确定每一个子组件的布局和绘制信息,如果 Sliver 可以包含多个子组件时,通常会实现按需加载模型。
只有当Sliver
出现在视口中时才会去构建它,这种模型也称为“基于Sliver的列表按需加载模型”。可滚动组件中有很多都支持基于Sliver的按需加载模型,如ListView
、GridView
,但是也有不支持该模型的,如SingleChildScrollView
。
Flutter 中的可滚动主要由三个角色组成:Scrollable、Viewport 和 Sliver:
具体布局过程:
比如有一个 ListView,大小撑满屏幕,假设它有 100 个列表项(都是RenderBox)且每个列表项高度相同,结构如下:
图中白色区域为设备屏幕,也是 Scrollable 、 Viewport 和 Sliver 所占用的空间,三者所占用的空间重合,父子关系为:Sliver 父组件为 Viewport,Viewport的 父组件为 Scrollable 。注意ListView 中只有一个 Sliver,在 Sliver 中实现了子组件的按需加载。
其中顶部和底部灰色的区域为 cacheExtent,它表示预渲染的高度,需要注意这是在可视区域之外,如果 RenderBox 进入这个区域内,即使它还未显示在屏幕上,也是要先进行构建的,预渲染是为了后面进入 Viewport 的时候更丝滑。cacheExtent 的默认值是 250,在构建可滚动列表时我们可以指定这个值,这个值最终会传给 Viewport。
用于处理滑动手势,确定滑动偏移,滑动偏移变化时构建 Viewport,我们看一下其关键的属性:
Scrollable({
...
this.axisDirection = AxisDirection.down,
this.controller,
this.physics,
required this.viewportBuilder, //后面介绍
})
AlwaysScrollableScrollPhysics:总是可以滑动
NeverScrollableScrollPhysics:禁止滚动
BouncingScrollPhysics :内容超过一屏 上拉有回弹效果
ClampingScrollPhysics :包裹内容 不会有回弹
在可滚动组件的坐标描述中,通常将滚动方向称为主轴,非滚动方向称为纵轴。由于可滚动组件的默认方向一般都是沿垂直方向,所以默认情况下主轴就是指垂直方向,水平方向同理。
Viewport 比较简单,用于渲染当前视口中需要显示 Sliver。
Viewport({
Key? key,
this.axisDirection = AxisDirection.down,
this.crossAxisDirection,
this.anchor = 0.0,
required ViewportOffset offset, // 用户的滚动偏移
// 类型为Key,表示从什么地方开始绘制,默认是第一个元素
this.center,
this.cacheExtent, // 预渲染区域
//该参数用于配合解释cacheExtent的含义,也可以为主轴长度的乘数
this.cacheExtentStyle = CacheExtentStyle.pixel,
this.clipBehavior = Clip.hardEdge,
List<Widget> slivers = const <Widget>[], // 需要显示的 Sliver 列表
})
需要注意的是:
Sliver 主要作用是对子组件进行构建和布局,比如 ListView 的 Sliver 需要实现子组件(列表项)按需加载功能,只有当列表项进入预渲染区域时才会去对它进行构建和布局、渲染。
Sliver 对应的渲染对象类型是 RenderSliver,RenderSliver 和 RenderBox 的相同点是都继承自 RenderObject 类,不同点是在布局的时候约束信息不同。RenderBox 在布局时父组件传递给它的约束信息对应的是 BoxConstraints,只包含最大宽高的约束;而 RenderSliver 在布局时父组件(列表)传递给它的约束是对应的是 SliverConstraints。
几乎所有的可滚动组件在构造时都能指定 scrollDirection(滑动的主轴)、reverse(滑动方向是否反向)、controller、physics 、cacheExtent ,这些属性最终会透传给对应的 Scrollable 和 Viewport,这些属性我们可以认为是可滚动组件的通用属性.
reverse
表示是否按照阅读方向相反的方向滑动,如:scrollDirection
值为Axis.horizontal
时,即滑动发现为水平,如果阅读方向是从左到右。
reverse
为true
时,那么滑动方向就是从右往左。
可滚动组件都有一个 controller 属性,通过该属性我们可以指定一个 ScrollController 来控制可滚动组件的滚动,比如可以通过ScrollController来同步多个组件的滑动联动。
按需加载子组件在大多数场景中都能有正收益,但是有些时候也会有副作用。比如有一个页面,它由一个ListView 组成,我们希望在页面顶部显示一块内容, 这部分内容的数据需要在每次页面打开时通过网络来获取,为此我们通一个 Header 组件来实现,它是一个 StatefulWidget ,会在initState 中请求网络数据,然后将它作为 ListView 的第一个孩子。现在问题来了,因为 ListView 是按需加载子节点的,这意味着如果 Header 滑出 Viewport 的预渲染区域之外时就会被销毁,重新滑入后又会被重新构建,这样就会发起多次网络请求,不符合我们期望。
为了解决上述问题,可滚动组件提供了一种缓存子节点的通用解决方案,它允许开发者对特定的子界限进行缓存.
Scrollbar
是一个Material风格的滚动指示器(滚动条),如果要给可滚动组件添加滚动条,只需将Scrollbar
作为可滚动组件的任意一个父级组件即可,如:
Scrollbar(
child: SingleChildScrollView(
...
),
);
Scrollbar
和CupertinoScrollbar
都是通过监听滚动通知来确定滚动条位置的。
CupertinoScrollbar
CupertinoScrollbar
是 iOS 风格的滚动条,如果你使用的是Scrollbar
,那么在iOS平台它会自动切换为CupertinoScrollbar
。
本篇介绍了可滚动组件的概念和具体的组成,构造。后续会具体介绍一些可滚动组件的使用详解。如ListView,GridView等,更多关于Flutter 可滚动组件的资料请关注编程网其它相关文章!
--结束END--
本文标题: Flutter之可滚动组件实例详解
本文链接: https://www.lsjlt.com/news/170498.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-01-21
2023-10-28
2023-10-28
2023-10-27
2023-10-27
2023-10-27
2023-10-27
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0