diff --git a/lib/controller/discover/visitor_controller.dart b/lib/controller/discover/visitor_controller.dart index 8ff3a63..f8c5c44 100644 --- a/lib/controller/discover/visitor_controller.dart +++ b/lib/controller/discover/visitor_controller.dart @@ -1,6 +1,6 @@ // controllers/visitor_controller.dart +import 'package:easy_refresh/easy_refresh.dart'; import 'package:get/get.dart'; -import 'package:pull_to_refresh/pull_to_refresh.dart'; import '../../model/discover/visitor_model.dart'; class VisitorController extends GetxController { @@ -8,8 +8,10 @@ class VisitorController extends GetxController { var visitors = [].obs; // Refresh controllers - final RefreshController refreshController = RefreshController(); - // final RefreshController loadMoreController = RefreshController(); + final EasyRefreshController refreshController = EasyRefreshController( + controlFinishRefresh: true, + controlFinishLoad: true, + ); // 分页参数 var currentPage = 1.obs; @@ -45,22 +47,19 @@ class VisitorController extends GetxController { final newVisitors = _generateMockData(1, pageSize); visitors.assignAll(newVisitors); - refreshController.refreshCompleted(); + refreshController.finishRefresh(); + refreshController.resetFooter(); hasMore.value = newVisitors.length == pageSize; if (newVisitors.isEmpty) { - refreshController.loadNoData(); - } else { - refreshController.loadComplete(); + hasMore.value = false; } - print(56); } // 上拉加载更多 void onLoadMore() async { print('onLoadMore'); if (!hasMore.value) { - refreshController.loadNoData(); return; } @@ -72,11 +71,11 @@ class VisitorController extends GetxController { if (newVisitors.isEmpty) { hasMore.value = false; - refreshController.loadNoData(); + refreshController.finishLoad(IndicatorResult.noMore); } else { visitors.addAll(newVisitors); - refreshController.loadComplete(); - hasMore.value = true; + // hasMore.value = true; + refreshController.finishLoad(IndicatorResult.success); } } @@ -147,7 +146,6 @@ class VisitorController extends GetxController { @override void onClose() { refreshController.dispose(); - // loadMoreController.dispose(); super.onClose(); } } \ No newline at end of file diff --git a/lib/pages/discover/visitor_list_page.dart b/lib/pages/discover/visitor_list_page.dart index 4aa5c36..69ca6f4 100644 --- a/lib/pages/discover/visitor_list_page.dart +++ b/lib/pages/discover/visitor_list_page.dart @@ -1,10 +1,10 @@ // pages/visitor_list_page.dart import 'package:cached_network_image/cached_network_image.dart'; import 'package:dating_touchme_app/extension/ex_widget.dart'; +import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:pull_to_refresh/pull_to_refresh.dart'; import '../../controller/discover/visitor_controller.dart'; import '../../model/discover/visitor_model.dart'; @@ -89,47 +89,45 @@ class _VisitorListPagePageState extends State { ); } - return SmartRefresher( + return EasyRefresh( controller: visitorController.refreshController, - enablePullDown: true, - enablePullUp: true, onRefresh: visitorController.onRefresh, - onLoading: visitorController.onLoadMore, + onLoad: visitorController.onLoadMore, header: ClassicHeader( - idleText: '下拉刷新', - releaseText: '松开刷新', - refreshingText: '刷新中...', - completeText: '刷新完成', + dragText: '下拉刷新', + armedText: '释放刷新', + readyText: '刷新中...', + processingText: '刷新中...', + processedText: '刷新完成', failedText: '刷新失败', - height: 60, + noMoreText: '没有更多数据', + messageText: '更新时间 %T', + showMessage: false ), - footer: CustomFooter( - builder: (BuildContext context, LoadStatus? mode) { - Widget body; - if (mode == LoadStatus.idle) { - body = Text("上拉加载更多"); - } else if (mode == LoadStatus.loading) { - body = SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2,)); - } else if (mode == LoadStatus.failed) { - body = Text("加载失败,点击重试"); - } else if (mode == LoadStatus.canLoading) { - body = Text("松开加载更多"); - } else { - body = Text("没有更多数据了"); - } - return SizedBox( - height: 36, - child: Center(child: body), - ); - }, + footer: ClassicFooter( + dragText: '上拉加载', + armedText: '释放加载', + readyText: '加载中...', + processingText: '加载中...', + processedText: '加载完成', + failedText: '加载失败', + noMoreText: '没有更多数据', + showMessage: false ), - child: ListView.builder( - padding: const EdgeInsets.only(top: 8, right: 10, left: 10), + child: ListView.separated( + padding: const EdgeInsets.only(top: 10, right: 10, left: 10), itemCount: visitorController.visitors.length, itemBuilder: (context, index) { final visitor = visitorController.visitors[index]; return VisitorListItem(visitor: visitor); }, + separatorBuilder: (context, index) { + // 空状态或加载状态时不显示分隔符 + if (visitorController.visitors.isEmpty) { + return const SizedBox.shrink(); + } + return const SizedBox(height: 10); + }, ), ); }), @@ -206,7 +204,6 @@ class VisitorListItem extends StatelessWidget { borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.all(12), - margin: EdgeInsets.only(bottom: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ diff --git a/lib/pages/home/nearby_tab.dart b/lib/pages/home/nearby_tab.dart index e82b006..b4c5ff3 100644 --- a/lib/pages/home/nearby_tab.dart +++ b/lib/pages/home/nearby_tab.dart @@ -1,8 +1,7 @@ +import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:dating_touchme_app/controller/home/home_controller.dart'; -import 'package:dating_touchme_app/model/home/marriage_data.dart'; import 'package:dating_touchme_app/pages/home/content_card.dart'; /// 同城列表 Tab @@ -13,15 +12,14 @@ class NearbyTab extends StatefulWidget { State createState() => _NearbyTabState(); } -class _NearbyTabState extends State - with AutomaticKeepAliveClientMixin { +class _NearbyTabState extends State with AutomaticKeepAliveClientMixin { final HomeController controller = Get.find(); - late final RefreshController _refreshController; + late final EasyRefreshController _refreshController; @override void initState() { super.initState(); - _refreshController = RefreshController(initialRefresh: false); + _refreshController = EasyRefreshController(controlFinishRefresh: true, controlFinishLoad: true); } @override @@ -39,96 +37,90 @@ class _NearbyTabState extends State final totalBottomPadding = bottomPadding + tabBarHeight; return Obx(() { - final List dataSource = controller.nearbyFeed; - final bool hasMore = controller.nearbyHasMore.value; - - return SmartRefresher( + return EasyRefresh( controller: _refreshController, - enablePullDown: true, - enablePullUp: true, header: const ClassicHeader( - refreshingText: '正在刷新...', - completeText: '刷新完成', - idleText: '下拉刷新', - releaseText: '释放刷新', + dragText: '下拉刷新', + armedText: '释放刷新', + readyText: '刷新中...', + processingText: '刷新中...', + processedText: '刷新完成', + failedText: '刷新失败', + noMoreText: '没有更多数据', + showMessage: false ), footer: ClassicFooter( - idleText: '上拉加载', - loadingText: '正在加载...', - noDataText: '没有更多数据', - canLoadingText: '释放加载', + dragText: '上拉加载', + armedText: '释放加载', + readyText: '加载中...', + processingText: '加载中...', + processedText: '加载完成', + failedText: '加载失败', + noMoreText: '没有更多数据', + showMessage: false ), // 下拉刷新 onRefresh: () async { print('同城列表下拉刷新被触发'); try { await controller.refreshNearbyData(); - _refreshController.refreshCompleted(); + _refreshController.finishRefresh(); + _refreshController.resetFooter(); print('同城列表刷新完成'); } catch (e) { print('同城列表刷新失败: $e'); - _refreshController.refreshFailed(); + _refreshController.finishRefresh(IndicatorResult.fail); } }, // 上拉加载更多 - onLoading: () async { - print('同城列表上拉加载被触发, hasMore: $hasMore'); - if (hasMore && controller.nearbyHasMore.value) { - try { - await controller.loadNearbyMoreData(); - // 完成加载,根据是否有更多数据决定 - if (controller.nearbyHasMore.value) { - _refreshController.loadComplete(); - print('同城列表加载更多成功'); - } else { - _refreshController.loadNoData(); - print('同城列表没有更多数据了'); - } - } catch (e) { - print('同城列表加载更多失败: $e'); - _refreshController.loadFailed(); + onLoad: () async { + print('同城列表上拉加载被触发, hasMore: ${controller.nearbyHasMore.value}'); + try { + await controller.loadNearbyMoreData(); + // 完成加载,根据是否有更多数据决定 + if (controller.nearbyHasMore.value) { + _refreshController.finishLoad(IndicatorResult.success); + print('同城列表加载更多成功'); + } else { + _refreshController.finishLoad(IndicatorResult.noMore); + print('同城列表没有更多数据了'); } - } else { - _refreshController.loadNoData(); - print('同城列表没有更多数据'); + } catch (e) { + print('同城列表加载更多失败: $e'); + _refreshController.finishLoad(IndicatorResult.fail); } }, - child: ListView.separated( - // 关键:始终允许滚动,即使内容不足 - physics: const AlwaysScrollableScrollPhysics( - parent: BouncingScrollPhysics(), - ), - // 移除顶部 padding,让刷新指示器可以正确显示在 AppBar 下方 - padding: EdgeInsets.only( - left: 12, - right: 12, - bottom: totalBottomPadding + 12, - ), - itemBuilder: (context, index) { - // 空数据状态 - if (dataSource.isEmpty && index == 0) { - // 使用足够的高度确保可以滚动 - return SizedBox( - height: MediaQuery.of(context).size.height * 1.2, - child: const Center( - child: Text( - "暂无数据", - style: TextStyle(fontSize: 14, color: Color(0xFF999999)), + child: SizedBox( + height: MediaQuery.of(context).size.height - totalBottomPadding, + child: ListView.separated( + // 移除顶部 padding,让刷新指示器可以正确显示在 AppBar 下方 + padding: EdgeInsets.only(left: 12, right: 12, bottom: 12), + itemBuilder: (context, index) { + // 空数据状态 + if (controller.nearbyFeed.isEmpty && index == 0) { + // 使用足够的高度确保可以滚动 + return SizedBox( + height: MediaQuery.of(context).size.height - totalBottomPadding, + child: const Center( + child: Text( + "暂无数据", + style: TextStyle(fontSize: 14, color: Color(0xFF999999)), + ), ), - ), - ); - } - // 数据项 - final item = dataSource[index]; - return ContentCard(item: item); - }, - separatorBuilder: (context, index) { - // 空状态或加载状态时不显示分隔符 - if (dataSource.isEmpty) return const SizedBox.shrink(); - return const SizedBox(height: 12); - }, - // 至少显示一个 item(用于显示加载或空状态) - itemCount: dataSource.isEmpty ? 1 : dataSource.length, + ); + } + // 数据项 + final item = controller.nearbyFeed[index]; + return ContentCard(item: item); + }, + separatorBuilder: (context, index) { + // 空状态或加载状态时不显示分隔符 + if (controller.nearbyFeed.isEmpty) return const SizedBox.shrink(); + return const SizedBox(height: 12); + }, + // 至少显示一个 item(用于显示加载或空状态) + itemCount: controller.nearbyFeed.isEmpty ? 1 : controller.nearbyFeed.length, + ) ), ); }); @@ -136,4 +128,5 @@ class _NearbyTabState extends State @override bool get wantKeepAlive => true; + } diff --git a/lib/pages/home/recommend_tab.dart b/lib/pages/home/recommend_tab.dart index f14ed10..b6cfb19 100644 --- a/lib/pages/home/recommend_tab.dart +++ b/lib/pages/home/recommend_tab.dart @@ -1,8 +1,7 @@ +import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:dating_touchme_app/controller/home/home_controller.dart'; -import 'package:dating_touchme_app/model/home/marriage_data.dart'; import 'package:dating_touchme_app/pages/home/content_card.dart'; /// 推荐列表 Tab @@ -16,12 +15,12 @@ class RecommendTab extends StatefulWidget { class _RecommendTabState extends State with AutomaticKeepAliveClientMixin { final HomeController controller = Get.find(); - late final RefreshController _refreshController; + late final EasyRefreshController _refreshController; @override void initState() { super.initState(); - _refreshController = RefreshController(initialRefresh: false); + _refreshController = EasyRefreshController(controlFinishRefresh: true, controlFinishLoad: true); } @override @@ -37,77 +36,71 @@ class _RecommendTabState extends State final bottomPadding = MediaQuery.of(context).padding.bottom; final tabBarHeight = 64.0; final totalBottomPadding = bottomPadding + tabBarHeight; - return SizedBox( - height: MediaQuery.of(context).size.height - totalBottomPadding, - child: Obx(() { - final List dataSource = controller.recommendFeed; - - return SmartRefresher( - controller: _refreshController, - enablePullDown: true, - enablePullUp: true, - physics: const ClampingScrollPhysics(), - header: const ClassicHeader( - refreshingText: '正在刷新...', - completeText: '刷新完成', - idleText: '下拉刷新', - releaseText: '释放刷新', - ), - footer: ClassicFooter( - idleText: '上拉加载', - loadingText: '正在加载...', - noDataText: '没有更多数据', - canLoadingText: '释放加载', - ), - // 下拉刷新 - onRefresh: () async { - print('推荐列表下拉刷新被触发'); - try { - await controller.refreshRecommendData(); - print('推荐列表刷新完成, hasMore: $controller.recommendHasMore.value'); - _refreshController.refreshCompleted(); - _refreshController.loadComplete(); - } catch (e) { - print('推荐列表刷新失败: $e'); - _refreshController.refreshFailed(); - } - }, - // 上拉加载更多 - onLoading: () async { - print('推荐列表上拉加载被触发, hasMore: $controller.recommendHasMore.value'); + return Obx(() { + return EasyRefresh( + controller: _refreshController, + header: const ClassicHeader( + dragText: '下拉刷新', + armedText: '释放刷新', + readyText: '刷新中...', + processingText: '刷新中...', + processedText: '刷新完成', + failedText: '刷新失败', + noMoreText: '没有更多数据', + showMessage: false + ), + footer: ClassicFooter( + dragText: '上拉加载', + armedText: '释放加载', + readyText: '加载中...', + processingText: '加载中...', + processedText: '加载完成', + failedText: '加载失败', + noMoreText: '没有更多数据', + showMessage: false + ), + // 下拉刷新 + onRefresh: () async { + print('推荐列表下拉刷新被触发'); + try { + await controller.refreshRecommendData(); + print( '推荐列表刷新完成, hasMore: $controller.recommendHasMore.value'); + _refreshController.finishRefresh(); + _refreshController.resetFooter(); + } catch (e) { + print('推荐列表刷新失败: $e'); + _refreshController.finishRefresh(IndicatorResult.fail); + } + }, + // 上拉加载更多 + onLoad: () async { + print('推荐列表上拉加载被触发, hasMore: $controller.recommendHasMore.value'); + try { + await controller.loadRecommendMoreData(); + // 完成加载,根据是否有更多数据决定 if (controller.recommendHasMore.value) { - try { - await controller.loadRecommendMoreData(); - // 完成加载,根据是否有更多数据决定 - if (controller.recommendHasMore.value) { - _refreshController.loadComplete(); - print('推荐列表加载更多成功'); - } else { - _refreshController.loadNoData(); - print('推荐列表没有更多数据了'); - } - } catch (e) { - print('推荐列表加载更多失败: $e'); - _refreshController.loadFailed(); - } + _refreshController.finishLoad(IndicatorResult.success); + print('推荐列表加载更多成功'); } else { - _refreshController.loadNoData(); - print('推荐列表没有更多数据'); + _refreshController.finishLoad(IndicatorResult.noMore); + print('推荐列表没有更多数据了'); } - }, + } catch (e) { + print('推荐列表加载更多失败: $e'); + _refreshController.finishLoad(IndicatorResult.fail); + } + }, + child: SizedBox( + height: MediaQuery.of(context).size.height - totalBottomPadding, child: ListView.separated( - // 关键:始终允许滚动,即使内容不足 - // 移除顶部 padding,让刷新指示器可以正确显示在 AppBar 下方 - padding: EdgeInsets.only( - left: 12, - right: 12, - bottom: 12, - ), + // 关键:始终允许滚动,即使内容不足 + // 移除顶部 padding,让刷新指示器可以正确显示在 AppBar 下方 + padding: EdgeInsets.only(left: 12, right: 12, bottom: 12), itemBuilder: (context, index) { - // 空数据状态 - if (dataSource.isEmpty && index == 0) { - // 使用足够的高度确保可以滚动 - if(controller.recommendIsLoading.value){ + // 空数据状态 + if (controller.recommendFeed.isEmpty && index == 0) { + // 使用足够的高度确保可以滚动 + if (controller.recommendIsLoading.value) { return SizedBox( height: MediaQuery.of(context).size.height - totalBottomPadding, child: Center( @@ -134,20 +127,22 @@ class _RecommendTabState extends State } } // 数据项 - final item = dataSource[index]; + final item = controller.recommendFeed[index]; return ContentCard(item: item); }, separatorBuilder: (context, index) { - // 空状态或加载状态时不显示分隔符 - if (dataSource.isEmpty) return const SizedBox.shrink(); + // 空状态或加载状态时不显示分隔符 + if (controller.recommendFeed.isEmpty) { + return const SizedBox.shrink(); + } return const SizedBox(height: 12); }, // 至少显示一个 item(用于显示加载或空状态) - itemCount: dataSource.isEmpty ? 1 : dataSource.length, - ), - ); - }), - ); + itemCount: controller.recommendFeed.isEmpty ? 1 : controller.recommendFeed.length, + ) + ), + ); + }); } @override diff --git a/lib/pages/mine/mine_page.dart b/lib/pages/mine/mine_page.dart index 8cf1d17..9ff3512 100644 --- a/lib/pages/mine/mine_page.dart +++ b/lib/pages/mine/mine_page.dart @@ -79,7 +79,14 @@ class _MinePageState extends State with AutomaticKeepAliveClientMixin{ imageUrl: "${controller.userData.value?.profilePhoto ?? ""}?x-oss-process=image/format,webp/resize,w_120", width: 60.w, height: 60.w, - fit: BoxFit.cover, + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), ) : Image.asset( Assets.imagesUserAvatar, width: 60.w, diff --git a/pubspec.yaml b/pubspec.yaml index 655924f..c373d63 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,6 +53,7 @@ dependencies: permission_handler: ^12.0.1 flustars: ^2.0.1 easy_refresh: ^3.4.0 + keframe: ^3.0.0 # 分帧组件 cached_network_image: ^3.4.1 # 图片加载 extended_image: ^9.0.4 # 图片查看器 wechat_assets_picker: ^9.8.0 @@ -68,7 +69,6 @@ dependencies: # fluwx: ^5.7.5 # tobias: ^5.3.1 agora_rtc_engine: ^6.5.3 - pull_to_refresh: ^2.0.0 agora_rtm: ^2.2.5 agora_token_generator: ^1.0.0 location_plugin: