分享一下结合getx实现瀑布流
来源:6-6 基于StaggeredGridView封装首页双Feed列表

weixin_慕神9322259
2025-05-07
跟着老师的课一步步写代码,但是想着能更有效的学习,于是自己引入了getx状态管理库做一些魔改。
选择getx的原因,我喜欢getx这种把状态都放在controller里,然后在stateless widget里就可以专注UI部分(getx可以不需要statefull widget),状态和UI两块分开,代码就比较清晰明了,而且getx还提供route和依赖注入的功能,我的背景是后端开发,所以我比较喜欢这种做法。
这里分享一下自己的基于getx的瀑布流解决方案。
首先,让我们对数据做一下抽象,本质上我们需要一个可分页的数据,使用getx,我们可以把分页的数据都塞在controller里,然后对于数据的获取和重置,都写成方法,非常易懂。
abstract class BasePagedController<T> extends GetxController {
final RxList<T> data = <T>[].obs;
final RxInt currentPage = 1.obs;
final RxBool isLoading = false.obs;
final RxBool hasMore = true.obs;
final int pageSize = 10;
Future<List<T>> loadData(int page, int pageSize);
@override
void onInit() {
super.onInit();
loadMore();
}
Future<void> loadMore() async {
if (isLoading.value || !hasMore.value) return;
isLoading.value = true;
print("loading more... currentPage: $currentPage");
try {
final newItems = await loadData(currentPage.value, pageSize);
if (newItems.isEmpty) {
hasMore.value = false;
} else {
data.addAll(newItems);
currentPage.value++;
}
} catch (e) {
Get.snackbar('错误', '加载数据失败: $e');
} finally {
isLoading.value = false;
}
}
Future<void> refreshData() async {
currentPage.value = 1;
hasMore.value = true;
data.clear();
await loadMore();
}
}
对于video的瀑布流,我们需要的就是能够获取分页的video model,所以继承一下上面的抽象类,实现一下loadData即可
class VideoPagedController extends BasePagedController<VideoModel> {
final String categoryName;
VideoPagedController({required this.categoryName});
@override
Future<List<VideoModel>> loadData(int page, int pageSize) async {
final HomeModel homeData = await HomeDao.get(
categoryName,
pageIndex: page,
pageSize: pageSize
);
return homeData.videoList?? [];
}
}
数据状态的部分完成了,现在我们搞一个瀑布流页面。
class CommonWaterfallGridView<T> extends StatelessWidget {
final BasePagedController<T> controller;
final Widget Function(T item) itemBuilder;
final int crossAxisCount;
final double crossAxisSpacing;
final double mainAxisSpacing;
final Widget? banner; // banner作为可选
const CommonWaterfallGridView({
super.key,
required this.controller,
required this.itemBuilder,
this.crossAxisCount = 2,
this.crossAxisSpacing = 4,
this.mainAxisSpacing = 4,
this.banner,
});
@override
Widget build(BuildContext context) {
return Obx(() {
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
// 判断是否滑动到底部
if (scrollInfo.metrics.pixels ==
scrollInfo.metrics.maxScrollExtent) {
controller.loadMore();
}
return false;
},
child: CustomScrollView(
slivers: [
// 顶部Banner
if (banner != null) SliverPadding(padding: EdgeInsets.only(top: 5), sliver: SliverToBoxAdapter(child: banner),),
// 瀑布流主体
SliverPadding(
padding: EdgeInsets.only(top: 10),
sliver: SliverMasonryGrid.count(
crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childCount: controller.data.length,
itemBuilder: (context, index) {
return itemBuilder(controller.data[index]);
},
),
),
// 底部加载指示器
SliverToBoxAdapter(
child: controller.hasMore.value
? _defaultLoadingIndicator()
: const SizedBox(), // TODO: 如果没有数据了,做一个提示? 可以作为field,让调用方自己决定
),
],
),
);
});
}
Widget _defaultLoadingIndicator() {
return const Padding(
padding: EdgeInsets.all(16.0),
child: Center(child: CircularProgressIndicator()),
);
}
}
回到我们的home_tab_page,只需要复用CommonWaterfallGridView即可,这里代码就很简单了。
class HomeTabPage extends StatelessWidget {
final String name;
final List<BannerModel>? bannerList;
const HomeTabPage({super.key, required this.name, this.bannerList});
@override
Widget build(BuildContext context) {
final VideoPagedController videoPagedController = Get.put(VideoPagedController(categoryName: name));
return CommonWaterfallGridView(
controller: videoPagedController,
banner: _banner(),
itemBuilder: (videoModel) => VideoCard(videoMo: videoModel),
);
}
_banner() => Padding(
padding: EdgeInsets.only(left: 8, right: 8),
child: HiBanner(bannerList!),
);
}
我看了一些状态管理库,比如provider, getx, signals。我的感受是flutter在状态管理库这里,没有一个比较统一的解决方案,类似spring在java中的地位。所以对于初学者,该选择什么学习,开发项目,就挺迷茫的。不过想了想,有时候技术并不重要,我们到底要做一个什么样的App,这个App的功能是否价值才是最重要的,所以对于初学者纠结这么多干嘛呢,挑一个喜欢的库能实现需求就够了,技术选型这种终极问题,等真的遇到了实际问题再说吧
1回答
-
CrazyCodeBoy
2025-05-08
很棒。
想要用getx做状态管理的小伙伴,也可以看下这个课程
https://coding.imooc.com/class/741.html00
相似问题