美文网首页Flutter
Flutter可滚动Widgets-ListView

Flutter可滚动Widgets-ListView

作者: Yuzo | 来源:发表于2019-05-13 11:43 被阅读11次

    个人博客

    ListView

    先看下如下截图

    enter image description here
    以上效果图的代码,是从flutter官方demoflutter_gallery内copy的部分代码。
    首先,首先定义一个列表,代码如下
    List<String> items = <String>[
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
    ];
    

    然后,通过上面的定义的列表数据,现在构建ListView的子Widget数据,代码如下

    Iterable<Widget> listTiles = items
        .map<Widget>((String item) => buildListTile(context, item));
    
    Widget buildListTile(BuildContext context, String item) {
        Widget secondary = const Text(
          'Even more additional list item information appears on line three.',
        );
        return ListTile(
          isThreeLine: true,
          leading: ExcludeSemantics(child: CircleAvatar(child: Text(item))),
          title: Text('This item represents $item.'),
          subtitle: secondary,
          trailing: Icon(Icons.info, color: Theme.of(context).disabledColor),
        );
    }
    

    最后,将生成的子Widget数据填充到ListView内,代码如下

    ListView(
        children: listTiles.toList(),
    )
    

    以上代码,就能完成最上面截图的效果。下面主要对ListTile做一下介绍

    ListTile

    ListTileFlutter给我们准备好的widget提供非常常见的构造和定义方式,包括文字,icon,点击事件,一般是能够满足基本列表需求。

    构造函数

    ListTile({
        Key key,
        this.leading,
        this.title,
        this.subtitle,
        this.trailing,
        this.isThreeLine = false,
        this.dense,
        this.contentPadding,
        this.enabled = true,
        this.onTap,
        this.onLongPress,
        this.selected = false,
     })
    

    属性

    enter image description here

    使用

    ListTile(
        //展示三行
        isThreeLine: true,
        //前置图标
        leading: ExcludeSemantics(child: CircleAvatar(child: Text(item))),
        //标题
        title: Text('This item represents $item.'),
        //副标题
        subtitle: secondary,
        //后置图标
        trailing: Icon(Icons.info, color: Theme.of(context).disabledColor),
    )
    

    效果

    enter image description here

    ListView.builder

    ListView.builder适合列表项比较多(或者无限)的情况,因为只有当子Widget真正显示的时候才会被创建。
    将上面列表填充的代码修改为ListView.builder,代码如下所示

    ListView.builder(
        itemCount: items.length,
        itemBuilder: (BuildContext context, int index) {
            return buildListTile(context, items[index]);
    })
    

    运行结果如下图所示


    enter image description here

    ListView.separated

    ListView.separated可以生成列表项之间的分割器,它比ListView.builder多了一个separatorBuilder参数,该参数是一个分割器生成器。
    将上面列表填充的代码修改为ListView.separated,代码如下所示

    ListView.separated(
        itemBuilder: (BuildContext context, int index) {
            return buildListTile(context, items[index]);
        },
        separatorBuilder: (BuildContext context, int index) {
            return index % 2 == 0 ? divider1 : divider2;
        },
        itemCount: items.length
    )
    

    运行结果如下图所示


    enter image description here

    实例:Listview下拉刷新 上拉加载更多

    下面实现首次进入页面,加载数据,下拉能刷新页面数据,上拉能加载更多数据。

    下拉刷新

    下拉刷新,用到的是Flutter自带的RefreshIndicatorWidget,ListView主要用ListView.builder进行实现。代码如下所示

    RefreshIndicator(
        key: refreshIndicatorKey,
        child: ListView.builder(
            itemCount: list.length,
            itemBuilder: (context, index) {
                return buildListTile(context, list[index]);
            },
        ),
        onRefresh: onRefresh)
    

    实现下拉刷新,主要需要实现RefreshIndicatoronRefresh属性,代码如下所示

    Future<Null> onRefresh() async {
        return Future.delayed(Duration(seconds: 2)).then((e) {
          list.addAll(items);
          setState(() {
            //重新构建列表
          });
        });
    }
    

    主要实现延迟2s加载数据,在重新刷新列表。
    首次进入页面,Loading状态的实现实现如下面代码所示

    void showRefreshLoading() async {
        await Future.delayed(const Duration(seconds: 0), () {
          refreshIndicatorKey.currentState.show().then((e) {});
          return true;
        });
    }
    

    Loading完之后会触发RefreshIndicatoronRefresh属性,到此,下拉刷新已经实现完毕。
    运行效果如下图所示

    enter image description here

    上拉加载更多

    上拉加载需要监听ListView的滚动事件,当滚动事件与底部小于50并且有更多数据加载时,才会触发加载更多的逻辑,如下面代码所示

    scrollController.addListener(() {
        var position = scrollController.position;
        // 小于50px时,触发上拉加载;
        if (position.maxScrollExtent - position.pixels < 50 &&
            !isNoMore) {
            loadMore();
        }
    });
    
    void loadMore() async {
        if (!isLoading) {
          //刷新加载状态
          isLoading = true;
          setState(() {});
    
          Future.delayed(Duration(seconds: 2)).then((e) {
            list.addAll(items);
            //取消加载状态,并提示暂无更多数据
            isLoading = false;
            isNoMore = true;
            setState(() {
              //重新构建列表
            });
          });
        }
    }
    

    视图层的代码,当需要处理加载更多的逻辑时,ListViewitemCount属性需要进行加1,用来填充加载更多的视图。如下面代码所示

    int getListItemCount() {
        int count = list.length;
        if (isLoading || isNoMore) {
          count += 1;
        }
        return count;
    }
    

    ListViewitemBuilder属性,加载更多的视图代码如下所示

    Widget builderMore() {
        return Center(
          child: Padding(
            padding: EdgeInsets.all(10.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                isNoMore
                    ? Text("")
                    : SizedBox(
                        width: 20.0,
                        height: 20.0,
                        child: CircularProgressIndicator(
                            strokeWidth: 4.0,
                            valueColor: AlwaysStoppedAnimation(Colors.black)),
                      ),
                Padding(
                  padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 15.0),
                  child: Text(
                    isNoMore ? "没有更多数据" : "加载中...",
                    style: TextStyle(fontSize: 16.0),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    

    RefreshIndicator代码做如下修改

    RefreshIndicator(
        key: refreshIndicatorKey,
        child: ListView.builder(
            controller: scrollController,
            itemCount: getListItemCount(),
            itemBuilder: (context, index) {
                  return builderItem(context, index);
            },
        ),
        onRefresh: onRefresh)
              
    Widget builderItem(BuildContext context, int index) {
        if (index < list.length) {
          return buildListTile(context, list[index]);
        }
        return builderMore();
    }
    

    运行代码
    加载中的效果如下图所示


    enter image description here

    没有更多数据的效果如下图所示


    enter image description here

    相关文章

      网友评论

        本文标题:Flutter可滚动Widgets-ListView

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