/// 首页模板 library; import 'package:card_swiper/card_swiper.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/behavior/custom_scroll_behavior.dart'; import 'package:loopin/components/backtop.dart'; import 'package:loopin/components/custom_sticky_header.dart'; import 'package:loopin/components/loading.dart'; import 'package:loopin/components/only_down_scroll_physics.dart'; import 'package:loopin/controller/shop_index_controller.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(); final ShopIndexController controller = Get.put(ShopIndexController()); // 下拉刷新初始化 Future handleRefresh() async {} ///商品详情 void shopDetail() async { // final res = await Http.get('${ShopApi.shopDetail}/1938137499482869762'); // logger.e(res['data']); } // 瀑布流卡片 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('${item['pic']}'), 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( '已售${item['sales']}件', style: TextStyle(color: Colors.grey, fontSize: 10.0), ), ], ), Text( '${item['shop']}', style: TextStyle(color: Colors.grey, fontSize: 12.0), ), ], ), ) ], ), ), onTap: () { Get.toNamed('/goods'); }, ); } @override void initState() { super.initState(); // controller.initTabs(vsync: this); } @override Widget build(BuildContext context) { return Obx(() { final tabIndex = controller.currentTabIndex.value; final scrollController = controller.tabs[tabIndex]?.scrollController; final pagesView = controller.tabs[tabIndex]; return Scaffold( backgroundColor: Colors.grey[50], body: ScrollConfiguration( behavior: CustomScrollBehavior().copyWith(scrollbars: false), child: CustomScrollView( scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false), controller: scrollController, slivers: [ SliverAppBar( backgroundColor: Colors.transparent, foregroundColor: Colors.white, pinned: true, expandedHeight: 200.0, titleSpacing: 10.0, // 搜索框(高斯模糊背景) // title: ClipRRect( // borderRadius: BorderRadius.circular(30.0), // child: BackdropFilter( // filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), // child: Container( // height: 45.0, // decoration: BoxDecoration( // color: Colors.white.withAlpha(200), // ), // child: TextField( // decoration: InputDecoration( // isDense: true, // hintText: "2025百亿补贴", // hintStyle: TextStyle(fontSize: 15.0), // prefixIcon: Icon( // Icons.search, // color: Colors.black38, // size: 21.0, // ), // suffixIcon: Container( // padding: EdgeInsets.only(right: 15.0), // child: Row( // mainAxisSize: MainAxisSize.min, // spacing: 10.0, // children: [ // Icon( // Icons.keyboard_voice, // color: Colors.black45, // size: 21.0, // ), // Icon( // Icons.camera_alt_outlined, // color: Colors.black45, // size: 21.0, // ), // ], // ), // ), // contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10.0), // border: OutlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(30.0))), // cursorColor: Colors.black, // onChanged: (val) { // debugPrint(val); // }, // ), // ), // ), // ), // actions: [ // IconButton( // icon: Icon(Icons.shopping_cart_outlined), // onPressed: () {}, // ), // ], // 自定义伸缩区域(轮播图) flexibleSpace: Container( decoration: BoxDecoration( gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFFFF5000), Color(0xFFfcaec4)])), child: FlexibleSpaceBar( background: Swiper.children( pagination: SwiperPagination( builder: DotSwiperPaginationBuilder( color: Colors.white70, activeColor: Colors.white, ), ), indicatorLayout: PageIndicatorLayout.SCALE, children: [ ...controller.swiperData.map((item) { final imageUrl = item['images'] ?? ''; return imageUrl.isNotEmpty ? Image.network( imageUrl, fit: BoxFit.fill, ) : SizedBox.shrink(); }), ], ), ), ), ), // tabbar列表 SliverPersistentHeader( pinned: true, delegate: CustomStickyHeader( child: PreferredSize( preferredSize: Size.fromHeight(45.0), child: Container( color: Colors.white, height: 45.0, child: TabBar( controller: controller.tabController, onTap: (index) { print('点击了第 $index 个 tab'); }, tabs: controller.tabList.map((v) => Tab(text: v['name'])).toList(), isScrollable: true, overlayColor: WidgetStateProperty.all(Colors.transparent), unselectedLabelColor: Colors.black87, labelColor: Color(0xFFFF5000), indicatorColor: Color(0xFFFF5000), indicatorSize: TabBarIndicatorSize.tab, unselectedLabelStyle: TextStyle(fontSize: 15.0, fontFamily: 'Microsoft YaHei'), labelStyle: TextStyle(fontSize: 15.0, fontFamily: 'Microsoft YaHei', fontWeight: FontWeight.w700), dividerHeight: 0, padding: EdgeInsets.symmetric(horizontal: 10.0), labelPadding: EdgeInsets.symmetric(horizontal: 7.5), indicatorPadding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 5.0), ), ), ), ), ), // 瀑布流列表 SliverToBoxAdapter( child: Container( padding: EdgeInsets.all(10.0), child: Column( children: [ pagesView?.dataList.isEmpty ?? true ? // 初始loading提示 Column( children: [ RefreshProgressIndicator( backgroundColor: Colors.white, color: Color(0xFFFF5000), ), ], ) : MasonryGridView.count( shrinkWrap: true, padding: EdgeInsets.zero, physics: NeverScrollableScrollPhysics(), crossAxisCount: 2, mainAxisSpacing: 10.0, crossAxisSpacing: 10.0, itemCount: ((pagesView?.dataList.length ?? 0) + (pagesView?.isLoading.value == true ? 1 : 0)), itemBuilder: (BuildContext context, int index) { final dataList = pagesView?.dataList ?? []; if (index < dataList.length) { return cardList(dataList[index]); } else { return SizedBox.shrink(); } }, ), Opacity( opacity: ((pagesView?.dataList.isNotEmpty ?? false) && (pagesView?.isLoading.value ?? false)) ? 1 : 0, child: Loading(title: 'loading...'), ), ], ), ), ), ], ), ), // 返回顶部 floatingActionButton: pagesView != null ? Backtop( controller: pagesView.scrollController, offset: pagesView.scrollOffset.value, ) : null, ); }); } // @override // Widget build(BuildContext context) { // return Obx(() { // final tabIndex = controller.currentTabIndex.value; // final pagesView = controller.tabs[tabIndex]; // return Scaffold( // backgroundColor: Colors.grey[50], // body: NestedScrollViewPlus( // // controller: pageScrollController, // overscrollBehavior: OverscrollBehavior.outer, // physics: (pagesView!.dataList.length > 4 && pagesView.currentPage > 1) // ? const OnlyDownScrollPhysics(parent: AlwaysScrollableScrollPhysics()) // : const AlwaysScrollableScrollPhysics(), // headerSliverBuilder: (context, innerBoxIsScrolled) { // return [ // SliverAppBar( // backgroundColor: Colors.transparent, // foregroundColor: Colors.white, // pinned: true, // stretch: false, // onStretchTrigger: () async { // print('触发 stretch 拉伸'); // // 加载刷新逻辑 // }, // expandedHeight: 180.0, // // collapsedHeight: kToolbarHeight, // collapsedHeight: 180.0, // // 自定义伸缩区域(轮播图) // flexibleSpace: Container( // decoration: BoxDecoration( // gradient: LinearGradient( // begin: Alignment.topLeft, // end: Alignment.bottomRight, // colors: [ // Color(0xFFFF5000), // Color(0xFFfcaec4), // ], // ), // ), // child: FlexibleSpaceBar( // background: Swiper.children( // pagination: SwiperPagination( // builder: DotSwiperPaginationBuilder( // color: Colors.white70, // activeColor: Colors.white, // ), // ), // indicatorLayout: PageIndicatorLayout.SCALE, // children: [ // ...controller.swiperData.map((item) { // final imageUrl = item['images'] ?? ''; // return imageUrl.isNotEmpty // ? Image.network( // imageUrl, // fit: BoxFit.fill, // ) // : SizedBox.shrink(); // }), // ], // ), // ), // ), // ), // // tab吸顶 // SliverPersistentHeader( // pinned: true, // delegate: CustomStickyHeader( // child: PreferredSize( // preferredSize: const Size.fromHeight(48.0), // child: Container( // color: Colors.white, // child: TabBar( // controller: controller.tabController, // tabs: controller.tabList.map((item) { // return Tab( // child: Text(item['name'], style: TextStyle(fontWeight: FontWeight.bold)), // ); // }).toList(), // isScrollable: false, // overlayColor: WidgetStateProperty.all(Colors.transparent), // unselectedLabelColor: Colors.black87, // labelColor: const Color(0xFFFF5000), // indicator: const UnderlineTabIndicator(borderSide: BorderSide(color: Color(0xFFFF5000), width: 2.0)), // indicatorSize: TabBarIndicatorSize.tab, // unselectedLabelStyle: const TextStyle(fontSize: 16.0, fontFamily: 'Microsoft YaHei'), // labelStyle: const TextStyle(fontSize: 18.0, fontFamily: 'Microsoft YaHei', fontWeight: FontWeight.bold), // dividerHeight: 0, // padding: const EdgeInsets.symmetric(horizontal: 10.0), // labelPadding: const EdgeInsets.symmetric(horizontal: 15.0), // ), // ), // ), // ), // ), // ]; // }, // body: TabBarView( // controller: controller.tabController, // children: controller.tabList.map((tabItem) { // final index = controller.tabList.indexOf(tabItem); // return buildTabContent(index); // }).toList(), // ), // ), // ); // }); // } //子view Widget buildTabContent(int index) { final tabState = controller.tabs[index]!; return Obx(() { if (tabState.dataList.isEmpty && tabState.isLoading.value) { return const Center( child: RefreshProgressIndicator( backgroundColor: Colors.white, color: Color(0xFFFF5000), ), ); } return CustomScrollView( primary: false, controller: tabState.scrollController, slivers: [ SliverPadding( padding: const EdgeInsets.all(10.0), sliver: SliverMasonryGrid.count( crossAxisCount: 2, mainAxisSpacing: 10.0, crossAxisSpacing: 10.0, childCount: tabState.dataList.length, itemBuilder: (context, idx) => cardList(tabState.dataList[idx]), ), ), SliverFillRemaining( hasScrollBody: false, child: Padding( padding: const EdgeInsets.symmetric(vertical: 20.0), child: Center( child: tabState.isLoading.value ? const Loading(title: 'loading...') : const Text('没有更多数据了'), ), ), ), ], ); }); } // // 空状态提示 Widget emptyTip(String text) { return CustomScrollView( physics: const OnlyDownScrollPhysics(), slivers: [ SliverFillRemaining( hasScrollBody: false, child: Align( alignment: Alignment.topCenter, child: Padding( padding: const EdgeInsets.only(top: 50.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ Image.asset('assets/images/empty.png', width: 100.0), const SizedBox(height: 8.0), Text( text, style: const TextStyle(color: Colors.grey, fontSize: 13.0), ), ], ), ), ), ), ], ); } }