06 多子元素滑动布局
滑动布局作为 “多子元素布局” 的另一个分支,如 ListView 、GridView、Pageview ,它们在实现上要复杂的多,从下图一个的流程上我们大致可以知道它们的关系:
由上图我们可以知道,流程最终回产生两个 RenderObject :
RenderSliver:Base class for the render objects that implement scroll effects in viewports.RenderViewport:A render object that is bigger on the inside.
/// [RenderViewport] cannot contain [RenderBox] children directly. Instead, use
/// a [RenderSliverList], [RenderSliverFixedExtentList], [RenderSliverGrid], or
/// a [RenderSliverToBoxAdapter], for example.并且从 RenderViewport的说明我们知道,RenderViewport内部是不能直接放置 RenderBox,需要通过 RenderSliver 大家族来完成布局。而从源码可知:RenderViewport对应的 Widget Viewport 就是一个 MultiChildRenderObjectWidget。 (你看,又回到 MultiChildRenderObjectWidget了吧。)
再稍微说下上图的流程:
ListView、Pageview、GridView等都是通过Scrollable、ViewPort、Sliver大家族实现的效果。这里简单不规范描述就是:一个“可滑动”的控件,嵌套了一个“视觉窗口”,然后内部通过“碎片”展示 children 。- 不同的是
PageView没有继承SrollView,而是直接通过NotificationListener和ScrollNotification嵌套实现。
注意
TabBarView内部就是:NotificationListener+PageView
是不是觉得少了什么?哈哈哈,有的有的,官方同样提供了解决“?疼”的自定义滑动 CustomScrollView,它继承了 ScrollView,可通过 slivers 参数实现布局,这些 slivers 最终回通过 Scrollable 的 buildViewport 添加到 ViewPort 中,如下代码所示:
CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
pinned: true,
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Demo'),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 20,
),
),
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 9)],
child: Text('list item $index'),
);
},
),
),
],
)
学员评价