import 'dart:async'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:card_swiper/card_swiper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import '../../beans/find_banner_bean.dart'; import '../../beans/recommend_bean.dart'; import '../../custom/custom_swiper_pagination.dart'; import '../chat/chat_page.dart'; import 'find_model.dart'; ///推荐 class RecommendPage extends StatefulWidget { const RecommendPage({super.key}); @override State createState() => _RecommendPageState(); } class _RecommendPageState extends State with AutomaticKeepAliveClientMixin { late StreamSubscription subscription; final FindModel _viewmodel = FindModel(); List bannerList = []; List recommendList = []; //推荐 List popularList = []; //热门 @override void initState() { // TODO: implement initState super.initState(); subscription = _viewmodel.streamController.stream.listen((newData) { String code = newData['code']; if (code.isNotEmpty) { switch (code) { case "getCategoryFindList": List data = newData['data']; for (var value in data) { switch (value['type']) { case "banner": //轮播图 bannerList = (value['data'] as List).map((e) => FindBannerBean.fromJson(e as Map)).toList(); break; case "tuijian": //推荐 recommendList = (value['data'] as List).map((e) => RecommendBean.fromJson(e as Map)).toList(); break; case "xiaoshuo": //小说 popularList = (value['data'] as List).map((e) => RecommendBean.fromJson(e as Map)).toList(); break; } } setState(() {}); break; default: EasyLoading.showToast(newData['data']); break; } // setState(() {}); EasyLoading.dismiss(); } }); EasyLoading.show(status: "'loading...'"); _viewmodel.getCategoryFindList(); } @override void dispose() { // TODO: implement dispose subscription.cancel(); super.dispose(); } goChatPage(String id) { Navigator.push( context, MaterialPageRoute( builder: (context) => ChatPage( characterId: id, )), ); } @override Widget build(BuildContext context) { return Stack( children: [ SizedBox( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: SingleChildScrollView( // physics: BouncingScrollPhysics(), child: Column( children: [ SizedBox( height: 270, child: bannerList.isNotEmpty ? Swiper( itemBuilder: (BuildContext context, int index) { return Container( key: ValueKey(index), padding: EdgeInsets.only(bottom: 30), child: GestureDetector( onTap: () { goChatPage(bannerList[index].actionId.toString()); }, child: CachedNetworkImage( fit: BoxFit.fill, imageUrl: bannerList[index].imageUrl!, errorWidget: (context, url, error) => const Icon(Icons.error), ), ), ); }, itemCount: bannerList.length, pagination: SwiperPagination( // 此处使用自己编写的样式 builder: CustomSwiperPaginationBuilder( alignment: Alignment.bottomRight, color: Color(0xFF646464), activeColor: Color(0xFFCFCFCF)), ), ) : Container(), ), Container( alignment: Alignment.centerLeft, margin: EdgeInsets.only(left: 16), child: Text( '热门推荐', style: TextStyle(color: Colors.white, fontSize: 16), ), ), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Container( // width: 500, alignment: Alignment.centerLeft, margin: EdgeInsets.only(top: 21), padding: EdgeInsets.only(left: 16), height: 330, child: GridView.count( shrinkWrap: true, //水平子Widget之间间距 crossAxisSpacing: 12.0, //垂直子Widget之间间距 mainAxisSpacing: 9.0, //GridView内边距 padding: EdgeInsets.zero, //一行的Widget数量 crossAxisCount: 2, //子Widget宽高比例 childAspectRatio: 1.4, //子Widget列表 children: _item(recommendList), physics: NeverScrollableScrollPhysics(), //类似 cellForRow 函数 scrollDirection: Axis.horizontal)), ), Container( alignment: Alignment.centerLeft, margin: EdgeInsets.only(left: 16, top: 34), child: Text( '热门小说角色', style: TextStyle(color: Colors.white, fontSize: 16), ), ), Container( height: 153.0 * (popularList.length), margin: EdgeInsets.only(left: 16, right: 16, bottom: 60), child: ListView.builder( itemCount: popularList.length, physics: NeverScrollableScrollPhysics(), itemBuilder: (BuildContext context, int index) { return _item2(index, popularList[index]); }), ) ], ), ), ), ], ); } _item(List list) { return list.map((res) { int index = recommendList.indexOf(res); return GestureDetector( onTap: () { goChatPage(res.id.toString()); }, child: Container( alignment: Alignment.center, // margin: EdgeInsets.only(right: 9, left: 16), child: Stack( children: [ ClipRRect( borderRadius: BorderRadius.all(Radius.circular(15)), child: CachedNetworkImage( width: 113, height: 159, fit: BoxFit.cover, imageUrl: res.imageUrl!, errorWidget: (context, url, error) => const Icon(Icons.error), ), ), Positioned( left: 7, bottom: 21, child: Text( '${res.name}', style: TextStyle(color: Colors.white, fontSize: 12), )), Positioned( left: 7, bottom: 9, child: Container( width: 105, child: Text( '${res.biography}', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Color(0xFFC2C2C2), fontSize: 9), ), )), ], ), ), ); }).toList(); } _item2(index, RecommendBean data) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { goChatPage(data.id.toString()); }, child: Container( height: 130, width: 50, margin: EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: Color(0xFF202021), borderRadius: BorderRadius.all(Radius.circular(7)), border: Border.all(color: Color(0xFF7E7E7E), width: 0.3), ), child: Stack( alignment: Alignment.center, children: [ Positioned( left: 7, child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(15)), child: CachedNetworkImage( width: 83, height: 115, fit: BoxFit.cover, imageUrl: data.imageUrl!, errorWidget: (context, url, error) => const Icon(Icons.error), ), ), ), Positioned( left: 101, top: 19, child: Text( '${data.name}', style: TextStyle(color: Colors.white, fontSize: 14), )), Positioned( left: 101, top: 45, child: SizedBox( width: 200, height: 16, child: ListView.builder( itemCount: data.label?.length, scrollDirection: Axis.horizontal, itemBuilder: (BuildContext context, int index) { return Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(horizontal: 11), margin: EdgeInsets.only(right: 5), decoration: BoxDecoration(border: Border.all(color: Color(0xFFFF9000)), borderRadius: BorderRadius.all(Radius.circular(7))), child: Text( '${data.label?[index].name}', style: TextStyle(fontSize: 10, color: Color(0xFFFF9000)), ), ); }), )), Positioned( left: 102, top: 70, child: Container( width: 200, child: Text( maxLines: 3, '${data.biography}', overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.white, fontSize: 10), ), )) ], ), ), ); } @override // TODO: implement wantKeepAlive bool get wantKeepAlive => true; }