diff --git a/lib/pages/index/index.dart b/lib/pages/index/index.dart index 7340ab4..b626e96 100644 --- a/lib/pages/index/index.dart +++ b/lib/pages/index/index.dart @@ -543,16 +543,6 @@ class _IndexPageState extends State with TickerProviderStateMixin { SliverToBoxAdapter( child: Obx( () { - // if (isInitLoading.value) { - // return Column( - // children: [ - // RefreshProgressIndicator( - // backgroundColor: Colors.white, - // color: Color(0xFFFF5000), - // ), - // ], - // ); - // } if (dataList.isEmpty) { return EmptyTip(); } diff --git a/lib/pages/my/index.dart b/lib/pages/my/index.dart index ef65710..088bdb7 100644 --- a/lib/pages/my/index.dart +++ b/lib/pages/my/index.dart @@ -28,7 +28,7 @@ import '../../utils/common.dart'; class PageParams { int page; int pageSize; - bool isLoading; + RxBool isLoading; RxBool hasMore; int total; bool isInitLoading; @@ -36,16 +36,21 @@ class PageParams { PageParams({ this.page = 1, this.pageSize = 10, - this.isLoading = false, + bool isLoading = false, bool hasMore = true, this.total = 0, this.isInitLoading = true, - }) : hasMore = hasMore.obs; + }) : hasMore = hasMore.obs, + isLoading = isLoading.obs; + @override + String toString() { + return 'PageParams(page: $page, pageSize: $pageSize, isLoading: ${isLoading.value}, hasMore: ${hasMore.value})'; + } void init() { page = 1; pageSize = 10; - isLoading = false; + isLoading.value = false; hasMore.value = true; total = 0; isInitLoading = true; @@ -98,16 +103,16 @@ class MyPageState extends State with SingleTickerProviderStateMixin { super.initState(); imUserInfoController = Get.find(); initControllers(); - + // 这里保证委托父类处理滚动时的触底加载 scrollListener = () { final pos = scrollController.position; final isNearBottom = pos.pixels >= pos.maxScrollExtent - 100; if (!isNearBottom) return; - if (currentTabIndex.value == 0 && !itemsParams.isLoading && itemsParams.hasMore.value) { + if (currentTabIndex.value == 0 && !itemsParams.isLoading.value && itemsParams.hasMore.value) { loadData(0); - } else if (currentTabIndex.value == 1 && !favoriteParams.isLoading && favoriteParams.hasMore.value) { + } else if (currentTabIndex.value == 1 && !favoriteParams.isLoading.value && favoriteParams.hasMore.value) { loadData(1); } }; @@ -124,8 +129,6 @@ class MyPageState extends State with SingleTickerProviderStateMixin { } }; tabController.addListener(tabListener); - - // loadData(0); } @override @@ -165,10 +168,10 @@ class MyPageState extends State with SingleTickerProviderStateMixin { Future loadData([int? tabIndex]) async { final index = tabIndex ?? currentTabIndex.value; if (index == 0) { - if (itemsParams.isLoading || !itemsParams.hasMore.value) return; - - itemsParams.isLoading = true; - // itemsParams.isInitLoading = true; + if (itemsParams.isLoading.value || !itemsParams.hasMore.value) return; + WidgetsBinding.instance.addPostFrameCallback((_) { + itemsParams.isLoading.value = true; + }); final res = await Http.post(VideoApi.myPublicList, data: { "userId": imUserInfoController.userID.value, @@ -179,25 +182,22 @@ class MyPageState extends State with SingleTickerProviderStateMixin { final obj = res['data']; final total = obj['total']; final row = obj['records'] ?? []; - logger.i(res['data']); // 判断是否还有更多数据 logger.e(items.length); // 添加新数据,触发响应式更新 items.addAll(row); - logger.e(obj); + itemsParams.page++; + if (items.length >= total) { itemsParams.hasMore.value = false; } - // 页码加一 - itemsParams.page++; - // - itemsParams.isLoading = false; + itemsParams.isLoading.value = false; itemsParams.isInitLoading = false; } else if (index == 1) { - if (favoriteParams.isLoading || !favoriteParams.hasMore.value) return; - - favoriteParams.isLoading = true; - // favoriteParams.isInitLoading = true; + if (favoriteParams.isLoading.value || !favoriteParams.hasMore.value) return; + WidgetsBinding.instance.addPostFrameCallback((_) { + favoriteParams.isLoading.value = true; + }); final res = await Http.post(VideoApi.myLikedList, data: { "userId": imUserInfoController.userID.value, @@ -209,14 +209,14 @@ class MyPageState extends State with SingleTickerProviderStateMixin { final total = obj['total']; final row = obj['records'] ?? []; favoriteItems.addAll(row); + favoriteParams.page++; if (favoriteItems.length >= total) { favoriteParams.hasMore.value = false; } - - favoriteParams.page++; - favoriteParams.isLoading = false; + favoriteParams.isLoading.value = false; favoriteParams.isInitLoading = false; + logger.e(favoriteParams.toString()); } } @@ -583,46 +583,65 @@ class MyPageState extends State with SingleTickerProviderStateMixin { if (listToShow.isEmpty) { return emptyTip('暂无相关数据'); } - return CustomScrollView( - // physics: !isPinned.value ? NeverScrollableScrollPhysics() : AlwaysScrollableScrollPhysics(), - // physics: AlwaysScrollableScrollPhysics(), - key: PageStorageKey('myindex_$tabIndex'), - slivers: [ - SliverPadding( - padding: EdgeInsets.all(10.0), - sliver: SliverGrid( - delegate: SliverChildBuilderDelegate( - (context, index) { - return Container( - decoration: BoxDecoration( - color: Colors.blue[100 * ((index % 8) + 1)], - borderRadius: BorderRadius.circular(10.0), - ), - alignment: Alignment.center, - child: _buildVdCard(listToShow[index], tabIndex), - ); - }, - childCount: listToShow.length, - ), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - crossAxisSpacing: 10.0, - mainAxisSpacing: 10.0, - childAspectRatio: 0.6, - ), - ), - ), - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 20.0), - child: Center( - child: Obx( - () => params.hasMore.value ? CircularProgressIndicator() : Text('没有更多数据了'), + return NotificationListener( + onNotification: (notification) { + if (notification is ScrollUpdateNotification) { + final metrics = notification.metrics; + final isNearBottom = metrics.pixels == metrics.maxScrollExtent; + + if (isNearBottom && !params.isLoading.value && params.hasMore.value) { + loadData(tabIndex); + } + } + return false; + }, + child: CustomScrollView( + key: PageStorageKey('myindex_$tabIndex'), + slivers: [ + SliverPadding( + padding: EdgeInsets.all(10.0), + sliver: SliverGrid( + delegate: SliverChildBuilderDelegate( + (context, index) { + return Container( + decoration: BoxDecoration( + color: Colors.blue[100 * ((index % 8) + 1)], + borderRadius: BorderRadius.circular(10.0), + ), + alignment: Alignment.center, + child: _buildVdCard(listToShow[index], tabIndex), + ); + }, + childCount: listToShow.length, + ), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 10.0, + mainAxisSpacing: 10.0, + childAspectRatio: 0.6, ), ), ), - ), - ], + SliverToBoxAdapter( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 20.0), + child: Center( + child: Obx( + () { + if (params.isLoading.value) { + return SafeArea(top: false, child: CircularProgressIndicator()); + } else if (!params.hasMore.value) { + return SafeArea(top: false, child: Text('没有更多数据了')); + } else { + return SizedBox(height: 20); + } + }, + ), + ), + ), + ), + ], + ), ); } diff --git a/lib/pages/my/vloger.dart b/lib/pages/my/vloger.dart index 5f72cd8..773e960 100644 --- a/lib/pages/my/vloger.dart +++ b/lib/pages/my/vloger.dart @@ -23,15 +23,20 @@ import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart'; class PageParams { int page; int pageSize; - bool isLoading; - bool hasMore; + RxBool isLoading; + RxBool hasMore; PageParams({ this.page = 1, - this.pageSize = 10, - this.isLoading = false, - this.hasMore = true, - }); + this.pageSize = 12, + bool isLoading = false, + bool hasMore = true, + }) : hasMore = hasMore.obs, + isLoading = isLoading.obs; + @override + String toString() { + return 'PageParams(page: $page, pageSize: $pageSize, isLoading: ${isLoading.value}, hasMore: ${hasMore.value})'; + } } class Vloger extends StatefulWidget { @@ -67,7 +72,7 @@ class MyPageState extends State with SingleTickerProviderStateMixin { )); RxBool get shouldFixHeader => (currentTabIndex.value == 0 && items.isEmpty) || (currentTabIndex.value == 1 && favoriteItems.isEmpty) ? true.obs : false.obs; - + RxInt totalCount = 0.obs; List tabList = [ {'name': "作品"}, ]; @@ -85,24 +90,21 @@ class MyPageState extends State with SingleTickerProviderStateMixin { void initState() { super.initState(); args = Get.arguments ?? {}; - print('argsssssssssssssssssssssss$args'); + logger.e(args); itemsParams = PageParams(); favoriteParams = PageParams(); selfInfo(); flowInfo(); checkFollowType(); initControllers(); - + // 这里保证委托父类处理滚动时的触底加载 scrollListener = () { final pos = scrollController.position; final isNearBottom = pos.pixels >= pos.maxScrollExtent - 100; - if (!isNearBottom) return; - if (currentTabIndex.value == 0 && !itemsParams.isLoading && itemsParams.hasMore) { + if (currentTabIndex.value == 0 && !itemsParams.isLoading.value && itemsParams.hasMore.value) { loadData(0); - } else if (currentTabIndex.value == 1 && !favoriteParams.isLoading && favoriteParams.hasMore) { - loadData(1); } }; scrollController.addListener(scrollListener); @@ -133,18 +135,27 @@ class MyPageState extends State with SingleTickerProviderStateMixin { void getUserLikesCount() async { try { final resData = await Http.get('${CommonApi.accountInfo}?memberId=${args['memberId']}'); - print('aaaaaaaaaaaaaaaaaaa$resData'); + logger.e('$resData'); if (resData != null && resData['code'] == 200) { vlogLikeCount = resData['data']['vlogLikeCount'] ?? 0; } - } catch (e) {} + } catch (e) { + logger.e(e); + } } void loadData([int? tabIndex]) async { final index = tabIndex ?? currentTabIndex.value; if (index == 0) { - if (itemsParams.isLoading || !itemsParams.hasMore) return; - itemsParams.isLoading = true; + if (itemsParams.isLoading.value || !itemsParams.hasMore.value) return; + WidgetsBinding.instance.addPostFrameCallback((_) { + itemsParams.isLoading.value = true; + }); + + // await Future.delayed(Duration(seconds: 5), () { + // logger.e('5秒后执行完毕'); + // }); + final res = await Http.post(VideoApi.getVideoListByMemberId, data: { "memberId": args['memberId'], "current": itemsParams.page, @@ -153,19 +164,20 @@ class MyPageState extends State with SingleTickerProviderStateMixin { final obj = res['data']; final total = obj['total']; final row = obj['records'] ?? []; - logger.i(res['data']); + // logger.i(res['data']); + totalCount.value = total; // 判断是否还有更多数据 logger.e(items.length); // 添加新数据,触发响应式更新 items.addAll(row); - logger.e(obj); - if (items.length >= total) { - itemsParams.hasMore = false; - } - // 页码加一 itemsParams.page++; - // - itemsParams.isLoading = false; + + if (items.length >= total) { + itemsParams.hasMore.value = false; + } + itemsParams.isLoading.value = false; + + logger.e(itemsParams.toString()); } } @@ -418,14 +430,20 @@ class MyPageState extends State with SingleTickerProviderStateMixin { controller: tabController, tabs: tabList.map((item) { return Tab( - child: Badge.count( - backgroundColor: Colors.red, - count: item['badge'] ?? 0, - isLabelVisible: item['badge'] != null, - alignment: Alignment.topRight, - offset: const Offset(14, -6), - child: Text(item['name'], style: const TextStyle(fontWeight: FontWeight.bold)), + child: Obx( + () => Text( + '${item['name']}(${totalCount.value})', + style: TextStyle(fontWeight: FontWeight.bold), + ), ), + // child: Badge.count( + // backgroundColor: Colors.red, + // count: item['badge'] ?? 0, + // isLabelVisible: item['badge'] != null, + // alignment: Alignment.topRight, + // offset: const Offset(14, -6), + // child: Text(item['name'], style: const TextStyle(fontWeight: FontWeight.bold)), + // ), ); }).toList(), isScrollable: true, //禁止左右滑动 @@ -496,111 +514,133 @@ class MyPageState extends State with SingleTickerProviderStateMixin { if (listToShow.isEmpty) { return emptyTip('暂无相关数据'); } + return NotificationListener( + onNotification: (notification) { + if (notification is ScrollUpdateNotification) { + final metrics = notification.metrics; + final isNearBottom = metrics.pixels >= metrics.maxScrollExtent; - return CustomScrollView( - slivers: [ - SliverPadding( - padding: const EdgeInsets.all(10.0), - sliver: SliverGrid( - delegate: SliverChildBuilderDelegate( - (context, index) { - final item = listToShow[index]; - return GestureDetector( - onTap: () { - // 点击跳转到视频播放详情页面 - Get.toNamed('/videoDetail', arguments: {'videoId': item['id']}); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: Stack( - fit: StackFit.expand, - children: [ - // 视频封面图片 - NetworkOrAssetImage( - imageUrl: item['firstFrameImg'] ?? item['cover'], - width: double.infinity, - height: double.infinity, - fit: BoxFit.cover, - placeholderAsset: 'assets/images/bk.jpg', - ), - // 半透明渐变底部背景 - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - height: 40, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - colors: [ - Colors.black.withOpacity(0.6), - Colors.transparent, - ], - ), - ), - ), - ), - // 右下角点赞数 - Positioned( - right: 8, - bottom: 8, - child: Row( - children: [ - const Icon( - Icons.favorite, - color: Colors.white, - size: 16, - ), - const SizedBox(width: 4), - Text( - '${item['likeCounts'] ?? 0}', - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), + if (isNearBottom && !params.isLoading.value && params.hasMore.value) { + loadData(0); + } + } + return false; + }, + child: CustomScrollView( + slivers: [ + SliverPadding( + padding: const EdgeInsets.all(10.0), + sliver: SliverGrid( + delegate: SliverChildBuilderDelegate( + (context, index) { + final item = listToShow[index]; + return GestureDetector( + onTap: () { + // 点击跳转到视频播放详情页面 + Get.toNamed('/videoDetail', arguments: {'videoId': item['id']}); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 4, + offset: const Offset(0, 2), ), ], ), + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: Stack( + fit: StackFit.expand, + children: [ + // 视频封面图片 + NetworkOrAssetImage( + imageUrl: item['firstFrameImg'] ?? item['cover'], + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + placeholderAsset: 'assets/images/bk.jpg', + ), + // 半透明渐变底部背景 + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + height: 40, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + Colors.black.withOpacity(0.6), + Colors.transparent, + ], + ), + ), + ), + ), + // 右下角点赞数 + Positioned( + right: 8, + bottom: 8, + child: Row( + children: [ + const Icon( + Icons.favorite, + color: Colors.white, + size: 16, + ), + const SizedBox(width: 4), + Text( + '${item['likeCounts'] ?? 0}', + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + ), ), - ), - ); - }, - childCount: listToShow.length, - ), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - crossAxisSpacing: 10.0, - mainAxisSpacing: 10.0, - childAspectRatio: 0.7, // 调整为更适合视频封面的比例 + ); + }, + childCount: listToShow.length, + ), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 10.0, + mainAxisSpacing: 10.0, + childAspectRatio: 0.6, // 宽高比1=正方 + ), ), ), - ), - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 20.0), - child: Center( - child: params.hasMore ? const CircularProgressIndicator() : const Text('没有更多数据了'), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 20.0), + child: Center( + child: Obx( + () { + if (params.isLoading.value) { + return SafeArea(top: false, child: CircularProgressIndicator()); + } else if (!params.hasMore.value) { + return SafeArea(top: false, child: Text('没有更多数据了')); + } else { + return SizedBox(height: 20); + } + }, + ), + ), ), ), - ), - ], + ], + ), ); }