flutter下拉刷新上拉加载的简单实现方式三
使用 `CustomScrollView` 结合 `SliverList` 实现了一个支持下拉刷新和上拉加载更多功能的滚动列表,对下面代码进行解析学习。
import 'dart:math';import 'package:flutter/material.dart';import 'custom_pull/gsy_refresh_sliver.dart';
import 'package:flutter/cupertino.dart' as IOS;class NewMyRefreshDemoPage extends StatefulWidget {const NewMyRefreshDemoPage({super.key});@overrideState<StatefulWidget> createState() => _NewMyRefreshDemoState();
}class _NewMyRefreshDemoState extends State<NewMyRefreshDemoPage> {final GlobalKey<CupertinoSliverRefreshControlState> sliverRefreshKey =GlobalKey<CupertinoSliverRefreshControlState>();final int pageSize = 30;bool disposed = false;List<String> dataList = [];final ScrollController _scrollController = ScrollController();Future<void> onRefresh() async {await Future.delayed(const Duration(seconds: 2));dataList.clear();for (int i = 0; i < pageSize; i++) {dataList.add("refresh");}if (disposed) {return;}setState(() {});}Future<void> loadMore() async {await Future.delayed(const Duration(seconds: 2));for (int i = 0; i < pageSize; i++) {dataList.add("loadmore");}if (disposed) {return;}setState(() {});}@overridevoid didChangeDependencies() {Future.delayed(const Duration(milliseconds: 500), () {_scrollController.animateTo(-141,duration: const Duration(milliseconds: 600), curve: Curves.linear);return true;});}@overridevoid dispose() {disposed = true;super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("NewMyRefreshDemoPage"),),body: NotificationListener(onNotification: (ScrollNotification notification) {//通知 CupertinoSliverRefreshControl 当前的拖拽状态sliverRefreshKey.currentState?.notifyScrollNotification(notification);if (notification is ScrollEndNotification) {if (_scrollController.position.pixels > 0 &&_scrollController.position.pixels ==_scrollController.position.maxScrollExtent) {loadMore();}}return false;},child: CustomScrollView(controller: _scrollController,physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),slivers: <Widget>[CupertinoSliverRefreshControl(key: sliverRefreshKey,refreshIndicatorExtent: 100,refreshTriggerPullDistance: 140,onRefresh: onRefresh,builder: buildSimpleRefreshIndicator,),//列表SliverSafeArea(sliver: SliverList(delegate: SliverChildBuilderDelegate((BuildContext context, int index) {if (index == dataList.length) {return Container(margin: const EdgeInsets.all(10),child: const Align(child: CircularProgressIndicator(),),);}return Card(child: Container(height: 60,alignment: Alignment.centerLeft,child: Text("Item ${dataList[index]} $index"),),);},childCount: (dataList.length >= pageSize)? dataList.length + 1: dataList.length,),))],),),);}
}Widget buildSimpleRefreshIndicator(BuildContext context,RefreshIndicatorMode? refreshState,double pulledExtent,double refreshTriggerPullDistance,double refreshIndicatorExtent) {const Curve opacityCurve = Interval(0.4, 0.8, curve: Curves.easeInOut);return Align(alignment: Alignment.bottomCenter,child: Padding(padding: const EdgeInsets.only(bottom: 16.0),child: refreshState != RefreshIndicatorMode.refresh? Opacity(opacity: opacityCurve.transform(min(pulledExtent / refreshTriggerPullDistance, 1.0)),child: const Icon(IOS.CupertinoIcons.down_arrow,color: IOS.CupertinoColors.inactiveGray,size: 36.0,),): Opacity(opacity: opacityCurve.transform(min(pulledExtent / refreshIndicatorExtent, 1.0)),child: const IOS.CupertinoActivityIndicator(radius: 14.0),),),);
}
相关代码解析
NewMyRefreshDemoPage
这是一个 `StatefulWidget`,表示可以维护状态的组件。核心功能是提供一个支持刷新和加载更多的列表页面。
_NewMyRefreshDemoState
`State` 类的子类,负责管理 `NewMyRefreshDemoPage` 的状态。包含了 `dataList` 用于存储列表数据,以及控制滚动和刷新状态的逻辑。
相关状态管理
- `sliverRefreshKey`:一个 `GlobalKey`,用于访问 `CupertinoSliverRefreshControl` 的状态。
- `pageSize`:每次刷新或加载的项目数。
- `disposed`:用于标识状态是否已被销毁,避免在组件卸载后进行状态更新。
- `dataList`:存储列表项的数据。
- `_scrollController`:用于控制滚动行为的 `ScrollController`。
相关方法
- `onRefresh`:模拟网络请求,清空并重新填充列表数据。
- `loadMore`:模拟网络请求,向列表追加更多数据。
- `didChangeDependencies`:在组件依赖变化时调用,初始化时会在短暂延时后滚动到一个指定位置以触发下拉刷新。
- `dispose`:在组件卸载时调用,标记状态为已销毁。
UI 构建相关
`build` 方法
Scaffold:页面的基础结构,包含一个 `AppBar` 和 `body`。
NotificationListener:监听滚动事件,用于通知刷新控件当前的拖拽状态,以及检测是否到达滚动底部以加载更多。
CustomScrollView:允许在同一滚动视图中使用多个 sliver 组件。
- CupertinoSliverRefreshControl:提供下拉刷新功能。
- SliverSafeArea & SliverList:用于在安全区域内展示列表项。
`buildSimpleRefreshIndicator` 方法
- `refreshState`:当前刷新状态。
- `pulledExtent`:拖动距离。
- `refreshTriggerPullDistance`:触发刷新的拖动距离。
- `refreshIndicatorExtent`:指示器的最大显示高度。
GlobalKey
final GlobalKey<CupertinoSliverRefreshControlState> sliverRefreshKey =GlobalKey<CupertinoSliverRefreshControlState>();
用于标识 `CupertinoSliverRefreshControl` 的全局键,允许在其他地方访问其状态。在 Flutter 中,`GlobalKey` 是一个强大的工具,用于唯一地标识和访问某个特定的组件实例。通过使用 `GlobalKey`,你可以在树的其他地方访问这个组件的状态或执行某些操作。
GlobalKey 是一个特殊的键,可以在 widget 树中唯一标识一个 widget。它允许访问与之关联的 widget 状态(`State` 对象),这在需要跨越 widget 树访问状态时非常有用。
CupertinoSliverRefreshControlState
这是 `CupertinoSliverRefreshControl` 的状态类。使用 `GlobalKey` 可以直接访问这个状态,进行一些状态更新或调用状态中的方法。
使用场景:
- 访问刷新控件的状态:通过 `sliverRefreshKey.currentState`,你可以访问 `CupertinoSliverRefreshControl` 的状态对象。
- 通知滚动状态:在 `NotificationListener` 中,使用 `sliverRefreshKey.currentState?.notifyScrollNotification(notification)` 来通知刷新控件当前的滚动状态。
CupertinoSliverRefreshControl
`CupertinoSliverRefreshControl` 是 Flutter 中一个用于实现 iOS 风格下拉刷新效果的组件。它通常用于 `CustomScrollView` 中,以提供流畅的下拉刷新体验,类似于 iOS 应用的原生行为。
主要特性
- iOS 风格:以 iOS 的外观和行为为设计基础,提供原生般的用户体验。
- 与 Sliver 兼容:设计用于与 `CustomScrollView` 和 sliver 系统一起使用,适合实现复杂的滚动布局。
- 自动处理刷新逻辑:通过提供 `onRefresh` 回调,轻松实现数据刷新逻辑。
主要属性
refreshTriggerPullDistance
定义触发刷新操作所需的下拉距离(默认值为 100.0)。用户必须拉动至少此距离才能触发刷新。
refreshIndicatorExtent
刷新指示器的最大高度(默认值为 60.0)。指示器在用户继续下拉时可以扩展到的最大高度。
builder
自定义刷新指示器的外观。默认情况下,使用内置的 iOS 风格指示器,你可以提供一个自定义构建函数来改变其外观。
onRefresh
异步回调函数,当用户触发刷新操作时调用。通常用于执行异步操作(如网络请求)来更新数据。
注意
- `CustomScrollView`:用于包裹 `CupertinoSliverRefreshControl` 和 `SliverList`,使得刷新控件可以与列表一起滚动。
- `CupertinoSliverRefreshControl`:提供下拉刷新功能,`onRefresh` 回调用于定义刷新时的逻辑(如更新数据)。
- 刷新逻辑:在 `_handleRefresh` 中模拟了一个网络请求,通过 `Future.delayed` 来延迟刷新操作。
buildSimpleRefreshIndicator
`buildSimpleRefreshIndicator` 是一个用于自定义刷新指示器外观的函数。它通常在实现下拉刷新功能时与 `CupertinoSliverRefreshControl` 一起使用。这个函数根据用户下拉的距离和当前的刷新状态来动态调整指示器的外观。
BuildContext context
Flutter 的上下文对象,用于获取主题、媒体查询等信息。在这个函数中没有被直接使用。
RefreshIndicatorMode? refreshState
刷新指示器的当前状态。可能的值包括:
- `inactive`:未触发刷新。
- `drag`:用户正在拖动,但未达到刷新阈值。
- `armed`:用户拖动超过阈值,松手后将触发刷新。
- `refresh`:正在刷新中。
- `done`:刷新完成。
该函数使用此状态来决定显示箭头图标还是加载动画。
double pulledExtent
用户下拉的距离(以像素为单位)。
double refreshTriggerPullDistance
触发刷新的下拉距离阈值。
double refreshIndicatorExtent
刷新指示器的最大显示高度。
Curve
const Curve opacityCurve = Interval(0.4, 0.8, curve: Curves.easeInOut)
使用 `Interval` 定义一个曲线,用于控制不透明度变化的动画效果。`Interval(0.4, 0.8, curve: Curves.easeInOut)` 表示在 40% 到 80% 的时间内应用 `easeInOut` 曲线。
刷新指示器的作用
使用条件表达式根据 `refreshState` 的值显示不同的组件:
- 如果状态不是 `RefreshIndicatorMode.refresh`,则显示一个箭头图标,且图标的透明度根据 `pulledExtent` 与 `refreshTriggerPullDistance` 的比例动态调整。
- 如果状态是 `RefreshIndicatorMode.refresh`,则显示一个 `CupertinoActivityIndicator` 加载动画,且透明度根据 `pulledExtent` 与 `refreshIndicatorExtent` 的比例调整。
如何工作
- 当用户开始下拉时,指示器的箭头图标会根据下拉距离逐渐显现。
- 当用户的下拉距离超过 `refreshTriggerPullDistance` 并松手后,指示器状态变为 `refresh`,显示加载动画。
- 加载动画的透明度也会随着用户下拉距离的变化而变化,提供更好的视觉反馈。
相关文章:
flutter下拉刷新上拉加载的简单实现方式三
使用 CustomScrollView 结合 SliverList 实现了一个支持下拉刷新和上拉加载更多功能的滚动列表,对下面代码进行解析学习。 import dart:math;import package:flutter/material.dart;import custom_pull/gsy_refresh_sliver.dart; import package:flutter/cupertino…...
【C++ 20进阶(2):属性 Attribute】
【C 20进阶(2):属性 Attribute】 原文:https://blog.csdn.net/weixin_44259356/article/details/143663492 引言 本篇文章为系列文章将着重介绍C20新特性,一是希望可以和大家交流分享,二是也便于自己巩固…...

【系统面试篇】其他相关题目——虚拟内存、局部性原理、分页、分块、页面置换算法
目录 一、相关问题 1. 什么是虚拟内存?为什么需要虚拟内存? (1)内存扩展 (2)内存隔离 (3)物理内存管理 (4)页面交换 (5)内存映…...

力扣617:合并二叉树
给你两棵二叉树: root1 和 root2 。 想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠&#…...
软件设计师 - 第1章 计算机网络概论
计算机系统硬件基本组成 输入设备:键盘,鼠标输出设备:显示器,打印机...存储器:主存储器,如内存;辅助存储器,如外存运算器:与控制器一同集成在CPU中控制器:与…...

方案丨车险保单OCR:3秒钟完成保单审核
在涉及车辆交易的各种情况下,记录和管理车险保单信息是一项必不可少的任务。然而,面对数量庞大的电子保单,传统的手工录入方式显得尤为低效——它不仅消耗大量时间,而且容易出现错误,这不仅影响了用户的满意度…...

Jmeter中的监听器(一)
监听器 1--查看结果树 用途 调试测试计划:查看每个请求的详细信息,帮助调试和修正测试计划。分析响应数据:查看服务器返回的响应数据,验证请求是否成功。检查错误:识别和分析请求失败的原因。 配置步骤 添加查看结果…...
C++ 标准库 std::vector 的介绍
std::vector 是 C 标准库中的一个动态数组容器,它提供了多种成员函数来管理其内部存储的元素。以下是一些常用的 std::vector 成员函数的介绍: 构造函数和析构函数 vector(): 默认构造函数。vector(size_type n): 构造一个包含 n 个元素的向量…...

鸿蒙开发-装饰器@Link问题
正常示例 class Parent {public count: number;constructor( count: number) {this.count count;} } Entry Component struct TestPage {State parent: Parent new Parent( 11)build() {Column() {SubComponent({ parent: this.parent })}.height(100%)} } Component struct…...

CTFhub靶场RCE学习
靶场 eval执行 <?php if (isset($_REQUEST[cmd])) {eval($_REQUEST["cmd"]); } else {highlight_file(__FILE__); } ?> PHP代码显示,要求将命令赋值给cmd然后执行 先查看一下根目录文件 ?cmdsystem("ls");!切记最后的分…...

一文3000字从0到1带你进行Mock测试(建议收藏)
什么是mock? mock测试是以可控的方式模拟真实的对象行为。程序员通常创造模拟对象来测试对象本身该具备的行为,很类似汽车设计者使用碰撞测试假人来模拟车辆碰撞中人的动态行为 为什么要使用Mock? 之所以使用mock测试,是因…...

数据结构 ——— 链式二叉树的销毁(释放)
目录 链式二叉树示意图 手搓一个链式二叉树 代码实现 示意图 手搓一个链式二叉树 代码演示: // 数据类型 typedef int BTDataType;// 二叉树节点的结构 typedef struct BinaryTreeNode {BTDataType data; //每个节点的数据struct BinaryTreeNode* left; //指向…...

log4j异常堆栈文件输出
目的:log4j异常堆栈关联到traceId一句话中,方便搜索 1、获取堆栈后一起打印 private void logException(Throwable t, ProceedingJoinPoint joinPoint) {if (this.printErrorStackSys) {StringWriter sw new StringWriter();PrintWriter pw new Print…...

在配置环境变量之后使用Maven报错 : mvn : 无法将“mvn”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
最近,我在 Windows 系统上安装和配置 Apache Maven 时遇到了一些问题,想在此记录下我的解决历程,希望对遇到类似问题的朋友有所帮助。 问题描述 我下载了 Maven 并按照常规步骤配置了相关的环境变量。然而,在 PowerShell 中输入…...
SpringSecurity源码中核心类
SpringSecurity源码 第一部分 核心类 SecurityBuilderHttpSecurityWebSecuritySecurityFilterChainFilterChainProxy SecurityBuilder是安全构架器,HttpSecurity和WebSecurity都是SecurityBuilder的实现类,HttpSecurity通过build()构建了一个Security…...

【JAVA】使用IDEA创建maven聚合项目
【JAVA】使用IDEA创建maven聚合项目 1.效果图 2.创建父模块项目 2.1删除父模块下面的src目录以及不需要的maven依赖 3创建子模块项目 3.1右击父模块项目选择Module… 3.2创建子模块 3.3删除子模块下不需要的maven依赖 4.子模块创建完成后引入SpringBoot依赖启动项目...

猿创征文|Inscode桌面IDE:打造高效开发新体验
猿创征文|Inscode桌面IDE:打造高效开发新体验 引言 在当今快速发展的软件开发领域,一个高效、易用的集成开发环境(IDE)是每个开发者必不可少的工具。Inscode 桌面 IDE 作为一款新兴的开发工具,凭借其强大…...
概率论中的PMF、PDF和CDF
在概率论中,PMF(概率质量函数)、PDF(概率密度函数)和CDF(累积分布函数)是描述随机变量分布的三个重要概念。它们分别用于不同类型的随机变量,并帮助我们理解随机事件的概率特性。本文…...

Vue 简单入手
前端工程化(Front-end Engineering)指的是在前端开发中,通过一系列工具、流程和规范的整合,以提高开发效率、代码质量和可维护性的一种技术和实践方法。其核心目的是使得前端开发变得更高效、可扩展和可维护。 文章目录 一、Vue 项…...

Github配置ssh key原理及操作步骤
文章目录 配置SSH第一步:检查本地主机是否已经存在ssh key第二步:生成ssh key第三步:获取ssh key公钥内容第四步:Github账号上添加公钥第五步:验证是否设置成功验证原理 往github上push项目的时候,如果走ht…...

web架构2------(nginx多站点配置,include配置文件,日志,basic认证,ssl认证)
一.前言 前面我们介绍了一下nginx的安装和基础配置,今天继续来深入讲解一下nginx的其他配置 二.nginx多站点配置 一个nginx上可以运行多个网站。有多种方式: http:// ip/域名 端口 URI 其中,ip/域名变了,那么网站入口就变了…...
Spring Boot DevTools 热部署
在Spring Boot项目中加入 spring-boot-devtools 热部署依赖启动器后,通常不需要手动重启项目即可让更改生效。spring-boot-devtools 的核心特性之一就是自动重启或热加载。 Spring Boot DevTools 热部署关键知识点 🔥 目的:spring-boot-devt…...

微服务-Sentinel
目录 背景 Sentinel使用 Sentinel控制台 Sentinel控制规则 Sentinel整合OpenFeign 背景 在微服务项目架构中,存在多个服务相互调用场景,在某些情况下某个微服务不可用时,上游调用者若一直等待,会产生资源的消耗,极端情…...

【多线程初阶】内存可见性问题 volatile
文章目录 再谈线程安全问题内存可见性问题可见性问题案例编译器优化 volatileJava内存模型(JMM) 再谈线程安全问题 如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该有的结果,则说这个程序是线程安全的,反之,多线程环境中,并发执行后,产生bug就是线程不安全…...

达梦数据库 Windows 系统安装教程
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...
HTTPS加密通信详解及在Spring Boot中的实现
HTTPS(Hyper Text Transfer Protocol Secure)是HTTP的安全版本,通过SSL/TLS协议为通讯提供加密、身份验证和数据完整性保护。 一、HTTPS核心原理 1.加密流程概述 客户端发起HTTPS请求(连接到服务器443端口)服务器返…...
Playwright Python API 测试:从入门到实践
Playwright Python API 测试:从入门到实践 在现代软件开发中,API 测试是确保应用程序后端功能正常运行的关键环节。Playwright 是一个强大的自动化测试工具,支持多种编程语言,其中包括 Python。通过 Playwright,我们可…...
麒麟v10,arm64架构,编译安装Qt5.12.8
Window和麒麟x86_64架构,官网提供安装包,麒麟arm64架构的,只能自己用编码编译安装。 注意,“桌面”路径是中文,所以不要把源码放在桌面上编译。 1. 下载源码 从官网下载源码:https://download.qt.io/arc…...

把 jar 打包成 exe
1. 把自己的项目先正常打成jar包 2. 使用exe4j工具将jar转换为exe 2.1 exe4j下载地址:https://www.ej-technologies.com/download/exe4j/files 2.2 下载完成之后激活 2.3 可以点击Change License,输入秘钥L-g782dn2d-1f1yqxx1rv1sqd 2.4 直接下一步…...
数据存储与运算
计算机中的数据存储与运算 输出地址后看不懂格式,为什么? 第一节:进制转换基础 ✅ 常见进制: 十进制(Decimal):日常使用的 0~9二进制(Binary):计算机底层使…...