diff --git a/lib/pages/goods_details_page/goods_details_page.dart b/lib/pages/goods_details_page/goods_details_page.dart index e42c3f1..7e9a135 100644 --- a/lib/pages/goods_details_page/goods_details_page.dart +++ b/lib/pages/goods_details_page/goods_details_page.dart @@ -55,8 +55,7 @@ class GoodsDetailsContainer extends StatefulWidget { class _GoodsDetailsContainerState extends State { bool _isEnded = false; ScrollController _controller = ScrollController(); - RefreshController _refreshController = - RefreshController(initialRefresh: false); + RefreshController _refreshController = RefreshController(initialRefresh: false); void _onLoading() async { // await Future.delayed(Duration(milliseconds: 1000)); diff --git a/lib/pages/search_page/bloc/search_bloc.dart b/lib/pages/search_page/bloc/search_bloc.dart new file mode 100644 index 0000000..ec27217 --- /dev/null +++ b/lib/pages/search_page/bloc/search_bloc.dart @@ -0,0 +1,54 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter/cupertino.dart'; +import 'search_repository.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +part 'search_event.dart'; + +part 'search_state.dart'; + +class SearchBloc extends Bloc { + // SreachBloc() : super(SreachInitial()); + + SearchRepository repository; + + SearchBloc({this.repository}); + + @override + SearchState get initialState => SearchInitial(); + + @override + Stream mapEventToState( + SearchEvent event, + ) async* { + /// 初始化方法 + if (event is SearchInitEvent) { + yield* _mapInitEventToState(event); + } + + /// 搜索的方法 + if (event is SearchSubmitEvent) { + yield* _mapSearchSubmitToState(event); + } + } + + /// 初始化 + Stream _mapInitEventToState(SearchInitEvent event) async* { + /// 获取数据 + var result = await repository.fetchInit(event.model); + Logger.log('result = ${result.toString()}'); + if (!EmptyUtil.isEmpty(result)) { + yield SearchLoadedState(model: result); + } else { + yield SearchErrorState(); + } + } + + /// 搜索的方法 + Stream _mapSearchSubmitToState(SearchSubmitEvent event) async* { + var result = await repository.fetchSearchSubmit(event.model); + } +} diff --git a/lib/pages/search_page/bloc/search_event.dart b/lib/pages/search_page/bloc/search_event.dart new file mode 100644 index 0000000..ed75f7d --- /dev/null +++ b/lib/pages/search_page/bloc/search_event.dart @@ -0,0 +1,28 @@ +part of 'search_bloc.dart'; + +abstract class SearchEvent extends Equatable { + const SearchEvent(); + + @override + List get props => []; +} + +/// 初始化方法 +class SearchInitEvent extends SearchEvent { + final Map model; + + const SearchInitEvent({this.model}); + + @override + List get props => [model]; +} + +/// 搜索方法 +class SearchSubmitEvent extends SearchEvent { + final String model; + + const SearchSubmitEvent({@required this.model}); + + @override + List get props => [this.model]; +} diff --git a/lib/pages/search_page/bloc/search_repository.dart b/lib/pages/search_page/bloc/search_repository.dart new file mode 100644 index 0000000..ebd6db2 --- /dev/null +++ b/lib/pages/search_page/bloc/search_repository.dart @@ -0,0 +1,27 @@ +import 'package:zhiying_comm/zhiying_comm.dart'; + +class SearchRepository { + List> _pageData = []; + + /// 获取网络数据 + Future>> fetchInit(final Map model) async { + var result = await NetUtil.post('/api/v1/mod/pub.flutter.search_index', method: NetMethod.GET); + if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { + try { + _pageData = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); + return _pageData; + } catch (e) { + Logger.error(e.toString()); + } + } + return null; + } + + /// 获取缓存数据 + Future>> fetchCachedData(final Map model) {} + + /// 搜索的方法 + Future fetchSearchSubmit(final String model) async { + var result = await NetUtil.post(''); + } +} diff --git a/lib/pages/search_page/bloc/search_state.dart b/lib/pages/search_page/bloc/search_state.dart new file mode 100644 index 0000000..edd42d8 --- /dev/null +++ b/lib/pages/search_page/bloc/search_state.dart @@ -0,0 +1,36 @@ +part of 'search_bloc.dart'; + +abstract class SearchState extends Equatable { + const SearchState(); + + @override + List get props => []; +} + +class SearchInitial extends SearchState { + @override + List get props => []; +} + +/// 数据加载完毕 +class SearchLoadedState extends SearchInitial { + List> model; + + SearchLoadedState({this.model}); + + @override + List get props => [this.model]; +} + +/// 搜索成功 +class SearchSubmitSuccessState extends SearchState{ + +} + +/// 搜索失败 +class SearchSubmitErrorState extends SearchState{ + +} + +/// 数据加载出错 +class SearchErrorState extends SearchState {} diff --git a/lib/pages/search_page/search_page.dart b/lib/pages/search_page/search_page.dart new file mode 100644 index 0000000..c6acf83 --- /dev/null +++ b/lib/pages/search_page/search_page.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'bloc/search_bloc.dart'; +import 'bloc/search_repository.dart'; + +/// +/// 搜索页 +/// +class SearchPage extends StatelessWidget { + final Map data; + + SearchPage(this.data, {Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), + child: SearchPageContianer(), + ); + } +} + +class SearchPageContianer extends StatefulWidget { + @override + _SearchPageContianerState createState() => _SearchPageContianerState(); +} + +class _SearchPageContianerState extends State { + /// tab轮播 + TabController _tabController; + ScrollController _controller = ScrollController(); + + @override + void initState() { + _tabController = TabController(length:0, vsync: ScrollableState()); + super.initState(); + } + + @override + void dispose() { + _controller?.dispose(); + _tabController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removePadding( + removeTop: true, + context: context, + child: Container( + width: double.infinity, + child: BlocConsumer( + listener: (BuildContext context, SearchState state) { + if (state is SearchErrorState) { + print('数据加载出错'); + } + }, + buildWhen: (previous, current) { + /// 数据加载出错不进行build + if (current is SearchErrorState) { + return false; + } + + /// 搜索成功,跳转结果页面 + if (current is SearchSubmitSuccessState) { + return false; + } + + /// 搜索失败,不进行build + if (current is SearchSubmitErrorState) { + return false; + } + + return true; + }, + builder: (context, state) { + print('currente state = $state'); + if (state is SearchLoadedState) { + return _getMainWidget(state?.model); + } + + /// 骨架屏幕 + return _getMainWidget(null); + }, + ), + ), + ); + } + + /// 主视图 + Widget _getMainWidget(List> datas) { + return Scaffold( + backgroundColor: Colors.white, + body: CustomScrollView( + controller: _controller, + slivers: _createContent(context, datas ?? []), + ), + ); + } + + List _createContent(BuildContext context, List> datas) { + List list = List(); + + int length = datas?.length ?? 0; + + if (length <= 0) { + list.add(SliverToBoxAdapter( + child: Container( + height: 200, + child: Center( + child: Text('暂时无数据哦~'), + ), + ), + )); + return list; + } + + for (int i = 0; i < 3; i++) { + WidgetModel item = WidgetModel.fromJson(Map.from(datas[i])); + print('item.modName ${item.modName}'); + list.addAll(WidgetFactory.create( + item.modName, + isSliver: true, + model: datas[i], + )); + } + + list.add(SliverFillRemaining( + child: Text('etstssss et'), + )); + + return list; + } +} diff --git a/lib/pages/search_page/search_page2.dart b/lib/pages/search_page/search_page2.dart new file mode 100644 index 0000000..e6dd099 --- /dev/null +++ b/lib/pages/search_page/search_page2.dart @@ -0,0 +1,183 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'bloc/search_bloc.dart'; +import 'bloc/search_repository.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +class SearchPage2 extends StatelessWidget { + final Map data; + + const SearchPage2(this.data); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), + child: SearchPage2Container(), + ); + } +} + +class SearchPage2Container extends StatefulWidget { + @override + _SearchPage2ContainerState createState() => _SearchPage2ContainerState(); +} + +class _SearchPage2ContainerState extends State { + + TabController _controller; + + @override + void initState() { + _controller = TabController(length: tabTitle.length, vsync: ScrollableState()); + super.initState(); + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removePadding( + removeTop: true, + context: context, + child: Container( + width: double.infinity, + child: BlocConsumer( + listener: (BuildContext context, SearchState state) { + if (state is SearchErrorState) { + print('数据加载出错'); + } + }, + buildWhen: (previous, current) { + /// 数据加载出错不进行build + if (current is SearchErrorState) { + return false; + } + + /// 搜索成功,跳转结果页面 + if (current is SearchSubmitSuccessState) { + return false; + } + + /// 搜索失败,不进行build + if (current is SearchSubmitErrorState) { + return false; + } + + return true; + }, + builder: (context, state) { + print('currente state = $state'); + if (state is SearchLoadedState) { + return _getMainWidget(state?.model); + } + + /// 骨架屏幕 + return _getMainWidget(null); + }, + ), + ), + ); + } + + /// 主视图 + Widget _getMainWidget(List> datas){ + return Scaffold( + backgroundColor: Colors.white, + body: NestedScrollView( + headerSliverBuilder: (context, bool){ + return _createHeadWidget(context, datas); + }, + body: ListView( + children: [ + Text('sss') + ], + ), + ), + ); + } + + + /// 头部视图 + List _createHeadWidget(BuildContext context, List> datas){ + List list = []; + + int length = datas?.length?? 0; + if (length <= 0) { + list.add(SliverToBoxAdapter( + child: Container( + height: 200, + child: Center( + child: Text('暂时无数据哦~'), + ), + ), + )); + return list; + } + + for (int i = 0; i < 2; i++) { + WidgetModel item = WidgetModel.fromJson(Map.from(datas[i])); + print('item.modName ${item.modName}'); + list.addAll(WidgetFactory.create( + item.modName, + isSliver: true, + model: datas[i], + )); + } + list.add(_getTabbar()); + return list; + + } + + var tabTitle = [ + '页面1', + '页面2', + '页面3', + ]; + + Widget _getTabbar(){ + /// 悬停TabBar + return SliverPersistentHeader( + delegate: new SliverTabBarDelegate( + TabBar( + controller: _controller, + tabs: tabTitle.map((f) => Tab(text: f)).toList(), + indicatorColor: Colors.red, + unselectedLabelColor: Colors.black, + labelColor: Colors.red, + ), + ), + pinned: true, + ); + } + +} + +class SliverTabBarDelegate extends SliverPersistentHeaderDelegate { + final TabBar widget; + + + const SliverTabBarDelegate(this.widget) + : assert(widget != null); + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return Container( color:Colors.white,child: this.widget); + } + + @override + bool shouldRebuild(SliverTabBarDelegate oldDelegate) { + return false; + } + + @override + double get maxExtent => widget.preferredSize.height; + + @override + double get minExtent => widget.preferredSize.height; +} diff --git a/lib/pages/search_page/search_page3.dart b/lib/pages/search_page/search_page3.dart new file mode 100644 index 0000000..2087325 --- /dev/null +++ b/lib/pages/search_page/search_page3.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'bloc/search_bloc.dart'; +import 'bloc/search_repository.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +class SearchPage3 extends StatelessWidget { + final Map data; + + const SearchPage3(this.data); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), + child: SearchPage3Container(), + ); + } +} + +class SearchPage3Container extends StatefulWidget { + @override + _SearchPage3ContainerState createState() => _SearchPage3ContainerState(); +} + +class _SearchPage3ContainerState extends State { + @override + Widget build(BuildContext context) { + return MediaQuery.removePadding( + removeTop: true, + context: context, + child: Container( + width: double.infinity, + child: BlocConsumer( + listener: (BuildContext context, SearchState state) { + if (state is SearchErrorState) { + print('数据加载出错'); + } + }, + buildWhen: (previous, current) { + /// 数据加载出错不进行build + if (current is SearchErrorState) { + return false; + } + + /// 搜索成功,跳转结果页面 + if (current is SearchSubmitSuccessState) { + return false; + } + + /// 搜索失败,不进行build + if (current is SearchSubmitErrorState) { + return false; + } + + return true; + }, + builder: (context, state) { + print('currente state = $state'); + if (state is SearchLoadedState) { + return _getMainWidget(state?.model); + } + + /// 骨架屏幕 + return _getMainWidget(null); + }, + ), + ), + ); + } + + /// 主视图 + Widget _getMainWidget(List> datas){ + return Scaffold( + backgroundColor: Colors.white, + body: NestedScrollView( + headerSliverBuilder: (context, bool){ + return _createHeadWidget(context, datas); + }, + body: Container( + child: Text('testssfee'), + ), + ), + ); + } + + + /// 头部视图 + List _createHeadWidget(BuildContext context, List> datas){ + List list = []; + + int length = datas?.length?? 0; + if (length <= 0) { + list.add(SliverToBoxAdapter( + child: Container( + height: 200, + child: Center( + child: Text('暂时无数据哦~'), + ), + ), + )); + return list; + } + + for (int i = 0; i < 3; i++) { + WidgetModel item = WidgetModel.fromJson(Map.from(datas[i])); + print('item.modName ${item.modName}'); + list.addAll(WidgetFactory.create( + item.modName, + isSliver: true, + model: datas[i], + )); + } + return list; + + } + + + /// 子视图 + + + List _createContent(BuildContext context, List> datas) { + List list = List(); + + /// datas.length - 1 为最后一个在底部 + for (int i = 0; i < datas.length; i++) { + WidgetModel item = WidgetModel.fromJson(Map.from(datas[i])); + print('item.modName ${item.modName}'); + list.addAll(WidgetFactory.create( + item.modName, + isSliver: true, + model: datas[i], + )); + } + if (list.length <= 0) { + list.add(SliverToBoxAdapter( + child: Container( + height: 200, + child: Center( + child: Text('暂时无数据哦~'), + ), + ), + )); + } + return list; + } +} + diff --git a/lib/pages/sreach_page/sreach_page.dart b/lib/pages/sreach_page/sreach_page.dart deleted file mode 100644 index 74240f1..0000000 --- a/lib/pages/sreach_page/sreach_page.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; - -/// -/// 搜索页 -/// -class SreachPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Container(); - } -} diff --git a/lib/register.dart b/lib/register.dart index 658d7cd..f7216fa 100644 --- a/lib/register.dart +++ b/lib/register.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; import 'package:zhiying_base_widget/pages/launch_page/launch_page.dart'; import 'package:zhiying_base_widget/pages/main_page/main_page.dart'; @@ -8,7 +9,6 @@ import 'package:zhiying_base_widget/pages/security_page/security_mobile/security import 'package:zhiying_base_widget/pages/security_page/security_page.dart'; import 'package:zhiying_base_widget/pages/security_page/security_password/security_password.dart'; import 'package:zhiying_base_widget/pages/setting_page/setting_page.dart'; -import 'package:zhiying_base_widget/pages/sreach_page/sreach_page.dart'; import 'package:zhiying_base_widget/pages/sreach_result_page/sreach_result_page.dart'; import 'package:zhiying_base_widget/pages/wallet_page/wallet_page.dart'; import 'package:zhiying_base_widget/pages/webview/base_webview.dart'; @@ -36,11 +36,16 @@ import 'package:zhiying_base_widget/widgets/wallet/wallet_income/wallet_income.d import 'package:zhiying_comm/util/defalut_widget_creater.dart'; import 'package:zhiying_comm/zhiying_comm.dart'; +import 'pages/search_page/search_page.dart'; import 'widgets/goods_details/coupon/counpon_widget.dart'; import 'widgets/goods_details/detail_img/goods_details_img.dart'; import 'widgets/goods_details/evaluate/goods_details_evaluate_widget.dart'; +import 'widgets/goods_details/recommend/goods_detail_commend_creater.dart'; import 'widgets/goods_details/title/goods_details_title_widget.dart'; import 'widgets/home/home_quick_entry/home_quick_entry.dart'; +import 'widgets/search/input/search_input_widget.dart'; +import 'widgets/search/tabbar/search_tab_creater.dart'; +import 'widgets/search/tabbar/search_tab_widget.dart'; class BaseWidgetRegister { /// 初始化方法 @@ -63,7 +68,7 @@ class BaseWidgetRegister { PageFactory.regist('pub.flutter.profile', (model) => MainPage(model)); PageFactory.regist('pub.flutter.my_wallet', (model) => WalletPage()); PageFactory.regist('goods_details', (model) => GoodsDetailsPage(model)); - PageFactory.regist('sreach', (model) => SreachPage()); + PageFactory.regist('sreach', (model) => SearchPage(model)); PageFactory.regist('sreach_result', (model) => SreachResultPage()); // PageFactory.regist('login', (model) => LoginPage(model)); // PageFactory.regist('login_quick', (model) => LoginQuickPage(model)); @@ -99,86 +104,79 @@ class BaseWidgetRegister { // ==================== 首页 // WidgetFactory.regist('index_title', NormalNavCreater()); /// 首页搜索栏 - // WidgetFactory.regist('index_search', HomeSreachCreater()); - WidgetFactory.regist('index_search', - DefaultWidgetCreater((model) => HomeSreachWidget(model))); + WidgetFactory.regist('index_search', HomeSreachCreater()); + // WidgetFactory.regist('index_search', + // DefaultWidgetCreater((model) => HomeSreachWidget(model))); /// 可滚动banner WidgetFactory.regist('index_carousel', HomeSlideBannerCreater()); WidgetFactory.regist('index_recommend_list', GoodsListCreater()); /// 首页快速入口 - WidgetFactory.regist( - 'multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model))); + WidgetFactory.regist('multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model))); /// 滚动公告 - WidgetFactory.regist('index_placard', - DefaultWidgetCreater((model) => HomeNoticeWidget(model))); + WidgetFactory.regist('index_placard', DefaultWidgetCreater((model) => HomeNoticeWidget(model))); /// 不可以滚动banner WidgetFactory.regist('index_banner_one', HomeBannerCreater()); WidgetFactory.regist('index_banner_two', HomeBannerCreater()); // WidgetFactory.regist('index_taobao_auth_tip', HomeAuthCreater()); + /// ==================== 搜索页面 ==================== /// + // 搜索标题 + // WidgetFactory.regist('search_index_app_bar', DefaultWidgetCreater((model) => SearchAppbarWidget(model))); + WidgetFactory.regist('search_index_app_bar', SearchAppbarCreater()); + // 搜索输入框 + WidgetFactory.regist('search_index_input', SearchInputCreater()); + // WidgetFactory.regist('search_index_input', DefaultWidgetCreater((model) => SearchInputWidget(model))); + // // 搜索tabBar + WidgetFactory.regist('search_index_icon_list', SearcchTabCreater()); + // WidgetFactory.regist('search_index_icon_list', DefaultWidgetCreater((model) => SearchTabWidget(model))); + // // 热门搜索标签 + // WidgetFactory.regist('search_index', null); + // // 历史搜索标签 + // WidgetFactory.regist('search_index_history', null); + /// ==================== 商品详情 ==================== /// // 商品详情轮播图 - WidgetFactory.regist('product_detail_carousel', - DefaultWidgetCreater((model) => GoodsDetailsSlideBannerWidget(model))); + WidgetFactory.regist('product_detail_carousel', DefaultWidgetCreater((model) => GoodsDetailsSlideBannerWidget(model))); // 商品详情下载APP提示 - WidgetFactory.regist('product_detail_download_tips', - DefaultWidgetCreater((model) => UpgradeTipWidget(model))); + WidgetFactory.regist('product_detail_download_tips', DefaultWidgetCreater((model) => UpgradeTipWidget(model))); // 商品详情价格显示 - WidgetFactory.regist('product_detail_price', - DefaultWidgetCreater((model) => GoodsDetailsPriceWidget(model))); + WidgetFactory.regist('product_detail_price', DefaultWidgetCreater((model) => GoodsDetailsPriceWidget(model))); // 商品详情标题 - WidgetFactory.regist('product_detail_title', - DefaultWidgetCreater((model) => GoodsDetailsTitleWidget(model))); + WidgetFactory.regist('product_detail_title', DefaultWidgetCreater((model) => GoodsDetailsTitleWidget(model))); // 商品详情优惠劵 - WidgetFactory.regist('product_detail_coupon', - DefaultWidgetCreater((model) => CounponWidget(model))); + WidgetFactory.regist('product_detail_coupon', DefaultWidgetCreater((model) => CounponWidget(model))); // 商品详情店铺 - WidgetFactory.regist('product_detail_shop', - DefaultWidgetCreater((model) => StoreWidget(model))); + WidgetFactory.regist('product_detail_shop', DefaultWidgetCreater((model) => StoreWidget(model))); // 商品详情宝贝评价 - WidgetFactory.regist('product_detail_comment', - DefaultWidgetCreater((model) => GoodsDetailsEvaluateWidget(model))); + WidgetFactory.regist('product_detail_comment', DefaultWidgetCreater((model) => GoodsDetailsEvaluateWidget(model))); // 商品详情图片 - WidgetFactory.regist('product_detail_img_list', - DefaultWidgetCreater((model) => GoodsDetailsImgWidget(model))); + WidgetFactory.regist('product_detail_img_list', DefaultWidgetCreater((model) => GoodsDetailsImgWidget(model))); // 商品详情底部推荐列表 - WidgetFactory.regist('product_detail_bottom_rec', - DefaultWidgetCreater((model) => GoodsListWidget(model))); + WidgetFactory.regist('product_detail_bottom_rec', GoodsDetailCommendCreater()); // 商品详情底部 - WidgetFactory.regist('product_detail_bottom', - DefaultWidgetCreater((model) => GoodsDetailsFooterWidget(model))); + WidgetFactory.regist('product_detail_bottom', DefaultWidgetCreater((model) => GoodsDetailsFooterWidget(model))); // ==================== 个人中心 WidgetFactory.regist('profile_appbar', MineNavCreater()); - WidgetFactory.regist('profile_background', - DefaultWidgetCreater((model) => MineNavBg(model))); - WidgetFactory.regist( - 'profile_header', DefaultWidgetCreater((model) => MineHeader(model))); - WidgetFactory.regist( - 'profile_earning', DefaultWidgetCreater((model) => MineData(model))); - WidgetFactory.regist('profile_functions', - DefaultWidgetCreater((model) => MineQuickEntry(model))); - WidgetFactory.regist('profile_my_functions', - DefaultWidgetCreater((model) => MineQuickEntry(model))); - WidgetFactory.regist('profile_carousel', - DefaultWidgetCreater((model) => HomeBannerWidget(model))); + WidgetFactory.regist('profile_background', DefaultWidgetCreater((model) => MineNavBg(model))); + WidgetFactory.regist('profile_header', DefaultWidgetCreater((model) => MineHeader(model))); + WidgetFactory.regist('profile_earning', DefaultWidgetCreater((model) => MineData(model))); + WidgetFactory.regist('profile_functions', DefaultWidgetCreater((model) => MineQuickEntry(model))); + WidgetFactory.regist('profile_my_functions', DefaultWidgetCreater((model) => MineQuickEntry(model))); + WidgetFactory.regist('profile_carousel', DefaultWidgetCreater((model) => HomeBannerWidget(model))); // ==================== 钱包 - WidgetFactory.regist( - 'wallet_data', DefaultWidgetCreater((model) => WalletData())); + WidgetFactory.regist('wallet_data', DefaultWidgetCreater((model) => WalletData())); // WidgetFactory.regist( // 'wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); // WidgetFactory.regist('wallet_detail', HomeAuthCreater()); - WidgetFactory.regist( - 'wallet_data', DefaultWidgetCreater((model) => WalletData())); - WidgetFactory.regist( - 'wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); + WidgetFactory.regist('wallet_data', DefaultWidgetCreater((model) => WalletData())); + WidgetFactory.regist('wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); - WidgetFactory.regist( - 'wallet_income', DefaultWidgetCreater((model) => WalletIncome())); + WidgetFactory.regist('wallet_income', DefaultWidgetCreater((model) => WalletIncome())); } } diff --git a/lib/widgets/home/home_banner/home_banner_widget.dart b/lib/widgets/home/home_banner/home_banner_widget.dart index 13b9fe8..46edc7c 100644 --- a/lib/widgets/home/home_banner/home_banner_widget.dart +++ b/lib/widgets/home/home_banner/home_banner_widget.dart @@ -61,8 +61,8 @@ class _HomeBannerContainerState extends State { builder: (context, state) { print(state); if (state is HomeBannerLoadedState) { - int lenght = state?.model?.list?.length ?? 0; - if (lenght > 0) + int length = state?.model?.list?.length ?? 0; + if (length > 0) return _getMainWidget(data: state?.model?.list); else return HomeBannerSkeleton(widget?.model); diff --git a/lib/widgets/search/appbar/model/search_appbar_model.dart b/lib/widgets/search/appbar/model/search_appbar_model.dart new file mode 100644 index 0000000..6020cda --- /dev/null +++ b/lib/widgets/search/appbar/model/search_appbar_model.dart @@ -0,0 +1,26 @@ +class SearchAppbarModel { + String app_bar_bg_color; + String app_bar_title; + String app_bar_title_color; + String back_icon; + + SearchAppbarModel({this.app_bar_bg_color, this.app_bar_title, this.app_bar_title_color, this.back_icon}); + + factory SearchAppbarModel.fromJson(Map json) { + return SearchAppbarModel( + app_bar_bg_color: json['app_bar_bg_color'], + app_bar_title: json['app_bar_title'], + app_bar_title_color: json['app_bar_title_color'], + back_icon: json['back_icon'], + ); + } + + Map toJson() { + final Map data = new Map(); + data['app_bar_bg_color'] = this.app_bar_bg_color; + data['app_bar_title'] = this.app_bar_title; + data['app_bar_title_color'] = this.app_bar_title_color; + data['back_icon'] = this.back_icon; + return data; + } +} diff --git a/lib/widgets/search/appbar/search_appbar_creater.dart b/lib/widgets/search/appbar/search_appbar_creater.dart new file mode 100644 index 0000000..a9c910c --- /dev/null +++ b/lib/widgets/search/appbar/search_appbar_creater.dart @@ -0,0 +1,28 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:zhiying_base_widget/widgets/search/appbar/search_appbar_widget.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'dart:ui'; +import 'package:zhiying_comm/util/custom_sliver_persistent_header_delegate.dart'; + +class SearchAppbarCreater extends WidgetCreater { + @override + List createWidgets(Map model) { + return [ + SliverPersistentHeader( + delegate: CustomSliverPersistentHeaderDelegate( + child: SearchAppbarWidget(model), + max: MediaQueryData.fromWindow(window).padding.top + 44, + min: MediaQueryData.fromWindow(window).padding.top + 44, + ), + pinned: true, + floating: false, + ), + ]; + } + + @override + bool isSliverChild() { + return true; + } +} diff --git a/lib/widgets/search/appbar/search_appbar_widget.dart b/lib/widgets/search/appbar/search_appbar_widget.dart new file mode 100644 index 0000000..5d391be --- /dev/null +++ b/lib/widgets/search/appbar/search_appbar_widget.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:zhiying_base_widget/widgets/search/appbar/model/search_appbar_model.dart'; +import 'dart:ui'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +class SearchAppbarWidget extends StatelessWidget { + final Map data; + SearchAppbarModel model; + + SearchAppbarWidget(this.data, {Key key}) : super(key: key) { + try { + model = SearchAppbarModel.fromJson(jsonDecode(data['data'])); + } catch (e) { + Logger.error(e); + } + } + + /// 返回键 + void _openPop(BuildContext context) { + Navigator.maybePop(context); + } + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + color: HexColor.fromHex(model?.app_bar_bg_color ?? '#FFFFFF'), + padding: EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top), + child: _getMainWidget(context), + ); + } + + /// 样式1 + Widget _getMainWidget(BuildContext context) { + return AppBar( + backgroundColor: Colors.transparent, + elevation: 0, + leading: IconButton( + icon: Icon( + Icons.arrow_back_ios, + size: 22, + color: HexColor.fromHex('#333333'), + ), + onPressed: () => _openPop(context), + ), + title: Text( + model?.app_bar_title ?? '搜索', + style: TextStyle(fontWeight: FontWeight.bold, color: HexColor.fromHex(model?.app_bar_title_color ?? '#333333')), + ), + centerTitle: true, + ); + } +} diff --git a/lib/widgets/search/history_tag/history_tag.dart b/lib/widgets/search/history_tag/history_tag.dart new file mode 100644 index 0000000..3261969 --- /dev/null +++ b/lib/widgets/search/history_tag/history_tag.dart @@ -0,0 +1,129 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:zhiying_base_widget/widgets/search/widget/text_tag_widget.dart'; +import 'package:zhiying_base_widget/widgets/search/widget/title_widget.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +/// +/// 历史搜索标签 +/// +class HistoryTagWidget extends StatefulWidget { + final Map data; + + const HistoryTagWidget(this.data); + + @override + _HistoryTagWidgetState createState() => _HistoryTagWidgetState(); +} + +class _HistoryTagWidgetState extends State { + ///文本标签集合 + List _tagList = []; + static final String SP_HOISTROY_KEY = 'hoistroyTag'; + static final int MAX_COUNT = 6; + + /// 点击历史标签 + void _historyTagClick(String tag) {} + + /// 初始化历史搜索标签 + _initHistoryTag() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String jsonStr = prefs.getString(SP_HOISTROY_KEY); + if (null != jsonStr && jsonStr.length > 0) { + final Map jsonMap = jsonDecode(jsonStr); + if (jsonMap != null && jsonMap.length > 0) { + jsonMap.forEach((key, value) => _tagList.insert(0, value)); + } + } + } + + /// 添加搜索 + void _addTag(String tag) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String jsonStr = prefs.getString(SP_HOISTROY_KEY); + if (null != jsonStr && jsonStr.length > 0) { + final Map jsonMap = jsonDecode(jsonStr); + jsonMap[tag.toString()] = tag.toString(); + + _tagList.insert(0, tag); // 第一位 + if (_tagList.length > MAX_COUNT) { + jsonMap.remove(_tagList[_tagList.length - 1]); + _tagList.removeAt(_tagList.length - 1); + } + + prefs.setString(SP_HOISTROY_KEY, jsonEncode(jsonMap)); + } else { + prefs.setString(SP_HOISTROY_KEY, jsonEncode({'${tag.toString()}': '${tag.toString()}'})); + _tagList.add(tag); + } + setState(() {}); + } + + /// 点击清除所有历史记录 + void _clearTag() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setString(SP_HOISTROY_KEY, ''); + } + + @override + void initState() { + _initHistoryTag(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + margin: const EdgeInsets.only(left: 12.5, right: 12.5), + child: Column( + children: [ + /// 标题 + SearchTitleWidget(titleText: '历史搜索', titleTextColor: '#333333', iconUrl: '', callback: () => _clearTag()), + const SizedBox( + height: 10, + ), + + /// 历史标签 + _getHistoryWarp(), + ], + ), + ); + } + + /// 历史搜索的标签 + Widget _getHistoryWarp() { + List itemWidgetList = []; + final int tagListLength = _tagList?.length ?? 0; + if (tagListLength > 0) { + for (var i = 0; i < _tagList.length; i++) { + var str = _tagList[i]; + itemWidgetList.add(GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _historyTagClick(_tagList[i]), + child: TextTagWidget( + "$str", + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10), + margin: const EdgeInsets.only(right: 5, bottom: 0, top: 0), + borderColor: HexColor.fromHex('#EDEDED'), + backgroundColor: Colors.white, + textStyle: TextStyle( + color: HexColor.fromHex('#383838'), + fontSize: 12.5, + ), + ), + )); + } + + return Wrap( + spacing: 8.0, + runSpacing: 8.0, + + ///子标签 + children: itemWidgetList); + } + return Container(); + } +} diff --git a/lib/widgets/search/input/model/search_input_model.dart b/lib/widgets/search/input/model/search_input_model.dart new file mode 100644 index 0000000..6182b53 --- /dev/null +++ b/lib/widgets/search/input/model/search_input_model.dart @@ -0,0 +1,32 @@ +class SearchInputModel { + String search_button; + String search_button_color; + String search_button_t; + String search_icon; + String search_inpu_hint_text; + String skip_identifier; + + SearchInputModel({this.search_button, this.search_button_color, this.search_button_t, this.search_icon, this.search_inpu_hint_text, this.skip_identifier}); + + factory SearchInputModel.fromJson(Map json) { + return SearchInputModel( + search_button: json['search_button'], + search_button_color: json['search_button_color'], + search_button_t: json['search_button_t'], + search_icon: json['search_icon'], + search_inpu_hint_text: json['search_inpu_hint_text'], + skip_identifier: json['skip_identifier'], + ); + } + + Map toJson() { + final Map data = new Map(); + data['search_button'] = this.search_button; + data['search_button_color'] = this.search_button_color; + data['search_button_t'] = this.search_button_t; + data['search_icon'] = this.search_icon; + data['search_inpu_hint_text'] = this.search_inpu_hint_text; + data['skip_identifier'] = this.skip_identifier; + return data; + } +} diff --git a/lib/widgets/search/input/search_input_creater.dart b/lib/widgets/search/input/search_input_creater.dart new file mode 100644 index 0000000..588535b --- /dev/null +++ b/lib/widgets/search/input/search_input_creater.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:zhiying_base_widget/widgets/search/input/search_input_widget.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'package:zhiying_comm/util/custom_sliver_persistent_header_delegate.dart'; + +class SearchInputCreater extends WidgetCreater { + @override + List createWidgets(Map model) { + return [ + SliverPersistentHeader( + delegate: CustomSliverPersistentHeaderDelegate( + child: SearchInputWidget(model), + min: 35, + max: 35, + ), + pinned: true, + floating: false, + ) + ]; + } + + @override + bool isSliverChild() { + return true; + } +} diff --git a/lib/widgets/search/input/search_input_sk.dart b/lib/widgets/search/input/search_input_sk.dart new file mode 100644 index 0000000..a5be3db --- /dev/null +++ b/lib/widgets/search/input/search_input_sk.dart @@ -0,0 +1,36 @@ + + +import 'package:shimmer/shimmer.dart'; +import 'package:flutter/material.dart'; + + +/// +/// 搜索输入框的骨架图 +/// +class SearchInputSkeleton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + margin: const EdgeInsets.only(right: 12.5, left: 12.5, top: 13), + child: _shimmerWidget( + width: double.infinity, + height: 32, + ), + ); + } + + + + Widget _shimmerWidget({double width, double height, double radius = 0}) { + return Shimmer.fromColors( + baseColor: Colors.grey[300], + highlightColor: Colors.grey[100], + child: Container( + width: width, + height: height, + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), + ), + ); + } +} diff --git a/lib/widgets/search/input/search_input_widget.dart b/lib/widgets/search/input/search_input_widget.dart new file mode 100644 index 0000000..8fbcf3e --- /dev/null +++ b/lib/widgets/search/input/search_input_widget.dart @@ -0,0 +1,172 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; +import 'package:zhiying_base_widget/widgets/search/input/model/search_input_model.dart'; +import 'package:zhiying_base_widget/widgets/search/input/search_input_sk.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'package:cached_network_image/cached_network_image.dart'; + +/// +/// 搜索页的搜索框 +/// +class SearchInputWidget extends StatefulWidget { + final Map data; + SearchInputModel model; + + SearchInputWidget(this.data, {Key key}) : super(key: key) { + try { + model = SearchInputModel.fromJson(jsonDecode(data['data'])); + } catch (e) { + Logger.error(e); + } + } + + @override + _SearchInputWidgetState createState() => _SearchInputWidgetState(); +} + +class _SearchInputWidgetState extends State { + /// 点击搜索按钮 + void _onSearchButtomClick() {} + + FocusNode _focusNode; + TextEditingController _editingController; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + } + + @override + void initState() { + _focusNode = FocusNode(); + _editingController = TextEditingController(); + super.initState(); + } + + @override + void dispose() { + _focusNode?.unfocus(); + _focusNode?.dispose(); + _editingController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Visibility( + visible: !EmptyUtil.isEmpty(widget?.model), + replacement: SearchInputSkeleton(), + child: _getMainWidget(widget?.model), + ); + } + + /// 获取主视图 + Widget _getMainWidget(SearchInputModel model) { + return Container( + width: double.infinity, + height: 32, + margin: const EdgeInsets.only( + left: 12.5, + right: 12.5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25), + color: HexColor.fromHex('#F9F9F9'), + ), + child: Row( + children: [ + /// 搜索icon + _getSearchIconWidget(model), + const SizedBox(width: 7.5), + + /// 搜索输入框 + Expanded(child: _getSearchInputWidget(model)), + + /// 搜索按钮 + _getSearchButtomWidget(model), + ], + ), + ); + } + + /// 搜索icon + Widget _getSearchIconWidget(SearchInputModel model) { + return Container( + height: double.infinity, + width: 20, + margin: const EdgeInsets.only(left: 12.5), + padding: const EdgeInsets.symmetric(vertical: 6), + child: CachedNetworkImage( + imageUrl: model?.search_icon ?? '', + ), + ); + } + + /// 搜索输入框 + Widget _getSearchInputWidget(SearchInputModel model) { + return Container( + height: double.infinity, + alignment: Alignment.centerLeft, + // padding: const EdgeInsets.symmetric(vertical: 6), + child: TextField( + showCursor: true, + cursorWidth: 1, + style: TextStyle(fontSize: 14, color: HexColor.fromHex('#333333')), + decoration: InputDecoration( + filled: false, + // focusColor: Colors.transparent, + // fillColor: Colors.transparent, + border: InputBorder.none, + focusedBorder: InputBorder.none, + focusedErrorBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + enabledBorder: InputBorder.none, + hintText: '搜索更多优惠商品', + hintStyle: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 14), + ), + ), + ); + } + + /// 搜索按钮 + Widget _getSearchButtomWidget(SearchInputModel model) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _onSearchButtomClick(), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 17.5, vertical: 6), + decoration: BoxDecoration( + gradient: LinearGradient(colors: [HexColor.fromHex('#FD5E5E'), HexColor.fromHex('#FF0100')], begin: Alignment.centerLeft, end: Alignment.centerRight), + borderRadius: BorderRadius.circular(30), + ), + child: Text( + '搜索', + style: TextStyle(color: HexColor.fromHex('#FFFFFF'), fontSize: 14), + ), + ), + ); + } + + /// 【弃用】搜索按钮 +// Widget _getSearchButtomWidget() { +// return Material( +// child: Container( +// decoration: BoxDecoration( +// borderRadius: BorderRadius.only(topRight: Radius.circular(25), bottomRight: Radius.circular(25)) +// ), +// height: double.infinity, +// width: 63, +// child: RaisedButton( +// padding: const EdgeInsets.only(bottom: 6, top: 6, left: 17.5, right: 17.5), +// shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 25)), +// child: Text('搜索', style: TextStyle( fontSize: 14, color: HexColor.fromHex('#FFFFFF')),), +// onPressed: ()=> _onSearchButtomClick(), +// color: HexColor.fromHex('#FF0100'), +// ), +// ), +// ); +// } +} diff --git a/lib/widgets/search/tabbar/model/search_tab_model.dart b/lib/widgets/search/tabbar/model/search_tab_model.dart new file mode 100644 index 0000000..99ff3c2 --- /dev/null +++ b/lib/widgets/search/tabbar/model/search_tab_model.dart @@ -0,0 +1,55 @@ +class SearchTabModel { + List search_icon_list; + + SearchTabModel({this.search_icon_list}); + + factory SearchTabModel.fromJson(Map json) { + return SearchTabModel( + search_icon_list: json['search_icon_list'] != null ? (json['search_icon_list'] as List).map((i) => SearchTabItemModel.fromJson(i)).toList() : null, + ); + } + + Map toJson() { + final Map data = new Map(); + if (this.search_icon_list != null) { + data['search_icon_list'] = this.search_icon_list.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class SearchTabItemModel { + String icon; + String line_select_color; + String name; + String name_color; + String name_select_color; + String type; + String with_icon_color; + + SearchTabItemModel({this.icon, this.line_select_color, this.name, this.name_color, this.name_select_color, this.type, this.with_icon_color}); + + factory SearchTabItemModel.fromJson(Map json) { + return SearchTabItemModel( + icon: json['icon'], + line_select_color: json['line_select_color'], + name: json['name'], + name_color: json['name_color'], + name_select_color: json['name_select_color'], + type: json['type'], + with_icon_color: json['with_icon_color'], + ); + } + + Map toJson() { + final Map data = new Map(); + data['icon'] = this.icon; + data['line_select_color'] = this.line_select_color; + data['name'] = this.name; + data['name_color'] = this.name_color; + data['name_select_color'] = this.name_select_color; + data['type'] = this.type; + data['with_icon_color'] = this.with_icon_color; + return data; + } +} diff --git a/lib/widgets/search/tabbar/search_tab_creater.dart b/lib/widgets/search/tabbar/search_tab_creater.dart new file mode 100644 index 0000000..b18f337 --- /dev/null +++ b/lib/widgets/search/tabbar/search_tab_creater.dart @@ -0,0 +1,24 @@ +import 'package:flutter/cupertino.dart'; +import 'package:zhiying_base_widget/widgets/search/tabbar/search_tab_widget.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'package:zhiying_comm/util/sliver_tab_bar_delegate.dart'; + +class SearcchTabCreater extends WidgetCreater{ + + @override + List createWidgets(Map model) { + return [ + // SliverPersistentHeader( + // delegate: SliverTabBarDelegate( + // SearchTabWidget(model), + // ), + // ), + SearchTabWidget(model), + ]; + } + + @override + bool isSliverChild() { + return true; + } +} \ No newline at end of file diff --git a/lib/widgets/search/tabbar/search_tab_sk.dart b/lib/widgets/search/tabbar/search_tab_sk.dart new file mode 100644 index 0000000..e8d3fed --- /dev/null +++ b/lib/widgets/search/tabbar/search_tab_sk.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:zhiying_comm/util/shimmer_util.dart'; + +class SearchTabSkeleton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + margin: const EdgeInsets.only(left: 12.5, right: 12.5, top: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ShimmerUtil.getShimmerWidget(width: 45, height: 15), + ShimmerUtil.getShimmerWidget(width: 45, height: 15), + ShimmerUtil.getShimmerWidget(width: 45, height: 15), + ShimmerUtil.getShimmerWidget(width: 45, height: 15), + ShimmerUtil.getShimmerWidget(width: 45, height: 15), + ], + ), + ); + } +} diff --git a/lib/widgets/search/tabbar/search_tab_widget.dart b/lib/widgets/search/tabbar/search_tab_widget.dart new file mode 100644 index 0000000..9bc1bf6 --- /dev/null +++ b/lib/widgets/search/tabbar/search_tab_widget.dart @@ -0,0 +1,105 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:tab_indicator_styler/tab_indicator_styler.dart'; +import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; +import 'package:zhiying_base_widget/widgets/search/tabbar/search_tab_sk.dart'; +import 'package:zhiying_base_widget/widgets/search/widget/my_tab.dart'; + +import 'package:zhiying_comm/zhiying_comm.dart'; + +import 'model/search_tab_model.dart'; + +class SearchTabWidget extends StatefulWidget { + final Map data; + SearchTabModel model; + + SearchTabWidget(this.data, {Key key}) : super(key: key) { + try { + model = SearchTabModel.fromJson(jsonDecode(data['data'])); + } catch (e) { + Logger.error(e.toString()); + } + } + + @override + _SearchTabWidgetState createState() => _SearchTabWidgetState(); +} + +class _SearchTabWidgetState extends State { + TabController _tabController; + int _currentIndex = 0; + + @override + void initState() { + _tabController = TabController(length: widget?.model?.search_icon_list?.length ?? 0, vsync: ScrollableState())..addListener((){ + setState(()=> _currentIndex = _tabController.index); + }); + super.initState(); + } + + @override + void dispose() { + _tabController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return _getMainWidget(widget?.model); + } + + /// 获取主视图 + Widget _getMainWidget(SearchTabModel model) { + return Visibility( + replacement: SearchTabSkeleton(), + visible: !EmptyUtil.isEmpty(model), + child: _getTabar(model), + ); + } + + /// 获取TabBar + Widget _getTabar(SearchTabModel model) { + return Container( + margin: const EdgeInsets.only(left: 12.5, right: 12.5, top: 20), + child: TabBar( + controller: _tabController, + isScrollable: true, + labelStyle: TextStyle( fontSize: 14), + unselectedLabelColor: HexColor.fromHex('#999999'), + labelColor: HexColor.fromHex('#FF4242'), + // indicatorSize: TabBarIndicatorSize.label, + indicator: MaterialIndicator( + height: 2.5, + topLeftRadius: 8, + topRightRadius: 8, + bottomLeftRadius: 8, + bottomRightRadius: 8, + color: HexColor.fromHex('#FF4242'), + horizontalPadding: 25, + ), + tabs: model.search_icon_list.map((item) { + return MyTab( + icon: CachedNetworkImage(imageUrl: item?.with_icon_color ?? '', width: 14,), + text: item.name, + ); + }).toList(), + ), + ); + } +} + + +class SearchTabItemWidget extends StatelessWidget { + final bool isSelect; + final SearchTabItemModel model; + + const SearchTabItemWidget(this.isSelect, this.model); + + @override + Widget build(BuildContext context) { + return Container(); + } +} + diff --git a/lib/widgets/search/widget/color_utils.dart b/lib/widgets/search/widget/color_utils.dart new file mode 100644 index 0000000..fde8fb9 --- /dev/null +++ b/lib/widgets/search/widget/color_utils.dart @@ -0,0 +1,19 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/** + * 创建人: Created by zhaolong + * 创建时间:Created by on 2020/6/26. + * + * 可关注公众号:我的大前端生涯 获取最新技术分享 + * 可关注网易云课堂:https://study.163.com/instructor/1021406098.htm + * 可关注博客:https://blog.csdn.net/zl18603543572 + */ + + +Color getRandomColor() { + return Color.fromARGB(255, Random.secure().nextInt(200), + Random.secure().nextInt(200), Random.secure().nextInt(200)); +} diff --git a/lib/widgets/search/widget/my_tab.dart b/lib/widgets/search/widget/my_tab.dart new file mode 100644 index 0000000..7ac62b9 --- /dev/null +++ b/lib/widgets/search/widget/my_tab.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +const double _kTabHeight = 46.0; +const double _kTextAndIconTabHeight = 40.0; + +/// A material design [TabBar] tab. +/// +/// If both [icon] and [text] are provided, the text is displayed below +/// the icon. +/// +/// See also: +/// +/// * [TabBar], which displays a row of tabs. +/// * [TabBarView], which displays a widget for the currently selected tab. +/// * [TabController], which coordinates tab selection between a [TabBar] and a [TabBarView]. +/// * +class MyTab extends StatelessWidget { + /// Creates a material design [TabBar] tab. + /// + /// At least one of [text], [icon], and [child] must be non-null. The [text] + /// and [child] arguments must not be used at the same time. + const MyTab({ + Key key, + this.text, + this.icon, + this.child, + }) : assert(text != null || child != null || icon != null), + assert(!(text != null && null != child)), + // TODO(goderbauer): https://github.com/dart-lang/sdk/issues/34180 + super(key: key); + + /// The text to display as the tab's label. + /// + /// Must not be used in combination with [child]. + final String text; + + /// The widget to be used as the tab's label. + /// + /// Usually a [Text] widget, possibly wrapped in a [Semantics] widget. + /// + /// Must not be used in combination with [text]. + final Widget child; + + /// An icon to display as the tab's label. + final Widget icon; + + Widget _buildLabelText() { + return child ?? Text(text, softWrap: false, overflow: TextOverflow.fade); + } + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMaterial(context)); + + double height; + Widget label; + if (icon == null) { + height = _kTabHeight; + label = _buildLabelText(); + } else if (text == null && child == null) { + height = _kTabHeight; + label = icon; + } else { + height = _kTextAndIconTabHeight; + label = Row( + children: [ + Container(child: icon, margin: const EdgeInsets.only(right: 5),), + _buildLabelText(), + ], + ); + } + + return SizedBox( + height: height, + child: Center( + child: label, + widthFactor: 1.0, + ), + ); + } + +} diff --git a/lib/widgets/search/widget/text_tag_widget.dart b/lib/widgets/search/widget/text_tag_widget.dart new file mode 100644 index 0000000..4d4b058 --- /dev/null +++ b/lib/widgets/search/widget/text_tag_widget.dart @@ -0,0 +1,81 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'color_utils.dart'; + +/** + * 创建人: Created by zhaolong + * 创建时间:Created by on 2020/6/26. + * + * 可关注公众号:我的大前端生涯 获取最新技术分享 + * 可关注网易云课堂:https://study.163.com/instructor/1021406098.htm + * 可关注博客:https://blog.csdn.net/zl18603543572 + */ +class TextTagWidget extends StatefulWidget { + ///显示的文本 + String text; + EdgeInsets margin; + EdgeInsets padding; + + TextStyle textStyle; + + Color backgroundColor; + Color borderColor; + + double borderRadius; + + TextTagWidget( + this.text, { + this.margin = const EdgeInsets.all(4), + this.padding = const EdgeInsets.only(left: 6, right: 6, top: 3, bottom: 3), + this.textStyle, + this.backgroundColor, + this.borderColor, + this.borderRadius = 20.0, + }) { + if (this.borderColor == null) { + if (this.backgroundColor != null) { + this.borderColor = this.backgroundColor; + } else { + this.borderColor = getRandomColor(); + } + } + + if (this.textStyle == null) { + Color textColor = this.borderColor; + if (backgroundColor != null) { + textColor = Colors.white; + } + this.textStyle = TextStyle(fontSize: 12, color: textColor); + } + + if (this.backgroundColor == null) { + this.backgroundColor = Colors.transparent; + } + } + + @override + _TestPageState createState() => _TestPageState(); +} + +//lib/code/main_data.dart +class _TestPageState extends State { + @override + Widget build(BuildContext context) { + return Container( + margin: widget.margin, + padding: widget.padding, + decoration: BoxDecoration(color: widget.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)), border: Border.all(color: widget.borderColor)), + child: buildTextWidget(), + ); + } + + ///构建文本 + Text buildTextWidget() { + return Text( + widget.text, + style: widget.textStyle, + textAlign: TextAlign.center, + ); + } +} diff --git a/lib/widgets/search/widget/title_widget.dart b/lib/widgets/search/widget/title_widget.dart new file mode 100644 index 0000000..d885654 --- /dev/null +++ b/lib/widgets/search/widget/title_widget.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +class SearchTitleWidget extends StatelessWidget { + final String titleText; + final String titleTextColor; + final String iconUrl; + final VoidCallback callback; + + const SearchTitleWidget({ + this.titleText, + this.titleTextColor, + this.iconUrl, + this.callback, + }); + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + /// 标题 + _title(), + + /// icon + Visibility(visible: !EmptyUtil.isEmpty(iconUrl), child: _icon()), + ], + ), + ); + } + + Widget _title() { + return Text( + titleText, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: HexColor.fromHex(titleTextColor), + ), + ); + } + + Widget _icon() { + return GestureDetector( + onTap: callback, + child: CachedNetworkImage( + imageUrl: iconUrl ?? '', + width: 15, + fit: BoxFit.fill, + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 208c6d2..c3d8a68 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: pull_to_refresh: ^1.6.1 flutter_cupertino_date_picker: ^1.0.26+2 image_picker: ^0.6.7+3 + tab_indicator_styler: 1.0.0 image_cropper: git: url: 'http://192.168.0.138:3000/FnuoOS_Flutter_Components/Image_Cropper.git'