Flutter 实现支持上拉加载和下拉刷新的 ListView

  Hello 大家好,最近在 flutter 中用到了列表展示数据,并且实现了上拉加载和下拉刷新,当时就想如何把他们抽象出来,形成一个 widget ,于是就有了下面这篇文章。

先看下效果图

  请忽略填充的内容[允悲]

具体实现

下拉刷新使用的是:RefreshIndicator,上拉加载是用的 ScrollController 的监听。代码如下:

import 'package:flutter/material.dart';

// ignore: must_be_immutable
class RecycleView<T> extends StatefulWidget {
  Function loadMore;
  Function refresh;
  List<T> lists;
  Function listBuilder;

  RecycleView(
      {Key key,
      @required this.lists,
      this.loadMore,
      this.refresh,
      this.listBuilder})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _Recycle();
}

class _Recycle extends State<RecycleView> {
  //下拉刷新触发距离
  static const double DISPLACEMENT = 40.0;

  //是否显示正在加载
  bool _showLoading = false;

  ScrollController _scrollController = ScrollController();

  @override
  void didUpdateWidget(RecycleView oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.lists == widget.lists && oldWidget.lists.isNotEmpty) {
      _showLoading = false;
    }
  }

  @override
  void initState() {
    super.initState();

    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        if (!_showLoading && widget.lists.isNotEmpty) {
          setState(() {
            _showLoading = true;
          });
          _loadMore();
        }
      }
    });
  }

  _refresh() {
    if (widget.refresh != null) {
      widget.refresh();
      setState(() {
        _showLoading = false;
      });
    }
  }

  _loadMore() {
    if (widget.loadMore != null) {
      widget.loadMore();
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    if (widget.lists == null || widget.lists.isEmpty) {
      return Container(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: Center(
          child: CircularProgressIndicator(),
        ),
      );
    } else {
      return RefreshIndicator(
        onRefresh: () async {
          await _refresh();
        },
        displacement: DISPLACEMENT,
        child: ListView.builder(
          itemCount: widget.lists.length + 1,
          itemBuilder: (context, index) {
            if (index == widget.lists.length) {
              return _showLoading ? _loadingWidget() : _noMoreWidget();
            } else {
              return widget.listBuilder(context, index);
              //return Text("3333$index");
            }
          },
          controller: _scrollController,
        ),
      );
    }
  }

  Widget _loadingWidget() {
    return Offstage(
        offstage: false,
        child: new Padding(
          padding: const EdgeInsets.all(8.0),
          child: new Center(
            child: new CircularProgressIndicator(),
          ),
        ));
  }

  Widget _noMoreWidget() {
    return Offstage(
        offstage: false,
        child: Center(
            child: Container(
                padding: EdgeInsets.only(top: 5, bottom: 5),
                child: Text("没有更多啦~"))));
  }
}

  ok ,这样就大体完成了。这里只起个抛砖引玉的作用,希望能给你提供些思路。


2月13日更新

  新增了itemCount属性,帮助自由构建子项,代码修改部分如下:

在这里插入图片描述
在这里插入图片描述
这样只需要传入不同的itemCount即可构建任意的子项了,如在以上的效果下新增轮播图。

return Scaffold(
          body: RecycleView<HomeArticleEntity>(
            lists: lists,
            loadMore: () {
              _loadData(++_currentPage);
            },
            refresh: () {
              _currentPage = _initPageCount;
              _loadData(_currentPage);
            },
            //这里定义了子项大小
            itemCount: lists.length + 1,
            listBuilder: _createBuilder,
          ),
        );
Widget _createBuilder(BuildContext context, int index) {
    if (index == 0) {
      return Container(
        height: 200,
        color: Colors.red,
      );
    } else {
      return xxxx;
    }
 }

最终效果如下:
  可以看到多了一个高度200dp的红色contener。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值