flutter-实现瀑布流布局及下拉刷新上拉加载更多

文章目录

  • 1. 效果预览
  • 2. 结构分析
  • 3. 完整代码
  • 4. 总结

1. 效果预览

在 Flutter 应用开发中,瀑布流布局常用于展示图片、商品列表等需要以不规则但整齐排列的内容。同时,下拉刷新和上拉加载更多功能,能够极大提升用户体验,让用户方便地获取最新和更多的数据。预览图如下:

预览

2. 结构分析

  1. 先安装依赖插件
# 瀑布流布局:https://pub.dev/packages/waterfall_flowwaterfall_flow: ^3.0.3# 上拉加载更多+下拉刷新:https://pub.dev/packages/pull_to_refreshpull_to_refresh: ^2.0.0
  1. 引入必要的库
import 'dart:async';
import 'package:demo3/constant/imageEnum.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:waterfall_flow/waterfall_flow.dart';
  • dart:async:提供了处理异步操作的能力,在我们的代码中用于处理刷新和加载更多时的延迟操作。
  • package:demo3/constant/imageEnum.dart:这是一个自己的本地图片Map库,用于引入图片枚举数据,在代码中用于获取瀑布流展示的图片资源路径。
  • package:flutter/material.dart:Flutter 的核心 UI 库,提供了构建用户界面所需的各种组件,如Scaffold、SafeArea、Container、Text等。
  • package:pull_to_refresh/pull_to_refresh.dart:这个库用于实现下拉刷新和上拉加载更多的功能,是实现页面交互性的关键库。
  • package:waterfall_flow/waterfall_flow.dart:专门用于创建瀑布流布局的库,让我们能够轻松实现不规则的列表排列效果。
  1. 定义ImageWaterfallFlow组件
class ImageWaterfallFlow extends StatefulWidget {const ImageWaterfallFlow({super.key});State<ImageWaterfallFlow> createState() => ImageWaterfallFlowState();
}

这里定义了ImageWaterfallFlow组件,它是一个有状态的组件。有状态组件允许我们在运行时根据用户操作或其他事件改变组件的状态,从而动态更新 UI。createState方法返回了ImageWaterfallFlowState实例,这个实例负责管理组件的状态和构建具体的 UI。

  1. ImageWaterfallFlowState类的详细解析
class ImageWaterfallFlowState extends State<ImageWaterfallFlow> {/// 字体样式final TextStyle myTxtStyle = const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.w800);/// 模拟数据(初始数据)List imageList = [ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4,ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4];/// 模拟数据(加载更多使用)List moreList = [ImageEnum.banner1, ImageEnum.banner2, ImageEnum.banner3];/// 上拉下拉控制器final RefreshController myRefreshController = RefreshController();
  • 字体样式定义:myTxtStyle定义了一种字体样式,包括白色字体颜色、24 的字体大小和粗体字重,用于在瀑布流的图片容器中显示图片序号。
  • 模拟数据定义:
    imageList用于存储瀑布流初始显示的图片数据。这里通过ImageEnum枚举引入了多个图片资源,组成了一个初始的图片列表。
  • moreList是用于上拉加载更多时的数据。当用户触发加载更多操作时,这个列表中的数据会被添加到imageList中。
  • 上拉下拉控制器:myRefreshController是一个RefreshController实例,它来自pull_to_refresh库。这个控制器用于控制下拉刷新和上拉加载更多的操作状态,比如完成刷新、完成加载等。
  1. 刷新和加载更多的方法
/// 刷新
void onRefresh() async {await Future.delayed(const Duration(milliseconds: 1000));myRefreshController.refreshCompleted();
}/// 加载更多
void onLoadMore() async {await Future.delayed(const Duration(milliseconds: 1000));imageList.addAll(moreList);if (mounted) {setState(() {});}myRefreshController.loadComplete();
}
  • 刷新方法onRefresh:当用户触发下拉刷新操作时,这个方法会被调用。Future.delayed函数模拟了一个 1 秒的延迟,代表实际应用中可能需要的网络请求或数据处理时间。延迟结束后,调用myRefreshController.refreshCompleted()方法通知pull_to_refresh库刷新操作已经完成,此时页面会恢复到正常状态。
  • 加载更多方法onLoadMore:当用户触发上拉加载更多操作时,该方法被执行。同样先通过Future.delayed模拟 1 秒的延迟。然后将moreList中的数据添加到imageList中,更新数据源。if (mounted)条件判断确保组件仍然在 Widget 树中(防止在组件被销毁后尝试更新状态),然后通过setState(() {})方法通知 Flutter 框架状态发生了变化,需要重新构建 UI 以显示新添加的数据。最后调用myRefreshController.loadComplete()方法表示加载更多操作完成。
  1. 构建 UI 的方法
/// 布局

Widget build(BuildContext context) {return Scaffold(backgroundColor: Colors.black,body: SafeArea(child: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: listWidget())));
}

在build方法中,首先创建了一个Scaffold组件,设置背景颜色为黑色。Scaffold是 Flutter 应用的基本结构,它提供了一个默认的导航栏、抽屉等布局。接着,使用SafeArea组件确保内容不会被设备的刘海屏或其他安全区域遮挡。在SafeArea内部,通过SizedBox设置了一个与屏幕大小相同的区域,并将listWidget()返回的内容作为其子组件。listWidget()方法负责构建包含瀑布流和刷新、加载更多功能的实际内容。

  1. 构建瀑布流列表的方法
/// 列表
Widget listWidget() {return SmartRefresher(enablePullDown: true,enablePullUp: true,header: const ClassicHeader(),footer: const ClassicFooter(),controller: myRefreshController,onRefresh: onRefresh,onLoading: onLoadMore,child: WaterfallFlow.builder(physics: const BouncingScrollPhysics(),gridDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(crossAxisCount: 2,crossAxisSpacing: 20,mainAxisSpacing: 20,viewportBuilder: (int index1, int index2) {print('变化:$index1-$index2');},lastChildLayoutTypeBuilder: (index) => index == imageList.length? LastChildLayoutType.fullCrossAxisExtent: LastChildLayoutType.none,),itemCount: imageList.length,itemBuilder: (BuildContext context, int index) {return Container(color: Colors.white,height: (index + 1) % 2 == 0? 100 : 200,child: Container(alignment: Alignment.center,decoration: BoxDecoration(color: Colors.blue.shade300,image: DecorationImage(image: AssetImage(imageList[index]),fit: BoxFit.cover,)),child: Text('第${index + 1}张', style: myTxtStyle)),);},),);
}
  • 使用SmartRefresher组件:这是pull_to_refresh库中的核心组件,用于实现下拉刷新和上拉加载更多功能。
  • enablePullDown: true和enablePullUp: true分别启用了下拉刷新和上拉加载更多功能。
  • header: const ClassicHeader()和footer: const ClassicFooter()分别设置了下拉刷新和上拉加载更多时显示的头部和底部样式,这里使用了pull_to_refresh库提供的经典样式。
  • controller: myRefreshController关联了之前定义的刷新控制器。
  • onRefresh: onRefresh和onLoading: onLoadMore分别指定了下拉刷新和上拉加载更多时执行的回调函数,即前面定义的onRefresh和onLoadMore方法。
  • 使用WaterfallFlow.builder构建瀑布流:
  • physics: const BouncingScrollPhysics()设置了瀑布流的滚动物理效果,这里使用了类似于 iOS 的弹性滚动效果。
  • gridDelegate属性:
    • crossAxisCount: 2指定了瀑布流每行显示两个项目。
    • crossAxisSpacing: 20和mainAxisSpacing: 20分别设置了项目在交叉轴(水平方向)和主轴(垂直方向)上的间距。
  • viewportBuilder是一个回调函数,只是简单打印了索引变化,但在实际应用中可以用于监控视口内项目的变化情况。
  • lastChildLayoutTypeBuilder用于设置最后一个子项的布局类型。当索引等于imageList的长度时,将最后一个子项设置为占据整个交叉轴宽度,否则不进行特殊设置。
  • itemCount: imageList.length指定了瀑布流中项目的数量,即imageList的长度。
  • itemBuilder属性:这个回调函数用于构建每个瀑布流项目。每个项目是一个Container,外层- Container设置了白色背景,高度根据索引奇偶性分别为 100 或 200。内层Container设置了蓝色背景和图片装饰,图片通过AssetImage从imageList中获取,并使用BoxFit.cover进行适配。同时,在图片上显示了图片的序号,使用了之前定义的myTxtStyle字体样式。

3. 完整代码

import 'dart:async';
import 'package:demo3/constant/imageEnum.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:waterfall_flow/waterfall_flow.dart';/// 瀑布流
class ImageWaterfallFlow extends StatefulWidget {const ImageWaterfallFlow({super.key});State<ImageWaterfallFlow> createState() => ImageWaterfallFlowState();
}/// 瀑布流状态
class ImageWaterfallFlowState extends State<ImageWaterfallFlow> {/// 字体样式final TextStyle myTxtStyle = const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.w800);/// 模拟数据(初始数据)List imageList = [ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4,ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4];/// 模拟数据(加载更多使用)List moreList = [ImageEnum.banner1, ImageEnum.banner2, ImageEnum.banner3];/// 上拉下拉控制器final RefreshController myRefreshController = RefreshController();/// 刷新void onRefresh() async {await Future.delayed(const Duration(milliseconds: 1000));myRefreshController.refreshCompleted();}/// 加载更多void onLoadMore() async {await Future.delayed(const Duration(milliseconds: 1000));imageList.addAll(moreList);if (mounted) {setState(() {});}myRefreshController.loadComplete();}/// 布局Widget build(BuildContext context) {return Scaffold(backgroundColor: Colors.black,body: SafeArea(child: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: listWidget())));}/// 列表Widget listWidget() {return SmartRefresher(enablePullDown: true,enablePullUp: true,header: const ClassicHeader(),footer: const ClassicFooter(),controller: myRefreshController,onRefresh: onRefresh,onLoading: onLoadMore,child: WaterfallFlow.builder(physics: const BouncingScrollPhysics(),gridDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(crossAxisCount: 2,crossAxisSpacing: 20,mainAxisSpacing: 20,viewportBuilder: (int index1, int index2) {print('变化:$index1-$index2');},lastChildLayoutTypeBuilder: (index) => index == imageList.length? LastChildLayoutType.fullCrossAxisExtent: LastChildLayoutType.none,),itemCount: imageList.length,itemBuilder: (BuildContext context, int index) {return Container(color: Colors.white,height: (index + 1) % 2 == 0 ? 100 : 200,child: Container(alignment: Alignment.center,decoration: BoxDecoration(color: Colors.blue.shade300,image: DecorationImage(image: AssetImage(imageList[index]),fit: BoxFit.cover,)),child: Text('第${index + 1}张', style: myTxtStyle)),);},),);}
}

4. 总结

通过这段代码,我们成功地在 Flutter 中实现了一个带有瀑布流布局、下拉刷新和上拉加载更多功能的页面。从引入必要的库,到定义组件、管理状态以及构建复杂的 UI 结构,每一步都紧密配合。pull_to_refresh库和waterfall_flow库的使用是实现这些功能的关键,合理地设置各种属性和回调函数,让页面具备了良好的交互性和美观的布局效果。希望这篇文章能帮助你理解并在自己的 Flutter 项目中运用类似的功能。


本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~

往期文章

  • flutter-使用extended_image操作图片的加载和状态处理以及缓存和下载
  • flutter-制作可缩放底部弹出抽屉评论区效果
  • flutter-实现Tabs吸顶的PageView效果
  • Vue2全家桶+Element搭建的PC端在线音乐网站
  • 助你上手Vue3全家桶之Vue3教程
  • 助你上手Vue3全家桶之VueX4教程
  • 助你上手Vue3全家桶之Vue-Router4教程
  • 超详细!Vue的九种通信方式
  • 超详细!Vuex手把手教程
  • 使用nvm管理node.js版本以及更换npm淘宝镜像源
  • vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令

个人主页

  • CSDN
  • GitHub
  • 简书
  • 博客园
  • 掘金

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41686.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【day2】数据结构刷题 栈

一 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的…

YAML是什么?

YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种以数据为中心、高度可读的序列化语言&#xff0c;广泛应用于配置文件、数据交换和自动化工具中。以下从多个维度对其进行全面解析&#xff1a; 1. 定义与历史演变 全称与定位&#xff1a; YAML的全称最初为“Yet…

熔断降级(Sentinel解决)

问题概述 在微服务架构中一定要预防微服务雪崩问题&#xff0c;微服务雪崩问题就是指在微服务架构中&#xff0c;当一个服务出现故障时&#xff0c;由于服务之间的依赖关系&#xff0c;故障可能会传播到其他服务&#xff0c;从而导致了大规模的服务失败&#xff0c;系统无法正…

反序列化漏洞

前提概要 本文章主要用于分享反序列化漏洞基础学习&#xff0c;以下是对反序列化漏洞的一些个人解析&#xff0c;请大家结合参考其他文章中的相关信息进行归纳和补充。 反序列化漏洞描述 反序列化漏洞是指程序在对输入的字节流进行反序列化时&#xff0c;因缺乏充分的验证和过…

吐血整理:Air8201如何使用LuatOS进行电源管理功能!

在物联网应用场景中&#xff0c;设备续航能力直接影响其部署成本与运维效率。LuatOS操作系统通过软件层面的精细化控制&#xff0c;为Air8201提供了灵活且高效的电源管理策略。本文将从系统架构、API接口、实战配置三个维度&#xff0c;解析如何利用LuatOS实现Air8201的智能电源…

STM32学习笔记之存储器映射(原理篇)

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

合宙780E开发学习-LUATOS-SOC云编译自定义固件

登录https://luatos.com 点击登录&#xff0c;使用合宙erp账号登录即可 点击右上角构建&#xff0c;点击右上角菜单新构建&#xff0c;自定义构建名称&#xff0c;可新建多个 勾选想要的组件 点击右上角保存修改&#xff0c;只有点击准备就绪&#xff08;注意&#xff1a;一定…

react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析

一、React 15&#xff08;2016&#xff09; 核心架构&#xff1a;Stack Reconciler&#xff08;栈协调器&#xff09; 工作原理&#xff1a; 同步递归渲染&#xff1a;采用深度优先遍历方式递归处理 Virtual DOM&#xff0c;形成不可中断的调用栈渲染流程&#xff1a;1. 触发 …

【HarmonyOS NEXT】EventHub和Emitter的使用场景与区别

一、EventHub是什么&#xff1f; 移动应用开发的同学应该比较了解EventHub&#xff0c;类似于EventBus。标准的事件广播通知&#xff0c;订阅&#xff0c;取消订阅的处理。EventHub模块提供了事件中心&#xff0c;提供订阅、取消订阅、触发事件的能力。 类似的框架工具有很多…

QT记事本

记事本应用程序提供了基本的文本编辑功能&#xff0c;支持文件的新建、打开、保存和另存为操作&#xff0c;同时具备修改提示和关闭窗口时的保存确认功能。使用 UTF - 8 编码确保了对多语言文本的支持。 1. 项目整体结构 main.cpp&#xff1a;程序的入口点&#xff0c;负责初…

如何用 Postman 发送 POST 请求?

POST 请求是 HTTP 协议中用于提交数据的一种方法&#xff0c;Postman 提供了丰富的功能来支持用户发送包含各种信息的 POST 请求&#xff0c;如文本数据、JSON 或 XML 数据结构、文件等。 Postman 发送 post 请求教程

Ant Design Vue 中的table表格高度塌陷,造成行与行不齐的问题

前言&#xff1a; Ant Design Vue: 1.7.2 Vue2 less 问题描述&#xff1a; 在通过下拉框选择之后&#xff0c;在获取接口数据&#xff0c;第一列使用了fixed:left&#xff0c;就碰到了高度塌陷&#xff0c;查看元素的样式结果高度不一致&#xff0c;如&#x…

Flink 通过 Chunjun Oracle LogMiner 实时读取 Oracle 变更日志并写入 Doris 的方案

文章目录 一、 技术背景二、 关键技术1、 Oracle LogMiner2、 Chunjun 的 LogMiner 关键流程3、修复 Chunjun Oracle LogMiner 问题 一、 技术背景 在大数据实时同步场景中&#xff0c;需要将 Oracle 数据库的变更数据&#xff08;CDC&#xff09; 采集并写入 Apache Doris&am…

qt+opengl 加载三维obj文件

1前面我们已经熟悉了opengl自定义顶点生成一个立方体&#xff0c;并且我们实现了立方体的旋转&#xff0c;光照等功能。下面我们来用opengl来加载一个obj文件。准备我们首先准备一个简单的obj文件&#xff08;head.obj&#xff09;。资源在本页下载 2 在obj文件里面&#xff0c…

计算机组成原理的学习day01

一 计算机系统层次结构 1 计算机硬件的基本组成 好的&#xff0c;上个小节中我们了解了计算机系统的概念&#xff0c;还有计算机的一个发展历程&#xff0c;那这个小节中我们会着重的探讨计算机硬件的一个基本组成。我们需要掌握这样的两种结构&#xff0c;第一种是早期的冯诺…

ASP 应用HTTP.SYS短文件文件解析Access 注入数据库泄漏

#ASP- 默认安装 -MDB 数据库泄漏下载&#xff08;路径是知道的话可以直接下载&#xff09; 由于大部分 ASP 程序与 ACCESS 数据库搭建&#xff0c;但 ACCESS 无需连接&#xff0c;都在脚本文件中定 义配置好数据库路径即用&#xff0c;不需要额外配置安装数据库&#x…

Redis 版本演进及主要新特性

Redis 版本发布历史 稳定版本时间线 Redis 2.6 (2012年)Redis 2.8 (2013年11月)Redis 3.0 (2015年4月) - 首次支持集群Redis 3.2 (2016年5月)Redis 4.0 (2017年7月)Redis 5.0 (2018年10月)Redis 6.0 (2020年4月)Redis 6.2 (2021年2月)Redis 7.0 (2022年4月) - 最新稳定版(截至…

从 MySQL 到时序数据库 TDengine:Zendure 如何实现高效储能数据管理?

小T导读&#xff1a;TDengine 助力广州疆海科技有限公司高效完成储能业务的数据分析任务&#xff0c;轻松应对海量功率、电能及输入输出数据的实时统计与分析&#xff0c;并以接近 1 : 20 的数据文件压缩率大幅降低存储成本。此外&#xff0c;taosX 强大的 transform 功能帮助用…

NVM安装速通使用手册(Windows版)NVM管理node版本命令手册 NVM使用手册

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的命令行工具。通过nvm&#xff0c;你可以在同一台机器上安装和切换多个Node.js版本&#xff0c;非常适合开发和测试在不同Node.js版本上运行的应用程序 一、安装地址 1. 官方下载&#xff1a; &…

qt QQuaternion详解

1. 概述 QQuaternion 是 Qt 中用于表示三维空间中旋转的四元数类。它包含一个标量部分和一个三维向量部分&#xff0c;可以用来表示旋转操作。四元数在计算机图形学中广泛用于平滑的旋转和插值。 2. 重要方法 默认构造函数 QQuaternion::QQuaternion(); // 构造单位四元数 (1…