Flutter 开发实战

235课时
1K学过
8分

课程评价 (0)

请对课程作出评价:
0/300

学员评价

暂无精选评价
3分钟

06 多子元素滑动布局

滑动布局作为 “多子元素布局” 的另一个分支,如 ListViewGridViewPageview ,它们在实现上要复杂的多,从下图一个的流程上我们大致可以知道它们的关系:

img

由上图我们可以知道,流程最终回产生两个 RenderObject

  • RenderSliverBase class for the render objects that implement scroll effects in viewports.
  • RenderViewportA 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了吧。)

再稍微说下上图的流程:

  • ListViewPageviewGridView 等都是通过 ScrollableViewPortSliver大家族实现的效果。这里简单不规范描述就是:一个“可滑动”的控件,嵌套了一个“视觉窗口”,然后内部通过“碎片”展示 children
  • 不同的是 PageView 没有继承 SrollView,而是直接通过 NotificationListenerScrollNotification 嵌套实现。

注意 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'),
          );
        },
      ),
    ),
  ],
)