在 Flutter 应用开发中,瀑布流布局常用于展示图片、商品列表等需要以不规则但整齐排列的内容。同时,下拉刷新和上拉加载更多功能,能够极大提升用户体验,让用户方便地获取最新和更多的数据。预览图如下:
# 瀑布流布局:https://pub.dev/packages/waterfall_flow
waterfall_flow: ^3.0.3
# 上拉加载更多+下拉刷新:https://pub.dev/packages/pull_to_refresh
pull_to_refresh: ^2.0.0
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();
}
这里定义了ImageWaterfallFlow组件,它是一个有状态的组件。有状态组件允许我们在运行时根据用户操作或其他事件改变组件的状态,从而动态更新 UI。createState方法返回了ImageWaterfallFlowState实例,这个实例负责管理组件的状态和构建具体的 UI。
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())));
}
在build方法中,首先创建了一个Scaffold组件,设置背景颜色为黑色。Scaffold是 Flutter 应用的基本结构,它提供了一个默认的导航栏、抽屉等布局。接着,使用SafeArea组件确保内容不会被设备的刘海屏或其他安全区域遮挡。在SafeArea内部,通过SizedBox设置了一个与屏幕大小相同的区域,并将listWidget()返回的内容作为其子组件。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)),
);
},
),
);
}
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)),
);
},
),
);
}
}
通过这段代码,我们成功地在 Flutter 中实现了一个带有瀑布流布局、下拉刷新和上拉加载更多功能的页面。从引入必要的库,到定义组件、管理状态以及构建复杂的 UI 结构,每一步都紧密配合。pull_to_refresh库和waterfall_flow库的使用是实现这些功能的关键,合理地设置各种属性和回调函数,让页面具备了良好的交互性和美观的布局效果。希望这篇文章能帮助你理解并在自己的 Flutter 项目中运用类似的功能。
本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~
往期文章
个人主页