496 lines
20 KiB
Dart
496 lines
20 KiB
Dart
/// 首页模板
|
|
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<IndexPage> createState() => _IndexPageState();
|
|
}
|
|
|
|
class _IndexPageState extends State<IndexPage> 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<void> 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),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|