/// 首页模板 library; import 'package:card_swiper/card_swiper.dart'; import 'package:dynamic_tabbar/dynamic_tabbar.dart'; import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:loopin/IM/im_friend_listeners.dart'; import 'package:loopin/components/backtop.dart'; import 'package:loopin/components/loading.dart'; import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/controller/shop_index_controller.dart'; import 'package:loopin/styles/index.dart'; import 'package:loopin/utils/index.dart'; class IndexPage extends StatefulWidget { const IndexPage({super.key}); @override State createState() => _IndexPageState(); } class _IndexPageState extends State with SingleTickerProviderStateMixin { // 分类列表 // List cateList = [ // { // 'id': 1, // 'list': [ // { // 'icon': 'order.svg', // 'label': '我的订单', // }, // { // 'icon': 'chongzhi.svg', // 'label': '充值中心', // }, // {'icon': 'qianbao.svg', 'label': '余额'}, // {'icon': 'comment.svg', 'label': '评价中心'} // ] // } // ]; final ScrollController pageScrollController = ScrollController(); late ShopIndexController controller; // 瀑布流卡片 Widget cardList(item) { return GestureDetector( child: Container( clipBehavior: Clip.antiAlias, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(5), offset: Offset(0.0, 1.0), blurRadius: 1.0, spreadRadius: 0.0, ), ]), child: Column( children: [ // Image.network(), NetworkOrAssetImage( imageUrl: '${item['pic']}', width: double.infinity, placeholderAsset: 'assets/images/bk.jpg', ), Container( padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 5.0, children: [ Text( '${item['name']}', style: TextStyle(fontSize: 14.0, height: 1.2), maxLines: 2, overflow: TextOverflow.ellipsis, ), Row( spacing: 5.0, children: [ Text.rich( TextSpan(style: TextStyle(color: Colors.red, fontSize: 12.0, fontWeight: FontWeight.w700, fontFamily: 'Arial'), children: [ TextSpan(text: '¥'), TextSpan( text: '${item['price']}', style: TextStyle( fontSize: 16.0, )), ]), ), Text( '已售${Utils.graceNumber(int.parse(item['sales'] ?? '0'))}件', style: TextStyle(color: Colors.grey, fontSize: 10.0), ), ], ), Text( '${item['storeName']}', style: TextStyle(color: Colors.grey, fontSize: 12.0), ), ], ), ) ], ), ), onTap: () { // Get.toNamed('/goods', arguments: item['id']); Get.toNamed('/goods', arguments: {'goodsId': item['id']}); }, ); } @override void initState() { super.initState(); controller = Get.find(); controller.initTabs(vsync: this); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[50], body: Column( children: [ _buildTopSection(), // 内容区域 Expanded( child: controller.tabController == null ? Center(child: CircularProgressIndicator()) : Obx( () { final tabs = controller.tabList.asMap().entries.map((entry) { final idx = entry.key; final item = entry.value; return TabData( index: idx, title: Tab( child: Center( child: Text( item['name'] ?? '', style: const TextStyle(fontWeight: FontWeight.bold), overflow: TextOverflow.ellipsis, softWrap: false, ), ), ), content: _buildTabContent(idx), ); }).toList(); return DynamicTabBarWidget( onTabControllerUpdated: (tabController) { controller.tabController = tabController; // 强制选中第一个 if (tabController.index != 0) { tabController.animateTo(0); } }, onTabChanged: (index) { logger.w("当前选中ssssstab: $index"); }, dynamicTabs: tabs, tabAlignment: TabAlignment.start, isScrollable: true, showNextIcon: false, // 显示前进图标 showBackIcon: false, // 显示后退图标 labelColor: FStyle.primaryColor, indicatorColor: FStyle.primaryColor, overlayColor: WidgetStateProperty.all(Colors.transparent), unselectedLabelColor: Colors.black87, indicator: const UnderlineTabIndicator( borderSide: BorderSide(color: Color.fromARGB(255, 236, 108, 49), width: 2.0), ), unselectedLabelStyle: const TextStyle( fontSize: 14.0, fontFamily: 'Microsoft YaHei', ), labelStyle: const TextStyle( fontSize: 14.0, fontFamily: 'Microsoft YaHei', fontWeight: FontWeight.bold, ), dividerHeight: 0, ); }, ), ), ], ), floatingActionButton: Obx(() { final tabIndex = controller.currentTabIndex.value; final currentTab = controller.tabs[tabIndex]; if (currentTab == null) return const SizedBox.shrink(); return Backtop( controller: currentTab.scrollController, offset: currentTab.scrollOffset.value, ); }), ); } // 构建顶部固定区域 Widget _buildTopSection() { if (controller.tabController == null) { return SizedBox(); } return Column( children: [ // 轮播图 Obx(() { if (controller.swiperData.isEmpty) return const SizedBox.shrink(); if (controller.swiperData.length == 1) { final imageUrl = controller.swiperData.first['images'] ?? ''; return Image.network(imageUrl, fit: BoxFit.fill, width: double.infinity, height: 240); } return SizedBox( width: double.infinity, height: 240, child: Swiper( itemCount: controller.swiperData.length, autoplay: true, loop: true, pagination: const SwiperPagination( builder: DotSwiperPaginationBuilder( color: Colors.white70, activeColor: Colors.white, ), ), itemBuilder: (context, index) { final imageUrl = controller.swiperData[index]['images'] ?? ''; return imageUrl.isNotEmpty ? Image.network(imageUrl, fit: BoxFit.fill) : const SizedBox.shrink(); }, ), ); }), ], ); } // 构建标签页内容 Widget _buildTabContent(int index) { final tabState = controller.tabs[index]!; return Obx(() { if (tabState.dataList.isEmpty && tabState.isLoading.value) { return Center( child: RefreshProgressIndicator( backgroundColor: Colors.white, color: Color(0xFFFF5000), ), ); } // 添加 下拉刷新 return EasyRefresh( onRefresh: () async { await controller.refreshData(index); }, header: ClassicHeader( dragText: '下拉刷新', armedText: '释放刷新', readyText: '加载中...', processingText: '加载中...', processedText: '加载完成', messageText: '最后更新于 %T', ), child: CustomScrollView( controller: tabState.scrollController, key: PageStorageKey('tab_$index'), physics: const AlwaysScrollableScrollPhysics(), // 确保可下拉 slivers: [ SliverPadding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), sliver: tabState.dataList.isEmpty ? SliverToBoxAdapter( child: SizedBox( height: MediaQuery.of(context).size.height - 500, // 给个足够高度让下拉触发 child: Center(child: _emptyTip('暂无数据')), ), ) : SliverMasonryGrid.count( crossAxisCount: 2, mainAxisSpacing: 10.0, crossAxisSpacing: 10.0, childCount: tabState.dataList.length, itemBuilder: (context, idx) => cardList(tabState.dataList[idx]), ), ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.symmetric(vertical: 20.0), child: Center( child: tabState.isLoading.value ? const Loading(title: 'loading...') : (tabState.dataList.isNotEmpty ? const Text('没有更多数据了') : const SizedBox.shrink()), ), ), ), ], ), ); }); } // 空状态提示 Widget _emptyTip(String text) { return Center( child: Padding( padding: const EdgeInsets.only(top: 50), child: Column( mainAxisSize: MainAxisSize.min, children: [ Image.asset('assets/images/empty.png', width: 50, height: 50), const SizedBox(height: 8), Text( text, style: const TextStyle(color: Colors.grey, fontSize: 13), ), ], ), ), ); } }