flutter widget: ListView

作者: 浩林Leon | 来源:发表于2018-10-08 23:29 被阅读23次

    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");
            },
          ),
    
    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),
    
    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'),
            ],
          ),
    
    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'),
                    ])),
              )
            ],
          ),
    
    image.png

    相关文章

      网友评论

        本文标题:flutter widget: ListView

        本文链接:https://www.haomeiwen.com/subject/tkplaftx.html