Flutter 上拉加载更多与分页功能实现

下拉刷新Widget

RefreshIndicator

RefreshIndicator(
        onRefresh: xxx, // 下拉刷新,加载数据
        child: Widget // 列表展示加载数据
)

监听列表滑动监听

ScrollController

 ScrollController scrollController = new ScrollController();
 // 添加列表滑动监听
 scrollController.addListener(() {
      // 滑动距离
      var dis = scrollController.position.maxScrollExtent -
          scrollController.position.pixels;
      // 当滑动到底部不足 300 并且没有加载数据时,加载更多
      // 也可以根据临界值,是否允许下拉刷新以及下拉加载更多
      if (dis < 300 && !_loading) {
        _loadData(loadMore: true);
      }
    });
 
  @override
  void dispose() {
    super.dispose();
    // 释放资源
    scrollController.dispose();
  }

在应用列表的地方,添加 controller 配置

StaggeredGridView.countBuilder(
     // 添加列表滑动监听
     controller: scrollController
)       

代码示例

class HomeTabPage extends StatefulWidget {
  @override
  _HomeTabPageState createState() => _HomeTabPageState();
}

class _HomeTabPageState extends State<HomeTabPage>
    with AutomaticKeepAliveClientMixin {
  // 列表滚动监听
  ScrollController scrollController = new ScrollController();

  List<VideoMo> videoList = [];
  int pageIndex = 1;
  bool _loading = false; // 是否在加载数据

  @override
  void initState() {
    super.initState();
    scrollController.addListener(() {
      // 滑动距离
      var dis = scrollController.position.maxScrollExtent -
          scrollController.position.pixels;
      // 当滑动到底部不足 300 并且没有加载数据时,加载更多
      // 也可以根据临界值,是否允许下拉刷新以及下拉加载更多
      if (dis < 300 && !_loading) {
        _loadData(loadMore: true);
      }
    });
    _loadData();
  }

  @override
  void dispose() {
    super.dispose();
    // 释放资源
    scrollController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return RefreshIndicator(
        onRefresh: _loadData,
        child: MediaQuery.removePadding(
          // 移除顶部top
          removeTop: true,
          context: context,
          child: StaggeredGridView.countBuilder(
            // 添加列表滑动监听
            controller: scrollController,
            itemCount: videoList.length,
            // 即使数据不足一屏幕时,也允许滑动列表
            physics: const AlwaysScrollableScrollPhysics(),
            padding: EdgeInsets.only(top: 10, left: 10, right: 10),
            itemBuilder: (BuildContext context, int index) {
              return VideoCard(
                videoMo: videoList[index],
              );
            },
            staggeredTileBuilder: (int index) {
              if (index == 0) {
                // Banner 独占两列
                return StaggeredTile.fit(2);
              } else {
                return StaggeredTile.fit(1);
              }
            },
          ),
        ));
  }

  /**
   * 加载数据
   */
  Future<void> _loadData({loadMore = false}) async {
    _loading = true;
    if (!loadMore) {
      pageIndex++;
    }
    try {
      // 访问网络
      var currentIndex = pageIndex + (loadMore ? 1 : 0);
      var result = await HomeDao.get("", pageIndex: currentIndex, pageSize: 30);
      // 更新数据
      setState(() {
        if (loadMore) {
          videoList = [...videoList, result.videoList];
          pageIndex++;
        } else {
          videoList = result.videoList;
        }
        // 延迟1s重置 _loading
        Future.delayed(Duration(milliseconds: 1000), () {
          _loading = false;
        });
      });
    } on NeedAuth catch (e) {
      _loading = false;
      print(e);
      showWarnToast(e.message);
    } on HiNetError catch (e) {
      _loading = false;
      print(e);
      showWarnToast(e.message);
    }
  }

  @override
  bool get wantKeepAlive => true;
}


版权声明:本文为weixin_43800535原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。