Flutter 列表控件ListView

Flutter ListView

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

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

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

继承关系
在这里插入图片描述

可以看到,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,
  })

常用属性

属性值类型说明
scrollDirectionAxis设置滚动的方向,horizontal(水平)或vertical(垂直)
reversebool是否翻转
itemExtentdouble滚动方向子控件的长度,垂直方向即为高度,水平方向即为宽度
controllerScrollController用来控制滚动位置及监听滚动事件
shrinkWrapbool是否根据子widget的总长度来设置ListView的长度
paddingEdgeInsetsGeometry间距
childrenList子控件

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

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

效果图:
在这里插入图片描述

这里我们要注意一下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控制的是子控件的高度
在这里插入图片描述

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

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控制的就是子控件的宽度了
图示:
在这里插入图片描述

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,
  })

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

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;
        }));
      });
    });
  }
}

图示:
初始值集合中只有50条数据,然后每次增加10条
在这里插入图片描述

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;
        }));
      });
    });
  }
}

在这里插入图片描述

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


如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可。也可以关注我的 Flutter 博客专栏,我会不定期的更新,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喻志强(Xeon)

码字不易,鼓励随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值