美文网首页
Flutter 小部件ListView

Flutter 小部件ListView

作者: 程序员阿兵 | 来源:发表于2020-10-21 21:43 被阅读0次

    文章目录

    Flutter ListView

    列表布局在手机上是最最常用的控件了。
    Android上的RecycleView尤其的强大。

    Flutter中也给我们提供了ListView,不过就目前的体验来看,性能跟原生的ListView或RecycleView比还是有一点差距的。滑动起来还是略卡。

    下面我们来看一下ListView的相关知识

    继承关系

    image.png

    可以看到,ListView和GridView都继承自BoxScrollView,因此,他们的属性差不多,用法也相似。

    构造方法

     ListView({
        Key key,
        Axis scrollDirection = Axis.vertical,
        bool reverse = false,
        ScrollController controller,
        bool primary,
        ScrollPhysics physics,
        bool shrinkWrap = false,
        EdgeInsetsGeometry padding,
        this.itemExtent,
        bool addAutomaticKeepAlives = true,
        bool addRepaintBoundaries = true,
        bool addSemanticIndexes = true,
        double cacheExtent,
        List<Widget> children = const <Widget>[],
        int semanticChildCount,
        DragStartBehavior dragStartBehavior = DragStartBehavior.down,
      })
    

    常用属性

    属性 值类型 说明
    scrollDirection Axis 设置滚动的方向,horizontal(水平)或vertical(垂直)
    reverse bool 是否翻转
    itemExtent double 滚动方向子控件的长度,垂直方向即为高度,水平方向即为宽度
    controller ScrollController 用来控制滚动位置及监听滚动事件
    shrinkWrap bool 是否根据子widget的总长度来设置ListView的长度
    padding EdgeInsetsGeometry 间距
    children List 子控件

    常用属性都比较简单,没啥好说的,我们来直接用一下

    ListView(
          children: List.generate(30, (index) {
            return Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.red),
              ),
              child: Text("item${index}"),
            );
          }),
        );
    

    效果图:


    list.gif

    这里我们要注意一下itemExtent属性
    itemExtent
    该属性用来控制子控件在滚动方向上的长度,所以它跟scrollDirection是密切相关的。
    例如:
    当滚动方向为垂直方向时,那么itemExtent就是控制子控件的高度
    当滚动方向为水平方向时,那么itemExtent就是控制子控件的宽度

    示例:我们在垂直方向上设置一下itemExtent

    ListView(
          scrollDirection: Axis.vertical,
          itemExtent: 60,
          children: List.generate(50, (index) {
            return Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.red),
              ),
              child: Text("item${index}"),
            );
          }),
        );
    

    图示如下:此时,itemExtent控制的是子控件的高度


    list2.gif

    我们更改一下滚动方向为水平:

    ListView(
          scrollDirection: Axis.horizontal,
          itemExtent: 60,
          children: List.generate(50, (index) {
            return Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.red),
              ),
              child: Text("item${index}"),
            );
          }),
        );
    

    此时,itemExtent控制的就是子控件的宽度了

    图示: list3.gif

    Flutter ListView加载更多/异步加载(ListView.builder)

    构造方法适合在数据较少且固定的情况下使用,我们在开发过程中一般数据都是从网络获取的,并且基本都有分页的需求,此时,我们就需要动态的加载数据了。
    跟GridView一样,ListView提供了ListView.builder方法供我们动态加载数据时使用,且使用方法基本一致。
    首先看看源码:

     ListView.builder({
        Key key,
        Axis scrollDirection = Axis.vertical,
        bool reverse = false,
        ScrollController controller,
        bool primary,
        ScrollPhysics physics,
        bool shrinkWrap = false,
        EdgeInsetsGeometry padding,
        this.itemExtent,
        @required IndexedWidgetBuilder itemBuilder,
        int itemCount,
        bool addAutomaticKeepAlives = true,
        bool addRepaintBoundaries = true,
        bool addSemanticIndexes = true,
        double cacheExtent,
        int semanticChildCount,
        DragStartBehavior dragStartBehavior = DragStartBehavior.down,
      })
    

    属性跟构造方法中的属性差不多,我们主要来看看itemCount和itemBuilder

    • itemCount表示列表的数量,一般都是集合的长度
    • itemBuilder是列表项构造器,返回一个Widget

    这里我就直接用了

    import 'package:flutter/material.dart';
    
    /*
    * 列表控件
    *
    * */
    class ListViewWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ListView(
          scrollDirection: Axis.horizontal,
          itemExtent: 60,
          children: List.generate(50, (index) {
            return Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.red),
              ),
              child: Text("item${index}"),
            );
          }),
        );
      }
    }
    
    class ListViewBuilder extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _ListViewBuilder();
      }
    }
    
    class _ListViewBuilder extends State<ListViewBuilder> {
      
      /*初始项为50个*/
      List<int> indexs = List.generate(50, (index) {
        return index;
      });
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
            itemCount: indexs.length,
            itemBuilder: (context, index) {
              
              /*加载到底部时且集合数量小于100的话,获取更多数据*/
              if (index==indexs.length-1&&indexs.length < 100) {
                _getMoreData(index);
              }
    
              return Text("${index}");
            });
      }
    
      void _getMoreData(int index) {
        Future.delayed(Duration(milliseconds: 300)).then((e) {
          setState(() {
            /*往集合里添加10条数据*/
            indexs.addAll(List.generate(10, (i) {
              return index + i;
            }));
          });
        });
      }
    }
    

    Flutter ListView分割线(ListView.separated)

    通常情况下,我们的列表之间都有分割线,便于用户区分,我们既可以在子控件中手动添加分割线的样式,例如一开始的构造方法那样,但是那样会造成分割线重叠的情况。
    而ListView.separated可以让我们方便的给列表加上分割线。
    我们先来看一下源码:

     ListView.separated({
        Key key,
        Axis scrollDirection = Axis.vertical,
        bool reverse = false,
        ScrollController controller,
        bool primary,
        ScrollPhysics physics,
        bool shrinkWrap = false,
        EdgeInsetsGeometry padding,
        @required IndexedWidgetBuilder itemBuilder,
        @required IndexedWidgetBuilder separatorBuilder, //分割线
        @required int itemCount,
        bool addAutomaticKeepAlives = true,
        bool addRepaintBoundaries = true,
        bool addSemanticIndexes = true,
        double cacheExtent,
      })
    

    可以看到属性中多了一个separatorBuilder

    separatorBuilder即为分割线构建器

    下面我们给上面的列表加上灰色分割线:

    import 'package:flutter/material.dart';
    
    /*
    * 列表控件
    *
    * */
    class ListViewWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ListView(
          scrollDirection: Axis.horizontal,
          itemExtent: 60,
          children: List.generate(50, (index) {
            return Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.red),
              ),
              child: Text("item${index}"),
            );
          }),
        );
      }
    }
    
    class ListViewBuilder extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _ListViewBuilder();
      }
    }
    
    class _ListViewBuilder extends State<ListViewBuilder> {
      /*初始项为50个*/
      List<int> indexs = List.generate(50, (index) {
        return index;
      });
    
      @override
      Widget build(BuildContext context) {
        /*灰色分割线*/
        var divider = Divider(
          color: Colors.grey,
        );
    
        return ListView.separated(
            padding: EdgeInsets.all(10),
            itemCount: indexs.length,
            separatorBuilder: (context, index) {
              return divider;
            },
            itemBuilder: (context, index) {
              /*加载到底部时且集合数量小于100的话,获取更多数据*/
              if (index == indexs.length - 1 && indexs.length < 100) {
                _getMoreData(index);
              }
    
              return Text("${index}");
            });
      }
    
      void _getMoreData(int index) {
        Future.delayed(Duration(milliseconds: 300)).then((e) {
          setState(() {
            /*往集合里添加10条数据*/
            indexs.addAll(List.generate(10, (i) {
              return index + i;
            }));
          });
        });
      }
    }
    
    
    list5.gif

    好了 Flutter ListView的基本用法大概就是这样

    相关文章

      网友评论

          本文标题:Flutter 小部件ListView

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