import 'package:cs_resources/generated/assets.dart'; import 'package:flutter/material.dart'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:plugin_basic/provider/user_config/user_config_service.dart'; import 'package:router/ext/auto_router_extensions.dart'; import 'package:shared/utils/color_utils.dart'; import 'package:shared/utils/log_utils.dart'; import 'package:widgets/my_load_image.dart'; import 'package:widgets/ext/ex_widget.dart'; import 'package:widgets/my_text_view.dart'; import 'package:widgets/my_appbar.dart'; import 'package:cs_resources/theme/app_colors_theme.dart'; import 'package:widgets/widget_export.dart'; import '../../router/page/community_page_router.dart'; import '../my_posts/my_posts_page.dart'; import 'newsfeed_tabs.dart'; import 'community_vm.dart'; import 'customSilverHeaderTabs.dart'; final tabsRouterKey = GlobalKey(); final GlobalKey extendedNestedScrollViewKey = GlobalKey(); @RoutePage() class CommunityPage extends HookConsumerWidget with WidgetsBindingObserver { CommunityPage({Key? key}) : super(key: key); //启动当前页面 static void startInstance({BuildContext? context}) { if (context != null) { context.router.push(const CommunityPageRoute()); } else { appRouter.push(const CommunityPageRoute()); } } bool _isKeyboardVisible = false; void handlerNestedScrollViewScroll({double? outerOffset, double? innerOffset, bool? isOuterScrollAnimated=false, bool? isInnerScrollAnimated=false}){ if(outerOffset !=null){ if(isOuterScrollAnimated!){ extendedNestedScrollViewKey.currentState?.outerController.animateTo( outerOffset, duration: const Duration(seconds: 1), curve: Curves.easeIn, ); }else { extendedNestedScrollViewKey.currentState?.outerController.jumpTo( outerOffset, ); } } if(innerOffset !=null){ extendedNestedScrollViewKey.currentState?.innerPositions.forEach((position) { if(isInnerScrollAnimated!){ position.animateTo(innerOffset, duration: Duration(seconds: 1), curve: Curves.easeIn); }else { position.jumpTo(innerOffset); } }); } } @override void didChangeMetrics() { final bottomInset = WidgetsBinding.instance.window.viewInsets.bottom; final newValue = bottomInset > 0.0; if (_isKeyboardVisible != newValue) { _isKeyboardVisible = newValue; if (_isKeyboardVisible) { handlerNestedScrollViewScroll(innerOffset: 0.0,); print("键盘已显示"); } else { WidgetsBinding.instance.removeObserver(this); print("键盘已隐藏"); } } } @override Widget build(BuildContext context, WidgetRef ref) { final vm = ref.read(communityVmProvider.notifier); final state = ref.watch(communityVmProvider); useEffect(() { // 监听窗口 WidgetsBinding.instance.addObserver(this); }, []); useEffect((){ Log.d("CommunityPage initState"); // 延迟监听 WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { if(tabsRouterKey.currentState?.controller != null){ tabsRouterKey.currentState?.controller?.addListener((){ vm.tabsRouterChange(); }); } }); return (){ Log.d("CommunityPage dispose"); WidgetsBinding.instance.removeObserver(this); tabsRouterKey.currentState?.controller?.removeListener(vm.tabsRouterChange); }; },[]); return Scaffold( appBar: MyAppBar.searchAppBar( context, value: vm.getCurrentQueryParams('keyword'), actions: [ const MyAssetImage( Assets.communityLikeActive, width: 21.5, height: 21.5, ).onTap((){ vm.handlerClickNavbarLikeBtn(context); }), SizedBox(width: state.currentCategoryIdx ==0 ? 15:20), state.currentCategoryIdx ==1 ? const MyAssetImage( Assets.communityFillterIcon, width: 21, height: 21, ).onTap((){ vm.handlerClickNavbarFilterBtn(context); }) : const SizedBox.shrink(), const SizedBox(width: 15), ], backgroundColor: context.appColors.backgroundWhite, onSearch: (value) { vm.handlerSearch(value); } ), backgroundColor: context.appColors.backgroundDefault, body: ExtendedNestedScrollView( key: extendedNestedScrollViewKey, onlyOneScrollInBody: true, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ // SliverPersistentHeader( // delegate: CustomSliverPersistentHeaderDelegate( // maxHeight: 180, // minHeight: 180, // child: _buildTopSection(context, ref, vm, state), // ), // pinned: false, // ), // top 组件,转换为 Sliver 组件 SliverToBoxAdapter( child: _buildTopSection(context, ref, vm, state), ), ]; }, body: Column( mainAxisSize: MainAxisSize.max, children: [ Expanded( child: AutoTabsRouter.pageView( key: tabsRouterKey, routes: const [ NewsPageRoute(), FollowingPageRoute(), ForyouPageRoute(), ForsalePageRoute(), ForrentPageRoute(), ], builder: (context, child, pageController) { final tabsRouter = AutoTabsRouter.of(context); return Column( children: [ _buildTabsSection(context, ref, tabsRouter, vm, state), _buildPostSection(context, ref, vm, state), Expanded( child: child ), ], ); }, ) ) ] ) ) ); } Widget _buildTopSection(BuildContext context, WidgetRef ref, vm, state) { final topSectionsData = vm.topSectionsData; // final currentPageIdx = tabsRouterKey.currentState?.controller?.activeIndex ?? 0; int curTagIdx = 0; int currentPageIdx = state.currentPageViewIdx; int newsfeedTabCount = state.newsFeedTabsList.length; if(currentPageIdx >= newsfeedTabCount){ curTagIdx = 1; }else { curTagIdx = 0; } return Container( color: context.appColors.whiteBG, padding: const EdgeInsets.only(top: 23, bottom: 30), child: Center( child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: List.generate(topSectionsData.length, (index) { final item = topSectionsData[index]; return Column( children: [ Container( width: MediaQuery.of(context).size.width / topSectionsData.length - 36, height: 70, decoration: BoxDecoration( shape: BoxShape.circle, // 设置为圆形 color: ColorUtils.string2Color("#F0F8FF"), boxShadow: index == curTagIdx ? [ BoxShadow( color: context.appColors.tabLightBlueShadow, // 设置阴影颜色 blurRadius: 5, // 设置模糊半径 spreadRadius: 0.05, // 控制阴影扩散 offset: const Offset(0, 4), // 设置阴影偏移量 ),] : [],// 未选中时无阴影, ), child: MyAssetImage( item['icon'], width: MediaQuery.of(context).size.width / topSectionsData.length - 36, // width: 70, height: 70, ).onTap(() { vm.handlerSwitchNewsfeedOrGaragesale(index, context, null); }, type: ClickType.throttle, ), ), SizedBox.fromSize(size: const Size(0, 9)), MyTextView( item['title'], fontSize: 15, textColor: index == curTagIdx ? ColorUtils.string2Color('#4161D0'): context.appColors.textBlack, textAlign: TextAlign.center, isFontMedium: true, ), ], ).marginOnly(left: 18, right: 18, top: 10, bottom: 10); }), ), ), ); } Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter, vm, state){ int currentPageIndex = tabsRouter!.activeIndex ?? 0; int newsfeedTabCount = state.newsFeedTabsList.length; List tabsList; if(currentPageIndex < newsfeedTabCount){ // news feed tabsList = state.newsFeedTabsList ?? []; }else { tabsList = state.garageSaleTabsList ?? []; } return Container( width: double.infinity, color: ColorUtils.string2Color('#F2F3F6'), child: Center( child: NewsfeedTabs( key: UniqueKey(), tabsList: tabsList, tabsRouter: tabsRouter, margin: EdgeInsets.only(top: 14,bottom: 12, left: 20, right: 20), onClickAction:(Map? params){ if (params != null) { // 解构 params final int? currentCatgoryIdx = params['currentCatgoryIdx'] as int?; final int? tabIdx = params['tabIdx'] as int?; vm.handlerChangeTab(tabIdx, tabsRouter, currentCatgoryIdx); } } ), ), ); } Widget _buildPostSection(BuildContext context, WidgetRef ref, vm, state){ int currentPageIndex = state.currentPageViewIdx; int newsfeedTabCount = state.newsFeedTabsList.length; if(currentPageIndex < newsfeedTabCount){ // news feed return _buildNewsFeedPost(context, ref, vm, state); }else { return _buildGarageSalePost(context, ref, vm, state); } } Widget _buildNewsFeedPost(BuildContext context, WidgetRef ref, vm, state){ final userConfig = UserConfigService.getState(ref: ref); return Container( height: 65.5, width: double.infinity, padding: const EdgeInsets.only(left: 20, right: 20), color: Colors.white, child: Row( children: [ // const MyAssetImage(Assets.communityNewsFeed, width: 45,height: 45,), MyLoadImage( userConfig.user?.avatar, width: 45, height: 45, isCircle: true, fit: BoxFit.fill, ), Expanded( child: MyTextView( "What’s on your mind?", textColor: context.appColors.textBlack, fontSize: 15, marginLeft: 15, alignment: Alignment.centerLeft, textAlign: TextAlign.left, backgroundColor: ColorUtils.string2Color('#ffffff'), maxLines: 1, isFontMedium: true, ), ), const MyAssetImage( Assets.communityCamera, width: 21, height: 16.5, ), ], ).onTap((){ vm.handlerGotoNewsfeedPost(context); }), ); } Widget _buildGarageSalePost(BuildContext context, WidgetRef ref, vm, state){ final userConfig = UserConfigService.getState(ref: ref); return Container( height: 65.5, width: double.infinity, padding: const EdgeInsets.only(left: 20, right: 20), color: Colors.white, child: Row( children: [ MyLoadImage( userConfig.user?.avatar, width: 45, height: 45, isCircle: true, fit: BoxFit.fill, ), Expanded( child: MyTextView( "Sell Item", textColor: context.appColors.textBlack, fontSize: 15, marginLeft: 15, alignment: Alignment.centerLeft, textAlign: TextAlign.left, backgroundColor: ColorUtils.string2Color('#ffffff'), maxLines: 1, isFontMedium: true, ), ), const MyAssetImage( Assets.communityCamera, width: 21, height: 16.5, ), ], ).onTap((){ vm.handlerGotoGaragePost(context); }), ); } }