flutter widget: ListView

ListView 是一个线性布局的widgets 列表.
ListView -extends->BoxScrollView -extends->ScrollView -extends->StatelessWidget

ListView是最常用的滑动组件。它在滚动方向上一个接一个地显示它的孩子。在交叉轴中,需要孩子填充ListView。

如果子控件非空,使用 itemExtent强制指定子控件高度范围。通过itemExtent设置值,比子控件自己决定范围更高效,因为滚动机制可以通过设置的预设的itemExtent来节约工作,比如在滚动位置急剧变化的时候。

在构建ListView时有4中选择:
  1. 利用显示的自列表来构造List<Widget>。此构造函数适合于具有少量子元素的列表视图,因为构造列表需要为可能显示在列表视图中的每个子元素执行工作,而不仅仅是那些实际可见的子元素。
  2. ListView.builder利用IndexedWidgetBuilder来按需构造。这个构造函数适合于具有大量(或无限)子视图的列表视图,因为构建器只对那些实际可见的子视图调用。
  3. 使用ListView.separated构造函数,采用两个IndexedWidgetBuilder:itemBuilder根据需要构建子项separatorBuilder类似地构建出现在子项之间的分隔符子项。此构造函数适用于具有固定数量的子控件的列表视图。
  4. 使用ListView.customSliverChildDelegate构造,它提供了定制子模型的其他方面的能力。 例如,SliverChildDelegate可以控制用于估计实际上不可见的孩子的大小的算法。

控制滚动的初始offset,可以通过设置ScrollController.initialScrollOffset属性。

默认情况下,ListView将自动填充列表的可滚动的末端,以避免MediaQuery的填充所指示的部分阻塞。若要避免此行为,请重写可以空的padding属性。

ListView.builder demo
body: new ListView.builder(
        padding: new EdgeInsets.all(5.0),
        itemExtent: 50.0,
        itemBuilder: (BuildContext context,int index){
          return new Text("text $index");
        },
      ),

《flutter widget: ListView》 image.png

这里的listView 可以无限往下滑动;)

ListView.separated demo
   body: new ListView.separated(
          itemBuilder: (BuildContext context, int index) {
            return new Text("text $index");
          },
          separatorBuilder: (BuildContext context, int index) {
            return new Container(height: 1.0, color: Colors.red);
          },
          itemCount: 40),

《flutter widget: ListView》 image.png

子结点的生命周期
1.创建

在布局列表时,可见的子元素、状态和呈现对象将基于现有控件(例如当使用默认构造函数时)或延迟提供的控件(例如当使用ListView.builder构造函数时)延迟地创建。

2.销毁

当从视图滑出时,关联的元素子树、状态和呈现对象将被销毁。当向后滚动时,位于列表中相同位置的新子节点将与新元素、状态和呈现对象一起延迟地重新创建。

3.销毁时的数据保存

为了保存子元素在视图中滚动和退出视图时的状态,可以做以下选择:
1> 将与UI状态驱动无关的业务逻辑从列表子子树中移出。例如,如果一个列表包含来自高速缓存的网络响应的带有上投票数的帖子,那么将帖子列表和上投票数存储在列表外部的数据模型中。让列表子UI子树很容易从真实模型对象的源中重新创建。使用子控件子树中的StatefulWidget只存储瞬时UI状态。
2>KeepAlive作为需要保存的列表子控件子树的root结点。KeepAlive使得孩子子树的顶部结点渲染对象的子结点保持存活。当关联的顶部渲染对象滚动到视图之外时,列表将子对象的渲染对象(以及通过扩展,其关联的元素和状态)保存在高速缓存列表中,而不是销毁它们。当滚动回到视图中时,渲染对象将按照当前现状被重新绘制(如果在中间阶段没有被标记为脏)。

这只在addAutomaticKeepAlivesaddRepaintBoundaries为false的情况下有效,因为这些参数导致ListView将每个子小部件子树与其他小部件包装在一起。
3> 使用AutomaticKeepAlive控件(当addautomatickeepalives设置为ture的时候默认会插入)。而不是向KeepAlive一样,当滑出屏幕的无条件的缓存孩子的子树,AutomaticKeepAlive可以让子树的派生的逻辑控制是否需要缓存该子树。

例如,EditableText 会在它有输入焦点时发送子结点子树以便保持存活状态。 如果它没有焦点,并且没有其他派生类通过KeepAliveNotification发出保持活动的信号,则滚动选择时将清除列表子元素子树。
AutomaticKeepAlive派生类通常使用AutomaticKeepAliveClientMixin发信号通知它保持活动状态,然后实现wantKeepAlive getter并调用updateKeepAlive

换到CustomScrollView

ListView基本上是一个CustomScrollView,在CustomScrollView.slivers属性中仅仅有一个SliverList。
如果ListView不满足需求,例如因为滚动视图既有列表又有网格,或者因为列表要与SliverAppBar等组合在一起,所以直接将代码从使用ListView移植到使用 CustomScrollView直接。

ListView上的key,scrollDirection,reverse,controller,primary,physics和shrinkWrap属性直接映射到CustomScrollView上具有相同名称的属性。

CustomScrollView.slivers属性应该是包含SliverList或SliverFixedExtentList的列表; 如果是前者,ListView上的itemExtent为null,如果是后者itemExtent不为null。

ListView上的childrenDelegate属性对应于SliverList.delegate(或SliverFixedExtentList.delegate)属性。 新的ListView构造函数的children参数对应于childrenDelegate是具有相同参数的SliverChildListDelegate。 新的ListView.builder构造函数的itemBuilder和childCount参数对应于childrenDelegate是一个带有匹配参数的SliverChildBuilderDelegate。

padding属性对应于在CustomScrollView.slivers属性中具有SliverPadding而不是列表本身,并且使SliverList成为SliverPadding的子级。

CustomScrollViews不会自动避免像ListView这样的MediaQuery障碍。 要重现该行为,请将slivers包裹在SliverSafeAreas中。

将代码移植到使用CustomScrollView后,可以将其他slivers(例如SliverGrid或SliverAppBar)放入CustomScrollView.slivers列表中。

demo

body: new ListView(
        shrinkWrap: true,
        padding: const EdgeInsets.all(20.0),
        children: <Widget>[
          const Text('I\'m dedicating every day to you'),
          const Text('Domestic life was never quite my style'),
          const Text('When you smile, you knock me out, I fall apart'),
          const Text('And I thought I was so smart'),
        ],
      ),

《flutter widget: ListView》 image.png

 body: new CustomScrollView(
        shrinkWrap: true,
        slivers: <Widget>[
          new SliverPadding(
            padding: const EdgeInsets.all(20.0),
            sliver: new SliverList(
                delegate: new SliverChildListDelegate(<Widget>[
                  const Text('I\'m dedicating every day to you'),
                  const Text('Domestic life was never quite my style'),
                  const Text('When you smile, you knock me out, I fall apart'),
                  const Text('And I thought I was so smart'),
                  const Text('I\'m dedicating every day to you'),
                  const Text('Domestic life was never quite my style'),
                  const Text('When you smile, you knock me out, I fall apart'),
                  const Text('And I thought I was so smart'),
                ])),
          )
        ],
      ),

《flutter widget: ListView》 image.png

    原文作者:浩林Leon
    原文地址: https://www.jianshu.com/p/9830b1a6ae1f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞