/// 首页模板 library; import 'dart:ui'; 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/IM/im_message.dart'; import 'package:loopin/components/custom_sticky_header.dart'; import '../../behavior/custom_scroll_behavior.dart'; import '../../components/backtop.dart'; import '../../components/loading.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': '评价中心'} ] } ]; List tabList = ['推荐', '美食', '娱乐', '文旅', '医疗', '房产']; // 瀑布流列表 List waterfallData = [ { 'price': 199.00, 'title': '韩料界的萨莉亚!', 'shop': '萨莉亚专卖店', 'image': 'https://qcloud.dpfile.com/pc/1c3egbzM_ICz90dhi6MAiTsazjxWYQcHCd-sbpD1Wqtph2eIJA04NCRvoGqL4_opG45IiB1YIyNuDTtqzVRwesm_qA1Pf8rFcayTY-n-rG8.jpg', 'saleNum': '2.1万' }, { 'price': 1499.90, 'title': '茅台(MOUTAI)飞天 53%vol 500ml 贵州茅台酒(带杯)', 'shop': '茅台京东自营旗舰店', 'image': 'https://img13.360buyimg.com/n1/jfs/t1/97097/12/15694/245806/5e7373e6Ec4d1b0ac/9d8c13728cc2544d.jpg', 'saleNum': '1254' }, { 'price': 18.90, 'title': '上海街头苹果糖!一口一个不吱声', 'shop': '芝洛洛自营旗舰店', 'image': 'https://p0.meituan.net/coverpic/f0eefdfa02619fb09ca53eacd4d97231123115.jpg', 'saleNum': '1.2万' }, { 'price': 59.00, 'title': '谁懂,就是这个菜,尝了第一口,立马决定加单了,真正的咸甜永动机啊🍬 去过云南的朋友都知道,当地的乳扇真的很好吃。', 'shop': '薄荷牛舌卷旗舰店', 'image': 'https://qcloud.dpfile.com/pc/UcW-v6AN1TxVTt9--5Kaw2-t4W55jUhEG_pM5S-w_AQ4IP3z9WxHzwJ9fOthIjEYY0q73sB2DyQcgmKUxZFQtw.jpg', 'saleNum': '1639' }, { 'price': 2499.00, 'title': '小米 REDMI K80 国家补贴 第三代骁龙 8 6550mAh大电池 澎湃OS 玄夜黑 12GB+256GB 红米5G至尊手机', 'shop': '小米京东自营旗舰店', 'image': 'https://img10.360buyimg.com/n1/s450x450_jfs/t1/264409/38/13856/102861/678dcfdaFb723c58f/5b97cf154bbba96c.jpg', 'saleNum': '9726' }, { 'price': 1.00, 'title': '圣菲尔伯爵法国红酒Saintfilcount干红葡萄酒珍藏13.5度单瓶送礼红酒 一元试饮', 'shop': '小森葡萄酒专营店', 'image': 'https://img10.360buyimg.com/n7/jfs/t1/226168/23/3411/118733/65537e5fF2db2d109/7d1d11a8013d6e8f.jpg', 'saleNum': '9.9万' }, { 'price': 42.00, 'title': '美的(Midea)LED便携充电小台灯书桌学习阅读灯学生宿舍卧室床头灯学习台灯', 'shop': '美的(Midea)旗舰店', 'image': 'https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/226233/4/10194/156936/658e8f88Fcfc9cb40/cea4a48783f11a7a.jpg', 'saleNum': '5106' }, { 'price': 22.90, 'title': '蒙都 羊杂500g 加热即食 京东超市肉干肉脯及礼包11.11真便宜', 'shop': '蒙都旗舰店', 'image': 'https://img10.360buyimg.com/n7/jfs/t1/155306/32/25324/231912/62d22fb8E4ffab855/c6001ee702fb240a.jpg', 'saleNum': '1.6万' }, { 'price': 19.90, 'title': '『 江西炒米粉 』本次最佳😋香就一个字话。锅气的香🔥干辣椒的焦香🌶️油的润香🐷蔬菜混合的清香🥬', 'shop': '去月球野餐嗎', 'image': 'https://qcloud.dpfile.com/pc/pOAOL-DQRBWfkVZIWYVoy0mMQf6_UutNlOpEpGkT_nz3b1n7ZbpikPgtXMhMsjXNY0q73sB2DyQcgmKUxZFQtw.jpg', 'saleNum': '3.2万' }, { 'price': 109.00, 'title': '附近新开业的,作为江西人当然要去试试。点了几个家常菜。', 'shop': '辣评新开江西菜', 'image': 'https://qcloud.dpfile.com/pc/HePD48CFNnS0kMZyf3Q391wxaW_zVgHimctthH__J6UI54HLPUkNt5e3qtP4Nl2G_aW_B6sGElzX-tSmYRvRnQxxxek7cKy7_R0W-KdxWUk.jpg', 'saleNum': '8764' }, ]; // 列表 List dataList = []; // 是否加载中 bool isLoading = false; late ScrollController scrollController = ScrollController(); late TabController tabController = TabController(initialIndex: 0, length: tabList.length, vsync: this); final PageController pageController = PageController(); // 滚动位置 double scrollOffset = 0; // 加载更多 loadMoreData() async { setState(() { isLoading = true; }); await Future.delayed(Duration(seconds: 1)); setState(() { dataList.addAll(waterfallData); isLoading = false; }); } // 下拉刷新 Future handleRefresh() async { await Future.delayed(Duration(seconds: 1)); dataList.clear(); for (int i = 0; i < waterfallData.length; i++) { dataList.add(waterfallData[i]); } if (mounted) { setState(() {}); } } // 瀑布流卡片 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['image']}'), Container( padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 5.0, children: [ Text( '${item['title']}', 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['saleNum']}件', 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(); scrollController.addListener(() { setState(() { scrollOffset = scrollController.offset; }); if (scrollController.position.pixels == scrollController.position.maxScrollExtent) { debugPrint('[index]滚动到底部'); if (!isLoading) { loadMoreData(); } } }); // 初始化加载 handleRefresh(); } @override void dispose() { scrollController.dispose(); tabController.dispose(); pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { 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: [ Image.network( 'https://m.360buyimg.com/babel/jfs/t20271217/224114/35/38178/150060/6760d559Fd654f946/968c156726b6e822.png', fit: BoxFit.fill, ), Image.network( 'https://m.360buyimg.com/babel/jfs/t20280117/88832/5/48468/139826/6789cbcfF4e0b2a3d/9dc54355b6f65c40.jpg', fit: BoxFit.fill, ), Image.network( 'https://m.360buyimg.com/babel/jfs/t20280108/255505/29/10540/137372/677ddbc1F6cdbbed0/bc477fadedef22a8.jpg', fit: BoxFit.fill, ), ], ), ), ), ), // 分类 // SliverToBoxAdapter( // child: Container( // margin: EdgeInsets.all(10.0), // padding: EdgeInsets.symmetric(vertical: 10.0), // height: 90.0, // clipBehavior: Clip.antiAlias, // decoration: BoxDecoration( // color: Colors.white, // borderRadius: BorderRadius.circular(15.0), // ), // child: Column( // children: [ // Expanded( // child: PageView.builder( // controller: pageController, // itemCount: cateList.length, // itemBuilder: (context, index) { // final item = cateList[index]; // return GridView.builder( // shrinkWrap: true, // padding: EdgeInsets.zero, // physics: NeverScrollableScrollPhysics(), // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( // crossAxisCount: 4, // ), // itemCount: item['list'].length, // itemBuilder: (BuildContext context, int index) { // final citem = item['list'][index]; // // return Column( // // spacing: 3.0, // // children: [ // // if (citem['icon'] != null) // // SvgPicture.asset( // // 'assets/images/svg/${citem['icon']}', // // height: 30.0, // // width: 30.0, // // ), // // Text(citem['label']), // // ], // // ); // return GestureDetector( // onTap: () { // logger.i('点击了$index'); // // 跳转逻辑,用你自己的目标路由替换 // Get.toNamed('/order'); // }, // child: Column( // mainAxisSize: MainAxisSize.min, // children: [ // if (citem['icon'] != null) // SvgPicture.asset( // 'assets/images/svg/${citem['icon']}', // height: 30.0, // width: 30.0, // ), // Text(citem['label']), // ], // ), // ); // }, // ); // }, // ), // ), // CustomPageViewIndicator( // controller: pageController, // count: cateList.length, // color: Color(0xFFCECECE), // activeColor: Color(0xFFFF5000), // ), // ], // )), // ), // tabbar列表 SliverPersistentHeader( pinned: true, delegate: CustomStickyHeader( child: PreferredSize( preferredSize: Size.fromHeight(45.0), child: Container( color: Colors.white, height: 45.0, child: TabBar( controller: tabController, onTap: (index) { logger.i('点击了第 $index 个 tab'); }, tabs: tabList.map((v) => Tab(text: v)).toList(), isScrollable: false, 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: [ dataList.isEmpty ? // 初始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: dataList.length + (isLoading ? 1 : 0), itemBuilder: (BuildContext context, int index) { if (index < dataList.length) { return cardList(dataList[index]); } else { return SizedBox.shrink(); } }, ), Opacity(opacity: dataList.isNotEmpty && isLoading ? 1 : 0, child: Loading(title: 'loading...')), ], ), ), ), ], ), ), // 返回顶部 floatingActionButton: Backtop(controller: scrollController, offset: scrollOffset), ); } }