【Flutter】使用ScrollController配合EasyRefresh实现列表预加载:在还未滑动到底部时加载下一页数据

server/2025/1/11 20:30:54/

需求/背景

在我们的业务场景中,列表的加载使用easy_refresh组件:

https://pub.dev/packages/easy_refresh

大概效果是往上滑动到一定的offset会触发一个上滑加载,可以触发一些网络请求拉取列表后面的数据来展示。

这种模式一般在一页翻完以后,才会触发加载,此时需要等待加载完以后才能看到新的数据。现在的需求是,想要在即将滑到当前页面底部的时候,预先加载后面的数据,这样表面上看来没有了中间的等待感,可以提升用户体验

思路

首先easy_refresh组件没有提供“预加载”相关的参数,所以我们需要自己去实现。分析需求,我们如何得知触发预加载的这个时机呢?可以比较容易的想到,如果可以监听到滑动的距离,那么就可以根据滑动距离触发加载,比如当监听到用户已经上滑了约一个手机高度那么高(一页)时,触发预加载。

监听滑动的offset,可以联想到使用ScrollController实现。

用法

double _currentOffset = 0; // 记录上一次触发了预加载的位置
ScrollController scrollController; // 列表controller,赋给用于展示元素的ListView
EasyRefreshController refreshController = EasyRefreshController(controlFinishLoad: true, controlFinishRefresh: true); // EasyRefresh组件的controller设置

在对应位置监听scrollController:

scrollController.addListener(() => preLoad());

preLoad方法:

  /// 通过检查当前滑动的位置触发加载.void preLoad() async {if (scrollController.offset - _currentOffset > appHeight) {_currentOffset = scrollController.offset;if (!isNoMore) {await updateItems();  // 加载一页数据}if (isNoMore) refreshController.finishLoad(IndicatorResult.noMore);}}
  • isNoMore:
    判断是否为最后一页,不同的业务场景可能不一样,我是根据拉取的数据数量是否小于我要求的数量来判断的,比如我请求api的时候要拉取20条数据,如果此时返回的不足20条,则说明已经拉到了最后一页。

  • refreshController:
    赋给EasyRefresh组件,这里要finishLoad是因为,在EasyRefresh组件中也有onLoad回调,原本的上拉加载和预加载是同时要有的,为了避免预加载到最后一页,再上滑的时候又发多余的请求,在这里需要及时将加载状态设为IndicatorResult.noMore。

  • appHeight: 屏幕高度,如果项目里面有使用Getx,则计算方式为:

    double appHeight = View.of(Get.context!).physicalSize.height / Get.pixelRatio;
    

    这里使用appHeight作为判断标准,是与业务相关的,这个时候根据我们api的速度等情况,上滑起来比较丝滑:即当往上滑动了一个屏幕这么多的距离时,触发预加载。这个参数可以根据实际情况设置的大一点或小一点。


http://www.ppmy.cn/server/157571.html

相关文章

力扣 74. 搜索二维矩阵

🔗 https://leetcode.cn/problems/search-a-2d-matrix 题目 给一个二维矩阵,保证数字在每行从左到右都是非严格递增每一行的第一个数字大于上一行最后一个数字给一个 target,判断是否存在在二维矩阵中 思路 先 binary search 定位到行&am…

WebRTC 的优缺点详细解析

在当今数字化浪潮中,WebRTC技术凭借其独特优势,在众多联网平台中得以广泛应用,为实时通信带来了革命性变化。然而,如同任何技术一样,它也并非十全十美,存在着一些有待攻克的短板。 一、WebRTC的优点 卓越…

大模型RAG面试内容有哪些?(附面试资料合集)

在面试涉及大模型RAG(Retrieval-Augmented Generation)的职位时,以下是一些常见的面试内容和问题: 技术知识 RAG的基本概念和工作原理:解释RAG系统的主要部分及其如何协同工作。检索技术:了解常见的检索方…

Vue sm3国密 IE模式报错处理

1、sm-crypto 转义错误 查看报错信息包名 在vue.config.js的transpileDependencies中把依赖包添加进去,让babel能够转译sm-crypto包 babel.config.js module.exports {presets: [[vue/app, {useBuiltIns: entry}]] }2、exports.destroy (() > { … }&a…

微信原生小程序自定义封装组件(以导航navbar为例)

封装 topnav.js const App getApp(); Component({// 组件的属性列表properties: {pageName: String, //中间的titleshowNav: { //判断是否显示左上角的按钮 type: Boolean,value: true},showHome: { //判断是否显示左上角的home按钮type: Boolean,value: true},showLocat…

TypeScript语言的软件工程

TypeScript语言的软件工程实践 引言 在现代软件工程中,编程语言的选择对项目的成功至关重要。近年来,JavaScript凭借其在Web开发中的广泛应用取得了巨大成功。然而,随着Web应用程序的复杂性不断增加,开发者渐渐发现纯JavaScript…

RT-DETR代码详解(官方pytorch版)——参数配置(1)

前言 RT-DETR虽然是DETR系列,但是它的代码结构和之前的DETR系列代码不一样。 它是通过很多的yaml文件进行参数配置,和之前在train.py的parser argparse.ArgumentParser()去配置所有参数不同,所以刚开始不熟悉代码的时候可能不知道在哪儿修…

类静态成员的相关内容

问&#xff1a;类静态成员能否在类的构造函数/类的非静态函数中初始化&#xff1f; 答&#xff1a;不能 class requestData {public:requestData(int fd_,int epoll_fd_);~requestData();static std::unordered_map<std::string,std::string> header_map;static int d;…