diff --git a/lib/pages/custom_page/bloc/custom_item_page_bloc.dart b/lib/pages/custom_page/bloc/custom_item_page_bloc.dart new file mode 100644 index 0000000..ef870eb --- /dev/null +++ b/lib/pages/custom_page/bloc/custom_item_page_bloc.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:zhiying_base_widget/pages/custom_page/bloc/custom_item_page_repository.dart'; +import 'custom_item_page_state.dart'; +import 'custom_item_page_event.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +class CustomItemPageBloc extends Bloc { + // CustomItemPageBloc() : super(CustomItemPageInitial()); + + CustomItemPageRepository repository; + + CustomItemPageBloc(this.repository); + + @override + CustomItemPageState get initialState => CustomItemPageInitial(); + + @override + Stream mapEventToState( + CustomItemPageEvent event, + ) async* { + /// 初始化 + if (event is CustomItemPageInitEvent) { + yield* _mapInitEventToState(event); + } + + /// 下拉刷新 + if (event is CustomItemPageRefreshEvent) { + yield* _mapRefreshEventToState(event); + } + + /// 上拉更多 + if (event is CustomItemPageLoadEvent) { + yield* _mapLoadEventToState(event); + } + } + + /// 初始化 + Stream _mapInitEventToState(CustomItemPageInitEvent event) async* { + var cacheStyle = await repository.fetchCacheStyle(); + if (!EmptyUtil.isEmpty(cacheStyle)) { + yield CustomItemPageLoadedState(model: cacheStyle); + } + var netStyle = await repository.fetchNetStyle(); + if (!EmptyUtil.isEmpty(netStyle) && netStyle is List) { + yield CustomItemPageLoadedState(model: netStyle); + } else { + yield CustomItemPageInitErrorState(); + } + } + + /// 下拉刷新 + Stream _mapRefreshEventToState(CustomItemPageRefreshEvent event) async* { + var netStyle = await repository.fetchNetStyle(); + if (!EmptyUtil.isEmpty(netStyle)) { + yield CustomItemPageRefreshSuccessState(); + yield CustomItemPageLoadedState(model: netStyle); + } else { + yield CustomItemPageRefreshErrorState(); + yield CustomItemPageErrorState(); + } + } + + /// 上拉更多 + Stream _mapLoadEventToState(CustomItemPageLoadEvent event) async* {} +} diff --git a/lib/pages/custom_page/bloc/custom_item_page_event.dart b/lib/pages/custom_page/bloc/custom_item_page_event.dart new file mode 100644 index 0000000..498cefa --- /dev/null +++ b/lib/pages/custom_page/bloc/custom_item_page_event.dart @@ -0,0 +1,13 @@ +import 'package:meta/meta.dart'; + +@immutable +abstract class CustomItemPageEvent {} + +/// 初始化 +class CustomItemPageInitEvent extends CustomItemPageEvent {} + +/// 下拉刷新 +class CustomItemPageRefreshEvent extends CustomItemPageEvent {} + +/// 上拉更多 +class CustomItemPageLoadEvent extends CustomItemPageEvent {} diff --git a/lib/pages/custom_page/bloc/custom_item_page_repository.dart b/lib/pages/custom_page/bloc/custom_item_page_repository.dart new file mode 100644 index 0000000..43d241d --- /dev/null +++ b/lib/pages/custom_page/bloc/custom_item_page_repository.dart @@ -0,0 +1,56 @@ +import 'package:zhiying_comm/zhiying_comm.dart'; + +class CustomItemPageRepository { + final Map data; + final int tabIndex; + final String modId; + final String modPid; + + CustomItemPageRepository(this.data, this.tabIndex, this.modId, this.modPid); + + /// 获取网络Style + Future>> fetchNetStyle() async { + try { + String reqUrl = _buildRequestUrl(); + if (!EmptyUtil.isEmpty(reqUrl)) { + var result = await NetUtil.post(reqUrl, method: NetMethod.GET, cache: true); + if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { + List mobList = !EmptyUtil.isEmpty(data) ? List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA][tabIndex.toString()]) : List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); + if (!EmptyUtil.isEmpty(mobList)) { + return mobList.map((e) => Map.from(e)).toList(); + } + } + } + } catch (e, s) { + Logger.error(e, s); + } + return null; + } + + /// 获取缓存Style + Future>> fetchCacheStyle() async { + try { + String reqUrl = _buildRequestUrl(); + if (!EmptyUtil.isEmpty(reqUrl)) { + var result = await NetUtil.getRequestCachedData(reqUrl); + if (!EmptyUtil.isEmpty(result)) { + List mobList = !EmptyUtil.isEmpty(data) ? List.from(result[tabIndex.toString()]) : List.from(result); + if (!EmptyUtil.isEmpty(mobList)) { + return mobList.map((e) => Map.from(e)).toList(); + } + } + } + } catch (e, s) { + Logger.error(e, s); + } + return null; + } + + String _buildRequestUrl() { + if (!EmptyUtil.isEmpty(data)) { + return '/api/v1/custom/mod/$modId'; + } else { + return '/api/v1/custom/mod/${modPid}?is_cate=1'; + } + } +} diff --git a/lib/pages/custom_page/bloc/custom_item_page_state.dart b/lib/pages/custom_page/bloc/custom_item_page_state.dart new file mode 100644 index 0000000..3b06936 --- /dev/null +++ b/lib/pages/custom_page/bloc/custom_item_page_state.dart @@ -0,0 +1,32 @@ +import 'package:meta/meta.dart'; + +@immutable +abstract class CustomItemPageState {} + +/// 骨架图状态 +class CustomItemPageInitial extends CustomItemPageState {} + +/// 数据加载成功 +class CustomItemPageLoadedState extends CustomItemPageState { + final List> model; + + CustomItemPageLoadedState({this.model}); +} + +/// 初始化失败 +class CustomItemPageInitErrorState extends CustomItemPageState {} + +/// 下拉刷新成功 +class CustomItemPageRefreshSuccessState extends CustomItemPageState {} + +/// 下拉刷新失败 +class CustomItemPageRefreshErrorState extends CustomItemPageState {} + +/// 上拉更多成功 +class CustomItemPageLoadSuccessState extends CustomItemPageState {} + +/// 上拉更多失败 +class CustomItemPageLoadErrorState extends CustomItemPageState {} + +/// 其他错误 +class CustomItemPageErrorState extends CustomItemPageState {} diff --git a/lib/pages/custom_page/bloc/custom_page_repository.dart b/lib/pages/custom_page/bloc/custom_page_repository.dart index dbeea7b..72db1ed 100644 --- a/lib/pages/custom_page/bloc/custom_page_repository.dart +++ b/lib/pages/custom_page/bloc/custom_page_repository.dart @@ -8,12 +8,16 @@ class CustomPageRepository { /// 初始化 Future>> fetchInitData() async { try { - String skipIdentifier = !EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER]) - ? data[GlobalConfig.SKIP_IDENTIFIER] - : null; + String skipIdentifier = + !EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER]) ? data[GlobalConfig.SKIP_IDENTIFIER] : null; if (!EmptyUtil.isEmpty(skipIdentifier)) { - var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET); - if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {} + var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET, cache: true); + if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { + List mobList = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); + if (!EmptyUtil.isEmpty(mobList)) { + return mobList.map((e) => Map.from(e)).toList(); + } + } } } catch (e, s) { Logger.error(e, s); @@ -23,7 +27,19 @@ class CustomPageRepository { /// 缓存数据 Future>> fetchCacheData() async { - try {} catch (e, s) { + try { + String skipIdentifier = + !EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER]) ? data[GlobalConfig.SKIP_IDENTIFIER] : null; + if (!EmptyUtil.isEmpty(skipIdentifier)) { + var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skipIdentifier'); + if (!EmptyUtil.isEmpty(result)) { + List mobList = result['mod_list']; + if (!EmptyUtil.isEmpty(mobList)) { + return mobList.map((e) => Map.from(e)).toList(); + } + } + } + } catch (e, s) { Logger.error(e, s); } return null; diff --git a/lib/pages/custom_page/bloc/custom_page_state.dart b/lib/pages/custom_page/bloc/custom_page_state.dart index 3f1bc93..7d9bf3b 100644 --- a/lib/pages/custom_page/bloc/custom_page_state.dart +++ b/lib/pages/custom_page/bloc/custom_page_state.dart @@ -1,7 +1,11 @@ import 'package:meta/meta.dart'; +import 'package:equatable/equatable.dart'; @immutable -abstract class CustomPageState {} +abstract class CustomPageState extends Equatable{ + @override + List get props => []; +} /// 初始化 class CustomPageInitialState extends CustomPageState {} @@ -10,6 +14,8 @@ class CustomPageInitialState extends CustomPageState {} class CustomPageLoadedState extends CustomPageState { List> model; CustomPageLoadedState({this.model}); + @override + List get props => [this.model]; } /// 刷新成功 diff --git a/lib/pages/custom_page/custom_item_page.dart b/lib/pages/custom_page/custom_item_page.dart new file mode 100644 index 0000000..fd3134e --- /dev/null +++ b/lib/pages/custom_page/custom_item_page.dart @@ -0,0 +1,188 @@ +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; +import 'package:zhiying_base_widget/widgets/refresh/refresh_footer/refresh_footer.dart'; +import 'package:zhiying_base_widget/widgets/refresh/refresh_header/refresh_header.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'bloc/custom_item_page_bloc.dart'; +import 'bloc/custom_item_page_state.dart'; +import 'bloc/custom_item_page_event.dart'; +import 'bloc/custom_item_page_repository.dart'; + +/// +/// 通用模块的分类导航下的子模块 +/// +/// +class CustomItemPage extends StatelessWidget { + final Map data; + final int tabIndex; + final String modPid; + final String modId; + + CustomItemPage(this.data, this.tabIndex, this.modId, this.modPid); + + @override + Widget build(BuildContext context) { + return MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: MainPageNotifier()), + ], + child: BlocProvider( + create: (_) => CustomItemPageBloc(CustomItemPageRepository(this.data, this.tabIndex, this.modId, this.modPid)), + child: _CustomItemPageContainer( + this.data, + this.tabIndex, + this.modId, + this.modPid, + key: UniqueKey(), + ), + ), + ); + } +} + +class _CustomItemPageContainer extends StatefulWidget { + final Map data; + final int tabIndex; + final String modPid; + final String modId; + + const _CustomItemPageContainer(this.data, this.tabIndex, this.modId, this.modPid, {Key key}) : super(key: key); + + @override + __CustomItemPageContainerState createState() => __CustomItemPageContainerState(); +} + +class __CustomItemPageContainerState extends State<_CustomItemPageContainer> with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + ScrollController _controller; + RefreshController _refreshController; + + /// 回到顶点 + void _scrollTop() { + // _controller.jumpTo(0); + _controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.linear); + } + + /// 初始化 + void _initEvent() { + BlocProvider.of(context).add(CustomItemPageInitEvent()); + } + + /// 刷新 + void _refreshEvent() { + BlocProvider.of(context).add(CustomItemPageRefreshEvent()); + } + + /// 下拉更多 + void _loadEvent() { + // BlocProvider.of(context).add(CustomItemPageLoadEvent()); + Provider.of(context, listen: false).loadMore(); + Future.delayed(Duration(seconds: 1),()=> _refreshController?.loadComplete()); + } + + @override + void initState() { + _controller = ScrollController(); + _refreshController = RefreshController(initialRefresh: false); + _initEvent(); + super.initState(); + } + + @override + void dispose() { + _controller?.dispose(); + _refreshController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocConsumer( + listener: (context, state) {}, + buildWhen: (prev, current) { + if (current is CustomItemPageRefreshSuccessState) { + _refreshController?.refreshCompleted(resetFooterState: true); + return false; + } + if (current is CustomItemPageRefreshErrorState) { + _refreshController?.refreshFailed(); + return false; + } + if (current is CustomItemPageLoadSuccessState) { + _refreshController?.loadComplete(); + return false; + } + if (current is CustomItemPageLoadErrorState) { + _refreshController?.loadNoData(); + return false; + } + if (current is CustomItemPageErrorState) { + return false; + } + return true; + }, + builder: (context, state) { + if (state is CustomItemPageLoadedState) { + if (EmptyUtil.isEmpty(state.model)) + return _buildEmptyWidget(); + else + return _buildMainWidget(state.model); + } + if (state is CustomItemPageInitErrorState) { + return _buildEmptyWidget(); + } + return _buildSkeletonWidget(); + }, + ); + } + + /// 有数据 + Widget _buildMainWidget(final List> model) { + return MediaQuery.removePadding( + context: context, + removeTop: true, + child: SmartRefresher( + controller: _refreshController, + enablePullDown: true, + enablePullUp: true, + onRefresh: _refreshEvent, + onLoading: _loadEvent, + header: RefreshHeader(), + footer: RefreshFooter(), + child: CustomScrollView( + controller: _controller, + slivers: _buildContentWidgets(model), + ), + ), + ); + } + + /// 根据widget的modName生成视图 + List _buildContentWidgets(final List> datas) { + List result = []; + for (int i = 0; i < datas.length; i++) { + WidgetModel item = WidgetModel.fromJson(Map.from(datas[i])); + result.addAll(WidgetFactory.create( + item.modName, + isSliver: true, + model: datas[i], + )); + } + return result; + } + + /// 空数据 + Widget _buildEmptyWidget() { + return Container(); + } + + /// 骨架图 + Widget _buildSkeletonWidget() { + return Container(); + } +} diff --git a/lib/pages/custom_page/custom_page.dart b/lib/pages/custom_page/custom_page.dart index b3c645b..dab0e5c 100644 --- a/lib/pages/custom_page/custom_page.dart +++ b/lib/pages/custom_page/custom_page.dart @@ -1,17 +1,22 @@ +import 'dart:convert'; + import 'package:flutter/cupertino.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:tab_indicator_styler/tab_indicator_styler.dart'; +import 'package:zhiying_base_widget/pages/custom_page/custom_item_page.dart'; +import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; +import 'package:zhiying_base_widget/widgets/custom/search/custom_search_widget.dart'; import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart'; -import 'package:zhiying_base_widget/widgets/refresh/refresh_header/refresh_header.dart'; import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:zhiying_comm/util/custom_sliver_persistent_header_delegate.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'bloc/custom_page_bloc.dart'; import 'bloc/custom_page_state.dart'; import 'bloc/custom_page_event.dart'; import 'bloc/custom_page_repository.dart'; import 'dart:ui'; +import 'package:fluttertoast/fluttertoast.dart'; /// /// 通用模块页面 @@ -24,55 +29,39 @@ class CustomPage extends StatelessWidget { @override Widget build(BuildContext context) { // return NestedScrollDemoPage(); - return BlocProvider( - create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()), - child: _CommonPageContainer(), - // ), + return MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: MainPageBgNotifier()), + ], + child: BlocProvider( + create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()), + child: _CommonPageContainer(data), + // ), + ), ); } } class _CommonPageContainer extends StatefulWidget { + final Map data; + + _CommonPageContainer(this.data); + @override __CommonPageContainerState createState() => __CommonPageContainerState(); } class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin { - ScrollController _controller; - ScrollController _controller2; - RefreshController _refreshController; TabController _tabController; - bool _isEnded = false; - - /// 回到顶点 - void _scrollTop() { - // _controller.jumpTo(0); - _controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.linear); - } /// 刷新 void _onRefreshEvent() async { BlocProvider.of(context).add(CustomPageRefreshEvent()); } - /// 加载更多 - void _onLoadEvent() async {} - - @override - void initState() { - _controller = ScrollController(); - _controller2 = ScrollController(); - _refreshController = RefreshController(initialRefresh: false); - _tabController = TabController(length: 10, vsync: this); - super.initState(); - } - @override void dispose() { - _controller?.dispose(); - _refreshController?.dispose(); _tabController?.dispose(); - _controller2?.dispose(); super.dispose(); } @@ -87,244 +76,43 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single return false; } if (current is CustomPageRefreshSuccessState) { - _refreshController.refreshCompleted(resetFooterState: true); + // _refreshController.refreshCompleted(resetFooterState: true); return false; } if (current is CustomPageRefreshErrorState) { - _refreshController.refreshFailed(); + // _refreshController.refreshFailed(); return false; } return true; }, builder: (context, state) { - // if (state is CustomPageLoadedState) { - // return _buildMain2Widget(); - // } - // if (state is CustomPageInitErrorState) { - // return _buildMain2Widget(); - // } - // return _buildMain2Widget(); - - return _buildMain2Widget(); - }, - ), - ); - } - - /// 有数据 - Widget _buildMainWidget() { - double top = MediaQueryData.fromWindow(window).padding.top; - return Scaffold( - backgroundColor: HexColor.fromHex('#F9F9F9'), - floatingActionButton: _buildFloatWidget(), - floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100), - body: SmartRefresher( - enablePullDown: true, - enablePullUp: false, - header: RefreshHeader( - offsetY: top, - ), - controller: _refreshController, - onLoading: _onLoadEvent, - onRefresh: _onRefreshEvent, - child: CustomScrollView( - key: UniqueKey(), - controller: _controller, - slivers: [ - /// 标题 - SliverAppBar( - title: Text('标题'), - centerTitle: true, - pinned: true, - ), - + /// 有数据 + if (state is CustomPageLoadedState) { + if (EmptyUtil.isEmpty(state.model)) return _buildEmptyWidget(); + return _buildMainWidget(state.model); + } - /// 轮播图 - _buildSliverBanner(), - - /// 搜索 - _buildSearch(), - - /// TAB BAR - _buildTabbar(), - - SliverFillRemaining( - child: TabBarView( - controller: _tabController, - children: List.generate(10, (index) => Container( - height: double.infinity, - width: double.infinity, - color: Colors.white, - child: MediaQuery.removePadding( - context: context, - removeTop: true, - child: CustomScrollView( - controller: _controller2, - key: UniqueKey(), - slivers: [ - _buildQucikEntry(), - _buildSearch(), - _buildSliverBanner(), - _buildGoodsList(), - - ], - ), - ), - )), - ), - ) + /// 初始化失败 + if (state is CustomPageInitErrorState) { + return _buildEmptyWidget(); + } - ], - ), + /// 骨架图 + return _buildSkeletonWidget(); + }, ), ); } - /// 有数据2 - Widget _buildMain2Widget(){ + /// 有数据 + Widget _buildMainWidget(List> model) { return Scaffold( - appBar: AppBar(title: Text('标题'),centerTitle: true,), + appBar: _buildAppbar(model?.first), backgroundColor: HexColor.fromHex('#F9F9F9'), - floatingActionButton: _buildFloatWidget(), + // floatingActionButton: _buildFloatWidget(), floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100), - body: Column( - children: [ - Container(height: 40, width: double.infinity, color: Colors.green,), - Container( - height: 40, - width: double.infinity, - color: Colors.red, - child: TabBar( - isScrollable: true, - controller: _tabController, - tabs: List.generate(10, (index) => Text('$index')), - ), - ), - Expanded( - child: TabBarView( - controller: _tabController, - children: List.generate(10, (index) => Container( - height: double.infinity, - width: double.infinity, - color: Colors.white, - child: MediaQuery.removePadding( - context: context, - removeTop: true, - child: CustomScrollView( - controller: _controller, - key: UniqueKey(), - slivers: [ - _buildQucikEntry(), - _buildSearch(), - _buildSliverBanner(), - _buildSearch(title: '商品列表'), - _buildGoodsList(), - - ], - ), - ), - )), - ), - ) - ], - ), - ); - } - - /// tabBar - Widget _buildTabbar(){ - return SliverPersistentHeader( - delegate: CustomSliverPersistentHeaderDelegate( - max: 40, - min: 40, - child: Container( - height: double.infinity, - width: double.infinity, - color: Colors.redAccent, - child: TabBar( - isScrollable: true, - controller: _tabController, - tabs: List.generate(10, (index) => Text('$index')), - ), - ), - ), - pinned: true, - ); - } - - /// 多眼导航 - Widget _buildQucikEntry(){ - return SliverToBoxAdapter( - child: Container( - alignment: Alignment.center, - child: Text('多眼导航'), - height: 70, - width: double.infinity, - color: Colors.green, - ), - ); - } - - /// 搜索 - Widget _buildSearch({String title}){ - return SliverPersistentHeader( - delegate: CustomSliverPersistentHeaderDelegate( - max: 40, - min: 40, - child: Container( - alignment: Alignment.center, - child: Text(title ?? '搜索'), - height: double.infinity, - width: double.infinity, - color: Colors.blueAccent, - ), - ), - pinned: true, - ); - } - - /// 商品列表 - Widget _buildGoodsList(){ - return SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - return Container( - height: 50, - width: double.infinity, - color: Colors.green[(index % 9 + 1) * 100], - ); - }, childCount: 50)); - } - - /// 轮播图 - Widget _buildSliverBanner(){ - return SliverPersistentHeader( - delegate: CustomSliverPersistentHeaderDelegate( - max: 140, - min: 140, - child: Container( - child: Text('轮播图'), - alignment: Alignment.center, - height: double.infinity, - width: double.infinity, - color: Colors.yellowAccent, - ), - ), - pinned: false, - ); - } - - /// 悬浮按钮 - Widget _buildFloatWidget() { - return Visibility( - visible: true, - child: GestureDetector( - onTap: ()=> _scrollTop(), - behavior: HitTestBehavior.opaque, - child: Container( - height: 30, - width: 30, - color: Colors.redAccent, - ), + body: Column( + children: _buildFirstWidget(model), ), ); } @@ -350,8 +138,8 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single onPressed: () => Navigator.maybePop(context), ), title: Text( - '爆款', - style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 15, fontWeight: FontWeight.bold), + '', + style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 18, fontWeight: FontWeight.bold), ), centerTitle: true, elevation: 0, @@ -383,8 +171,179 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single ], )); } + + /// 数据,生成第一层widget + List _buildFirstWidget(List> model) { + List result = []; + + // 分类导航的key ⚠️ 这里先写成Test 后续要改 + const String CATEGORY_KEY = 'category_test'; + // 判断是否有分类导航 + // 判断最后一个是否属于分类导航,如果属于,则有分类导航,如果不是,则无分类导航 + bool haveCategory = !EmptyUtil.isEmpty(model?.last) && model.last.containsKey('mod_name') && model.last['mod_name'] == CATEGORY_KEY; + int endIndexLength = model.length; + // 如果没有分类导航,则取分类导航之上的所有mod + if (!haveCategory) { + for (int i = 0; i < model.length; i++) { + Map item = model[i]; + if (item['mod_name'] == CATEGORY_KEY) { + endIndexLength = (i + 1); + break; + } + } + } + + for (int i = 0; i < endIndexLength; i++) { + WidgetModel item = WidgetModel.fromJson(Map.from(model[i])); + // last model + if (i == endIndexLength - 1) { + result.addAll(_buildTabBar(model[i])); + break; + } + + // appBar 无需在这里添加 + if (item.modName.contains('appbar')) { + continue; + } + + result.addAll(WidgetFactory.create( + item.modName, + isSliver: false, + model: model[i], + )); + } + + return result; + } + + /// appbar + Widget _buildAppbar(final Map model) { + if (EmptyUtil.isEmpty(model)) return null; + String mobName = model['mod_name']; + if (!mobName.contains('_appbar')) return null; + Map data = Map(); + try { + data = jsonDecode(model['data']); + } catch (e, s) { + Logger.warn(e, s); + } + + String parentTitle = !EmptyUtil.isEmpty(widget?.data) ? widget?.data['title_1'] ?? '' : ''; + + return AppBar( + backgroundColor: HexColor.fromHex(null != data ? data['app_bar_bg_color'] ?? '#FFFFFF' : '#FFFFFF'), + brightness: Brightness.light, + leading: IconButton( + icon: Icon( + Icons.arrow_back_ios, + size: 22, + color: HexColor.fromHex('#333333'), + ), + onPressed: () => Navigator.maybePop(context), + ), + title: Text( + null != data && data.containsKey('app_bar_name') ? data['app_bar_name'] != '自定义页面' ? data['app_bar_name'] : parentTitle : parentTitle, + style: TextStyle( + color: HexColor.fromHex(null != data ? data['app_bar_name_color'] ?? '#333333' : '#333333'), + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + centerTitle: true, + elevation: 0, + ); + } + + /// tabBar + List _buildTabBar(final Map model) { + Map data = Map(); + List> listStyle = []; + List result = []; + try { + data = jsonDecode(model['data']); + listStyle = List.from(data['list_style']); + } catch (e, s) { + Logger.warn(e, s); + } + + // 1、导航栏没开启的情况 传null进去进行获取没开启导航栏的widget集合 + if (EmptyUtil.isEmpty(listStyle)) { + result.add(Expanded( + child: CustomItemPage(null, 0, model['mod_id']?.toString() ?? null, model['mod_pid']?.toString() ?? null), + )); + return result; + } + + // 2、导航栏开启的情况 + if (listStyle.length > 0) { + // tabContorller 初始化 + if (null == _tabController || _tabController.length != listStyle.length) { + _tabController = new TabController(length: listStyle.length, vsync: this); + } + result.add(Container( + height: 40, + width: double.infinity, + color: HexColor.fromHex('#FFFFFF'), + child: TabBar( + controller: _tabController, + isScrollable: /*listStyle.length <= 5 ? false : */ true, + labelColor: HexColor.fromHex('#FF4242'), + labelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + unselectedLabelColor: HexColor.fromHex('#999999'), + unselectedLabelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + indicatorSize: TabBarIndicatorSize.label, + indicator: MaterialIndicator( + color: HexColor.fromHex('#FF4242'), + bottomLeftRadius: 1.25, + topLeftRadius: 1.25, + topRightRadius: 1.25, + bottomRightRadius: 1.25, + height: 2.5, + horizontalPadding: 5, + ), + tabs: listStyle.map((e) => Text(e['name'])).toList(), + ), + )); + + // 最后添加TabBarView + result.add(Expanded( + child: TabBarView( + controller: _tabController, + children: _buildTabBarViewChildren(listStyle, model['mod_id']?.toString(), model['mod_pid']?.toString()), + ), + )); + } + return result; + } + + /// 返回TabBarView的视图 + List _buildTabBarViewChildren(final List> listStyle, final String modId, final String modPid) { + List result = []; + for (int i = 0; i < listStyle.length; i++) { + result.add(CustomItemPage(listStyle[i], i, modId, modPid)); + } + return result; + } + +// /// 悬浮按钮 +// Widget _buildFloatWidget() { +// return Visibility( +// visible: true, +// child: GestureDetector( +// onTap: () => _scrollTop(), +// behavior: HitTestBehavior.opaque, +// child: Container( +// height: 30, +// width: 30, +// child: Icon(Icons.arrow_upward), +// ), +// ), +// ); +// } + } +/// 回到顶部的icon class _CustomFloatingActionButtonLocation extends FloatingActionButtonLocation { FloatingActionButtonLocation location; double offsetX; // X方向的偏移量 diff --git a/lib/pages/goods_details_page/goods_details_page.dart b/lib/pages/goods_details_page/goods_details_page.dart index 8963fdc..50d4b53 100644 --- a/lib/pages/goods_details_page/goods_details_page.dart +++ b/lib/pages/goods_details_page/goods_details_page.dart @@ -8,6 +8,7 @@ import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_ import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_repository.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page_sk.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart'; +import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; import 'package:zhiying_base_widget/widgets/goods_details/appbar/goods_details_appbar_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; import 'package:zhiying_comm/zhiying_comm.dart'; @@ -35,7 +36,7 @@ class _GoodsDetailsPageState extends State { return MultiProvider( providers: [ /// 滑动通知 - ChangeNotifierProvider.value(value: GoodsDetailsPageNotifier()), + ChangeNotifierProvider.value(value: MainPageNotifier()), ChangeNotifierProvider.value(value: GoodsDetailsAppBarColorNotifier()), ], child: BlocProvider( @@ -83,10 +84,10 @@ class _GoodsDetailsContainerState extends State { if (_controller.offset >= _controller.position.maxScrollExtent && !_isEnded) { // 滑动到底部 _isEnded = true; - Provider.of(context, listen: false).loadMore(); + Provider.of(context, listen: false).loadMore(); } else if (_controller.offset < _controller.position.maxScrollExtent && _isEnded) { _isEnded = false; - Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); } if (_controller.offset >= 0 && _controller.offset <= BANNER_HEIGHT) { diff --git a/lib/pages/goods_details_page/notifier/goods_details_page_notifier.dart b/lib/pages/goods_details_page/notifier/goods_details_page_notifier.dart index 7e041d7..f8159e4 100644 --- a/lib/pages/goods_details_page/notifier/goods_details_page_notifier.dart +++ b/lib/pages/goods_details_page/notifier/goods_details_page_notifier.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; -class GoodsDetailsPageNotifier with ChangeNotifier { - bool scrollEnd = false; - - // 加载更多数据 - void loadMore() { - scrollEnd = true; - notifyListeners(); - } - - void reset() { - scrollEnd = false; - notifyListeners(); - } -} +// class GoodsDetailsPageNotifier with ChangeNotifier { +// bool scrollEnd = false; +// +// // 加载更多数据 +// void loadMore() { +// scrollEnd = true; +// notifyListeners(); +// } +// +// void reset() { +// scrollEnd = false; +// notifyListeners(); +// } +// } diff --git a/lib/pages/main_page/main_page.dart b/lib/pages/main_page/main_page.dart index fdbd12c..f99f93c 100644 --- a/lib/pages/main_page/main_page.dart +++ b/lib/pages/main_page/main_page.dart @@ -173,9 +173,9 @@ class _MainPageContainerState extends State<_MainPageContainer> { list.add(SliverToBoxAdapter( child: Container( height: 200, - child: Center( - child: Text('暂时无数据哦~'), - ), + // child: Center( + // child: Text('暂时无数据哦~'), + // ), ), )); } diff --git a/lib/widgets/custom/tabbar/custom_tabbar_widget.dart b/lib/pages/main_page/main_page_skeleton.dart similarity index 50% rename from lib/widgets/custom/tabbar/custom_tabbar_widget.dart rename to lib/pages/main_page/main_page_skeleton.dart index 4bda984..82e4f36 100644 --- a/lib/widgets/custom/tabbar/custom_tabbar_widget.dart +++ b/lib/pages/main_page/main_page_skeleton.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:zhiying_comm/zhiying_comm.dart'; - /// -/// 通用模块的tabbar +/// 首页的骨架图 /// -class CustomTabBarWidget extends StatelessWidget { +class MainPageSkeleton extends StatelessWidget { @override Widget build(BuildContext context) { return Container(); diff --git a/lib/pages/wechat_teacher_page/model/wechat_teacher_style_model.dart b/lib/pages/wechat_teacher_page/model/wechat_teacher_style_model.dart index c549299..0d2c659 100644 --- a/lib/pages/wechat_teacher_page/model/wechat_teacher_style_model.dart +++ b/lib/pages/wechat_teacher_page/model/wechat_teacher_style_model.dart @@ -265,16 +265,16 @@ class OfficalWxchat { } class OfficalWxchatList { - String type; + String index; String text; String subText; String wechatAccount; String qrcode; - OfficalWxchatList({this.type, this.text, this.subText, this.wechatAccount, this.qrcode}); + OfficalWxchatList({this.index, this.text, this.subText, this.wechatAccount, this.qrcode}); OfficalWxchatList.fromJson(Map json) { - type = json['type']; + index = json['index']; text = json['text']; subText = json['sub_text']; wechatAccount = json['wechat_account']; @@ -283,7 +283,7 @@ class OfficalWxchatList { Map toJson() { final Map data = new Map(); - data['type'] = this.type; + data['index'] = this.index; data['text'] = this.text; data['sub_text'] = this.subText; data['wechat_account'] = this.wechatAccount; diff --git a/lib/register.dart b/lib/register.dart index 72b61cb..581a275 100644 --- a/lib/register.dart +++ b/lib/register.dart @@ -30,6 +30,9 @@ import 'package:zhiying_base_widget/pages/team_page/team_page.dart'; import 'package:zhiying_base_widget/pages/webview/base_webview.dart'; import 'package:zhiying_base_widget/pages/wechat_teacher_page/wechat_teacher_page.dart'; import 'package:zhiying_base_widget/pages/withdraw_page/withdraw_page.dart'; +import 'package:zhiying_base_widget/widgets/custom/multi_nav/custom_quick_entry.dart'; +import 'package:zhiying_base_widget/widgets/custom/search/custom_search_widget.dart'; +import 'package:zhiying_base_widget/widgets/custom/slide_banner/custom_slide_banner_creater.dart'; import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/price/goods_details_price_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_widget.dart'; @@ -233,15 +236,14 @@ class BaseWidgetRegister { /// 可滚动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()); @@ -261,8 +263,7 @@ class BaseWidgetRegister { WidgetFactory.regist('search_index_host_keyword', DefaultWidgetCreater((model) => SearchHotTagWidget(model))); // // 历史搜索标签 - WidgetFactory.regist('search_index_history', - DefaultWidgetCreater((model) => SearchHistoryTagWidget(model))); + WidgetFactory.regist('search_index_history', DefaultWidgetCreater((model) => SearchHistoryTagWidget(model))); /// ==================== 搜索结果页面 ==================== /// // 输入框 @@ -395,5 +396,16 @@ class BaseWidgetRegister { DefaultWidgetCreater((model) => HotRankTableBar(model))); WidgetFactory.regist('hot_rank_tab_view', DefaultWidgetCreater((model) => HotRankingList(model))); + + + /// ==================== 通用模块 ==================== /// + // 搜索 + WidgetFactory.regist('search_test', DefaultWidgetCreater((model) => CustomSearchWidget(model))); + // 轮播广告位, 可滑动 + WidgetFactory.regist('carousel_test', CustomSlideBannerCreater()); + // 多眼导航,可滑动 + WidgetFactory.regist('multi_nav_test', DefaultWidgetCreater((model) => CustomQuickEntry(model))); + // 商品列表 + WidgetFactory.regist('product_test', GoodsDetailCommendCreater()); } } diff --git a/lib/widgets/custom/appbar/custom_appbar_creater.dart b/lib/widgets/custom/appbar/custom_appbar_creater.dart deleted file mode 100644 index 573d025..0000000 --- a/lib/widgets/custom/appbar/custom_appbar_creater.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:zhiying_comm/zhiying_comm.dart'; -import 'package:flutter/material.dart'; - -import 'custom_appbar_widget.dart'; - -class CustomAppBarCreater extends WidgetCreater { - @override - List createWidgets(Map model) { - return [CustomAppBarWidget(model)]; - } - - @override - bool isSliverChild() { - return true; - } -} diff --git a/lib/widgets/custom/appbar/custom_appbar_widget.dart b/lib/widgets/custom/appbar/custom_appbar_widget.dart deleted file mode 100644 index a18ed02..0000000 --- a/lib/widgets/custom/appbar/custom_appbar_widget.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:zhiying_comm/zhiying_comm.dart'; - -/// -/// 通用模块的AppBar Widget -/// -class CustomAppBarWidget extends StatelessWidget { - final Map data; - Map model; - - CustomAppBarWidget(this.data, {Key key}) : super(key: key) { - try { - var dataItem = data['data']; - if (!EmptyUtil.isEmpty(dataItem)) { - model = dataItem is Map ? dataItem : dataItem is String ? jsonDecode(dataItem) : null; - } - } catch (e, s) { - Logger.error(e, s); - } - } - - @override - Widget build(BuildContext context) { - return SliverAppBar( - leading: IconButton( - icon: Icon( - Icons.arrow_back_ios, - size: 22, - color: HexColor.fromHex( '#333333'), - ), - onPressed: () => Navigator.maybePop(context), - ), - title: Text( - '自定义页面', - style: TextStyle( - fontSize: 15, - color: HexColor.fromHex('#333333'), - fontWeight: FontWeight.bold, - ), - ), - ); - } -} diff --git a/lib/widgets/custom/multi_nav/bloc/bloc.dart b/lib/widgets/custom/multi_nav/bloc/bloc.dart new file mode 100644 index 0000000..4a4afab --- /dev/null +++ b/lib/widgets/custom/multi_nav/bloc/bloc.dart @@ -0,0 +1,4 @@ +export 'custom_quick_entry_bloc.dart'; +export 'custom_quick_entry_event.dart'; +export 'custom_quick_entry_state.dart'; +export 'custom_quick_entry_repository.dart'; \ No newline at end of file diff --git a/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_bloc.dart b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_bloc.dart new file mode 100644 index 0000000..b6abed3 --- /dev/null +++ b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_bloc.dart @@ -0,0 +1,50 @@ +import 'dart:async'; +import 'dart:math'; + +import 'package:bloc/bloc.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:zhiying_comm/util/empty_util.dart'; + +import './bloc.dart'; + +class CustomQuickEntryBloc extends Bloc { + CustomQuickEntryRepository repository; + + CustomQuickEntryBloc({@required this.repository}); + + @override + CustomQuickEntryState get initialState => InitialCustomQuickEntryState(); + + @override + Stream mapEventToState(CustomQuickEntryEvent event) async* { + /// 初始化 + if (event is CustomQuickEntryInitEvent) { + yield* _mapHomeQuickEntryInitToState(event); + } + } + + /// 初始化 + Stream _mapHomeQuickEntryInitToState(CustomQuickEntryInitEvent event) async* { + /// 获取父页面传进来的数据 + var parentData = await repository.fetchPreantData(event: event); + if (!EmptyUtil.isEmpty(parentData)) { + yield CustomQuickEntryLoadedState(model: parentData); + } else { + yield CustomQuickEntryErrorState(); + } + + // /// 获取本地缓存数据 + // var cached = await repository.fetchCachedData(event: event); + // if (!EmptyUtil.isEmpty(cached)) { + // yield CustomQuickEntryCachedState(model: cached); + // } + // + // /// 获取网络的数据 + // var result = await repository.fetchData(event: event); + // if (!EmptyUtil.isEmpty(result)) { + // yield CustomQuickEntryLoadedState(model: result); + // } else { + // yield CustomQuickEntryErrorState(); + // } + } +} diff --git a/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_event.dart b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_event.dart new file mode 100644 index 0000000..630b2c7 --- /dev/null +++ b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_event.dart @@ -0,0 +1,18 @@ +import 'package:equatable/equatable.dart'; + +abstract class CustomQuickEntryEvent extends Equatable { + const CustomQuickEntryEvent(); + + @override + List get props => []; +} + +/// 初始事件 +class CustomQuickEntryInitEvent extends CustomQuickEntryEvent { + final Map model; + + const CustomQuickEntryInitEvent({this.model}); + + @override + List get props => [this.model]; +} diff --git a/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_repository.dart b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_repository.dart new file mode 100644 index 0000000..1161070 --- /dev/null +++ b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_repository.dart @@ -0,0 +1,75 @@ +import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; +import 'package:zhiying_base_widget/widgets/custom/multi_nav/model/custom_quick_entry_model.dart'; +import 'package:zhiying_comm/util/net_util.dart'; +import 'package:zhiying_comm/util/empty_util.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +import 'custom_quick_entry_event.dart'; + +class CustomQuickEntryRepository { + /// 获取数据 + Future fetchData({@required CustomQuickEntryInitEvent event}) async { + try { + var result = await NetUtil.post('/api/v1/mod/${event.model['mod_id']}', + params: { + 'ids': [event.model['mod_id']] + }, + cache: true, + method: NetMethod.GET); + + if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { + Map data = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]; + return _getHomeQuickEntryModel(data); + } + } catch (e, s) { + Logger.error(e, s); + } + + return null; + } + + /// 获取父页面传进来的数据 + Future fetchPreantData({@required CustomQuickEntryInitEvent event}) async { + try { + String jsonStr = event.model['data']; + return CustomQuickEntryModel.fromJson(json.decode(jsonStr)); + } catch (e, s) { + Logger.error(e, s); + } + return null; + } + + /// 获取缓存数据 + Future fetchCachedData({@required CustomQuickEntryInitEvent event}) async { + try { + var result = await NetUtil.getRequestCachedData('/api/v1/mod/${event.model['mod_id']}', params: { + 'ids': [event.model['mod_id']] + }); + if (!EmptyUtil.isEmpty(result)) { + return _getHomeQuickEntryModel(result); + } + } catch (e, s) { + Logger.error(e, s); + } + return null; + } + + CustomQuickEntryModel _getHomeQuickEntryModel(var data) { + try { + if (!EmptyUtil.isEmpty(data) && !EmptyUtil.isEmpty(data['data'])) { + var jsonData = jsonDecode(data['data']); + if (!EmptyUtil.isEmpty(jsonData)) { + CustomQuickEntryModel model = CustomQuickEntryModel.fromJson(jsonData); + if (null != model) { + return model; + } + } + } + } catch (e) { + Logger.log(e); + } + return null; + } +} diff --git a/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_state.dart b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_state.dart new file mode 100644 index 0000000..ff87323 --- /dev/null +++ b/lib/widgets/custom/multi_nav/bloc/custom_quick_entry_state.dart @@ -0,0 +1,40 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:zhiying_base_widget/widgets/custom/multi_nav/model/custom_quick_entry_model.dart'; + + +abstract class CustomQuickEntryState extends Equatable { + const CustomQuickEntryState(); + + @override + List get props => []; +} + +/// 初始化状态 +class InitialCustomQuickEntryState extends CustomQuickEntryState { + @override + List get props => []; +} + +/// 加载数据完毕 +class CustomQuickEntryLoadedState extends CustomQuickEntryState { + final CustomQuickEntryModel model; + + const CustomQuickEntryLoadedState({@required this.model}); + + @override + List get props => [this.model]; +} + +/// 加载缓存数据 +class CustomQuickEntryCachedState extends CustomQuickEntryState { + final CustomQuickEntryModel model; + + const CustomQuickEntryCachedState({@required this.model}); + + @override + List get props => [this.model]; +} + +/// 加载数据出错 +class CustomQuickEntryErrorState extends CustomQuickEntryState {} diff --git a/lib/widgets/custom/multi_nav/cached_network_image_util.dart b/lib/widgets/custom/multi_nav/cached_network_image_util.dart new file mode 100644 index 0000000..240c89e --- /dev/null +++ b/lib/widgets/custom/multi_nav/cached_network_image_util.dart @@ -0,0 +1,18 @@ + +import 'package:flutter/material.dart'; + +/// +/// 图片工具类,隔离build +/// +class CachedNetworkImageUtil extends StatelessWidget { + Widget child; + CachedNetworkImageUtil({this.child}); + + @override + Widget build(BuildContext context) { + return RepaintBoundary( + child: child, + ); + } +} + diff --git a/lib/widgets/custom/multi_nav/custom_quick_entry.dart b/lib/widgets/custom/multi_nav/custom_quick_entry.dart new file mode 100644 index 0000000..94e6ec8 --- /dev/null +++ b/lib/widgets/custom/multi_nav/custom_quick_entry.dart @@ -0,0 +1,373 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_swiper/flutter_swiper.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'custom_quick_entry_sk.dart'; +import 'model/custom_quick_entry_model.dart'; +import 'bloc/bloc.dart'; + +class CustomQuickEntry extends StatelessWidget { + final Map model; + + const CustomQuickEntry(this.model); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (_) => CustomQuickEntryBloc(repository: CustomQuickEntryRepository())..add(CustomQuickEntryInitEvent(model: model)), + child: _CustomQuickEntryContainer(model), + ); + } +} + +class _CustomQuickEntryContainer extends StatefulWidget { + final Map model; + _CustomQuickEntryContainer(this.model); + @override + __CustomQuickEntryContainerState createState() => __CustomQuickEntryContainerState(); +} + +class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer> { + /// Icon点击事件 + void _itemIconClick(ListStyle model) { + print("item type = ${model.skipIdentifier}"); + // Navigator.push(context, CupertinoPageRoute(builder: (_) => CommonPage(null))); + RouterUtil.route(model, model.toJson(), context); + } + + SwiperController _controller; + + @override + void initState() { + _controller = SwiperController(); + super.initState(); + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocConsumer( + listener: (context, state) { + }, + buildWhen: (prev, current) { + return true; + }, + builder: (context, state) { + if (state is CustomQuickEntryCachedState) { + return _getMainWidget(state.model); + } + if (state is CustomQuickEntryLoadedState) { + return _getMainWidget(state.model); + } + if(state is CustomQuickEntryErrorState){ + return Container(); + } + return CustomQuickEntrySkeleton(); + }, + ); + } + + Widget _getMainWidget(CustomQuickEntryModel model) { + // 数据总数 + int totalDataSize = model?.listStyle?.length ?? 0; + + // 展示的总行数 + int totalRowSize = int.parse(model?.rowSize ?? '1'); + + // 展示的列数 + int columSize = int.parse(model?.columnSize ?? '5'); + + // 图标的高度 + double iconHeight = 40.0; + // 标题的高度 + double titleHeight = 20.0; + + // 子元素的高度 + double itemHeight = iconHeight; + + // 如果有一级标题 + if (!EmptyUtil.isEmpty(model?.isShowTitle) && model.isShowTitle == '1') { + itemHeight = iconHeight + titleHeight; + } + + //如果有二级标题 + if (!EmptyUtil.isEmpty(model?.isShowSubTitle) && model.isShowSubTitle == '1') { + itemHeight = iconHeight + titleHeight * 2; + } + + // 进度条的边距 + double barMargin = 15.0; + // 总页数 + int totalPage = totalDataSize % (totalRowSize * columSize) == 0 ? totalDataSize ~/ (totalRowSize * columSize) : (totalDataSize ~/ (totalRowSize * columSize)) + 1; + + // 总体高度 = 行数 * (子元素高度 + 边距高度) + 进度条的高度 + double totalHeight = totalRowSize * (itemHeight + barMargin) + 4; + if (!EmptyUtil.isEmpty(model?.pagination) && model.pagination != 'type_null' /*model.pagination_open == '0'*/) { + totalHeight = totalRowSize * (itemHeight + barMargin); + } + + return Container( + color: HexColor.fromHex(widget?.model['bg_color']), + child: Container( + margin: EdgeInsets.only(top: 15, bottom: totalPage > 1 ? 15 : 0), + height: totalHeight, + // 总体高度 + width: double.infinity, + color: HexColor.fromHex(widget?.model['bg_color']), + child: Swiper( + controller: _controller, + itemCount: totalPage, + loop: false, + itemBuilder: (context, index) { + return Container( + height: double.infinity, + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 12.5), + child: _getPageWidget( + iconHeight: iconHeight, + titleHeight: titleHeight, + totalDataSize: totalDataSize, + totalPage: totalPage, + currentPage: index, + totalRowSize: totalRowSize, + columSize: columSize, + model: model, + itemHeight: itemHeight, + ), + ); + }, + pagination: totalPage <= 1 ? null : _getSwiperPaginationContorl(model, totalPage), + ), + ), + ); + } + + /// 页的数据 + Widget _getPageWidget( + {double titleHeight, double iconHeight, int totalPage, int currentPage, int columSize, int totalRowSize, int totalDataSize, CustomQuickEntryModel model, double itemHeight}) { + List rowList = []; + for (int i = 0; i < totalRowSize; i++) { + rowList.add(i); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: rowList.map((currentRow) { + return Container( + padding: EdgeInsets.only(bottom: 15), + width: double.infinity, + child: _getRowWidget( + titleHeight: titleHeight, + iconHeight: iconHeight, + totalPage: totalPage, + currentPage: currentPage, + columSize: columSize, + totalRowSize: totalRowSize, + totalDataSize: totalDataSize, + model: model, + currentRow: currentRow, + itemHeight: itemHeight), + ); + }).toList(), + ); + } + + /// 行的数据 + Widget _getRowWidget( + {double titleHeight, + double iconHeight, + int totalPage, + int currentPage, + int columSize, + int totalRowSize, + int totalDataSize, + CustomQuickEntryModel model, + int currentRow, + double itemHeight}) { + List itemList = []; + for (int i = 0; i < columSize; i++) { + itemList.add(i); + } + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: itemList.map((currentIndex) { + return _getColumWidget( + titleHeight: titleHeight, + iconHeight: iconHeight, + totalPage: totalPage, + currentPage: currentPage, + totalDataSize: totalDataSize, + columSize: columSize, + totalRowSize: totalRowSize, + model: model, + currentRow: currentRow, + currentColum: currentIndex, + itemHeight: itemHeight, + ); + }).toList(), + ); + } + + /// item 的数据 + Widget _getColumWidget({ + double titleHeight, + double iconHeight, + int totalPage, + int currentPage, + int columSize, + int totalRowSize, + int totalDataSize, + CustomQuickEntryModel model, + int currentRow, + int currentColum, + double itemHeight, + }) { + // 当前index = 当前的页数+1 * 当前的行数 + 当前的列数 + // int currentIndex = (currentPage + 1) * currentRow + currentColum + currentRow*columSize; + // int currentIndex = currentPage != 0 ? currentPage * (columSize * totalRowSize) + columSize + currentRow * columSize : + // currentColum + currentRow * columSize; + + // 当前元素的下表 = 当前的列数 + 当前的行数 * 列数 + 当前的页数 * 当前的行数 + 当前的列数 + int currentIndex = currentColum + currentRow * columSize + currentPage * totalRowSize * columSize; + + // print('current Index sss = $currentIndex'); + + if (currentIndex >= totalDataSize) { + return Container( + height: itemHeight, + width: 60, + ); + } + + ListStyle item = model?.listStyle[currentIndex]; + + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _itemIconClick(item), + child: Container( + height: itemHeight, + width: 60, + // color: Colors.red, + child: Column( + children: [ + /// 图标 + MyNetWorkImage(item.img), + + /// 一级标题 + Visibility( + visible: !EmptyUtil.isEmpty(model?.isShowTitle) && model.isShowTitle == '1', + child: Padding( + padding: const EdgeInsets.only(top: 5), + child: Text( + item?.title ?? '', + style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.titleColor)), + ), + ), + ), + + /// 二级标题 + Visibility( + visible: !EmptyUtil.isEmpty(model?.isShowSubTitle) && model.isShowSubTitle == '1', + child: Padding( + padding: const EdgeInsets.only(top: 5), + child: Text( + item?.subTitle ?? '', + style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.subTitleColor)), + ), + ), + ) + ], + ), + ), + ); + } + + /// 进度条 + SwiperPagination _getSwiperPaginationContorl(CustomQuickEntryModel model, int pageCount) { + if (EmptyUtil.isEmpty(model?.pagination) || model.pagination == 'type_null' /*model.pagination_open == '0'*/) { + return null; + } + + if (model.pagination == 'type_point') { + // 点点点进度条 + return _swiperPaginationDot(model); + } else { + // 自定义进度条 + return _swiperCustomPagination(pageCount); + } + } + + // 进度条 圆形 + SwiperPagination _swiperPaginationDot(CustomQuickEntryModel model) { + return SwiperPagination( + margin: const EdgeInsets.only(), + builder: DotSwiperPaginationBuilder(color: HexColor.fromHex(model?.paginationUnselectColor), activeColor: HexColor.fromHex(model?.paginationSelectColor), size: 8, activeSize: 8)); + } + + // 自定义进度条 条形 + SwiperPlugin _swiperCustomPagination(int pageCount) { + List list = []; + for (int i = 0; i < pageCount; i++) { + list.add(i); + } + + return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) { + return Align( + alignment: Alignment(0.0, 1), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: list.map((index) { + var borderRadius; + if (index == 0) { + borderRadius = BorderRadius.only(topLeft: Radius.circular(2), bottomLeft: Radius.circular(2)); + } + if (index == list.length - 1) { + borderRadius = BorderRadius.only(topRight: Radius.circular(2), bottomRight: Radius.circular(2)); + } + + if (index == config.activeIndex) { + borderRadius = BorderRadius.all(Radius.circular(2)); + } + + return Container( + height: 4, + width: 25, + decoration: BoxDecoration(borderRadius: borderRadius, color: index == config.activeIndex ? HexColor.fromHex('#FF4242') : HexColor.fromHex('#FFFFFF')), + ); + }).toList(), + ), + ); + }); + } +} + +/// +/// 图片build 优化 +/// +class MyNetWorkImage extends StatelessWidget { + final String imgUrl; + final double width; + + const MyNetWorkImage(this.imgUrl, {this.width = 40}); + + @override + Widget build(BuildContext context) { + return RepaintBoundary( + child: CachedNetworkImage( + width: width, + imageUrl: imgUrl, + ), + ); + } +} diff --git a/lib/widgets/custom/multi_nav/custom_quick_entry_creater.dart b/lib/widgets/custom/multi_nav/custom_quick_entry_creater.dart new file mode 100644 index 0000000..acd5741 --- /dev/null +++ b/lib/widgets/custom/multi_nav/custom_quick_entry_creater.dart @@ -0,0 +1,20 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +import 'custom_quick_entry.dart'; +import 'custom_quick_entry_sk.dart'; + +/// +/// 快速入口 +/// +class CustomQuickEntryCreater extends WidgetCreater { + @override + List createSkeleton(Map model) { + return [CustomQuickEntrySkeleton()]; + } + + @override + List createWidgets(Map model) { + return [CustomQuickEntry(model)]; + } +} diff --git a/lib/widgets/custom/multi_nav/custom_quick_entry_sk.dart b/lib/widgets/custom/multi_nav/custom_quick_entry_sk.dart new file mode 100644 index 0000000..595119e --- /dev/null +++ b/lib/widgets/custom/multi_nav/custom_quick_entry_sk.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:shimmer/shimmer.dart'; + +class CustomQuickEntrySkeleton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + height: 153, + child: GridView.builder( + physics: NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5), + itemBuilder: (context, index) { + return CustomQuickEntrySkeletonItem( + index: index, + ); + }, + itemCount: 10, + ), + ); + } +} + +class CustomQuickEntrySkeletonItem extends StatelessWidget { + final int index; + + const CustomQuickEntrySkeletonItem({this.index}); + + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.center, + child: Shimmer.fromColors( + baseColor: Colors.grey[300], + highlightColor: Colors.grey[100], + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // 图片 + Container( + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)), + height: 40, + width: 40, + ), + SizedBox(height: 5), + +// Container(height: 10.h, width: 40.w, color: Colors.white,), + ], + ), + )); + } +} diff --git a/lib/widgets/custom/multi_nav/model/custom_quick_entry_model.dart b/lib/widgets/custom/multi_nav/model/custom_quick_entry_model.dart new file mode 100644 index 0000000..6d117bb --- /dev/null +++ b/lib/widgets/custom/multi_nav/model/custom_quick_entry_model.dart @@ -0,0 +1,187 @@ +import 'package:zhiying_comm/zhiying_comm.dart'; + +class CustomQuickEntryModel { + String name; + String desc; + String pagination; + String moduleType; + String moduleKey; + String isTopMargin; + String isLeftRightMargin; + String isShow; + String topMargin; + String leftRightMargin; + String rowSize; + String columnSize; + String isShowSubTitle; + String isShowTitle; + String isShowCornerIcon; + String isShowCategory; + String paginationSelectColor; + String paginationUnselectColor; + List listStyle; + List typeList; + int moduleKeyId; + String titleColor; + String subTitleColor; + + CustomQuickEntryModel({ + this.name, + this.desc, + this.pagination, + this.moduleType, + this.moduleKey, + this.isTopMargin, + this.isLeftRightMargin, + this.isShow, + this.topMargin, + this.leftRightMargin, + this.rowSize, + this.isShowSubTitle, + this.isShowCornerIcon, + this.isShowCategory, + this.paginationSelectColor, + this.paginationUnselectColor, + this.listStyle, + this.typeList, + this.moduleKeyId, + this.titleColor, + this.subTitleColor, + this.columnSize, + this.isShowTitle, + }); + + CustomQuickEntryModel.fromJson(Map json) { + name = json['name']?.toString(); + desc = json['desc']?.toString(); + pagination = json['pagination']?.toString(); + moduleType = json['module_type']?.toString(); + moduleKey = json['module_key']?.toString(); + isTopMargin = json['is_top_margin']?.toString(); + isLeftRightMargin = json['is_left_right_margin']?.toString(); + isShow = json['is_show']?.toString(); + topMargin = json['top_margin']?.toString(); + leftRightMargin = json['left_right_margin']?.toString(); + rowSize = json['row_size']?.toString(); + columnSize = json['column_size']?.toString() ?? '5'; + isShowSubTitle = json['is_show_sub_title']?.toString(); + isShowCornerIcon = json['is_show_corner_icon']?.toString(); + isShowCategory = json['is_show_category']?.toString(); + paginationSelectColor = json['pagination_select_color']?.toString(); + paginationUnselectColor = json['pagination_unselect_color']?.toString(); + if (json['list_style'] != null) { + listStyle = new List(); + json['list_style'].forEach((v) { + listStyle.add(new ListStyle.fromJson(v)); + }); + } + if (json['type_list'] != null) { + typeList = new List(); + json['type_list'].forEach((v) { + typeList.add(new TypeList.fromJson(v)); + }); + } + moduleKeyId = json['module_key_id']; + titleColor = json['title_color']; + subTitleColor = json['sub_title_color']; + isShowTitle = '1'; + } + + Map toJson() { + final Map data = new Map(); + data['name'] = this.name; + data['desc'] = this.desc; + data['pagination'] = this.pagination; + data['module_type'] = this.moduleType; + data['module_key'] = this.moduleKey; + data['is_top_margin'] = this.isTopMargin; + data['is_left_right_margin'] = this.isLeftRightMargin; + data['is_show'] = this.isShow; + data['top_margin'] = this.topMargin; + data['left_right_margin'] = this.leftRightMargin; + data['row_size'] = this.rowSize; + data['column_size'] = this.columnSize; + data['is_show_sub_title'] = this.isShowSubTitle; + data['is_show_corner_icon'] = this.isShowCornerIcon; + data['is_show_category'] = this.isShowCategory; + data['pagination_select_color'] = this.paginationSelectColor; + data['pagination_unselect_color'] = this.paginationUnselectColor; + if (this.listStyle != null) { + data['list_style'] = this.listStyle.map((v) => v.toJson()).toList(); + } + if (this.typeList != null) { + data['type_list'] = this.typeList.map((v) => v.toJson()).toList(); + } + data['module_key_id'] = this.moduleKeyId; + data['title_color'] = this.titleColor; + data['sub_title_color'] = this.subTitleColor; + data['is_show_title'] = this.isShowTitle; + return data; + } +} + +class ListStyle extends SkipModel { + String title; + String img; + String subTitle; + String typeListKey; + String rightIcon; + String requiredLogin; + String requiredTaobaoAuth; + String skipIdentifier; + + ListStyle({ + this.title, + this.img, + this.subTitle, + this.typeListKey, + this.rightIcon, + this.requiredLogin, + this.requiredTaobaoAuth, + this.skipIdentifier, + }); + + ListStyle.fromJson(Map json) { + super.fromJson(json); + title = json['title']; + img = json['img']; + subTitle = json['sub_title']; + typeListKey = json['type_list_key']; + rightIcon = json['right_icon']; + requiredLogin = json['required_login']; + requiredTaobaoAuth = json['required_taobao_auth']; + skipIdentifier = json['skip_identifier']; + } + + Map toJson() { + final Map data = super.toJson(); + data['title'] = this.title; + data['img'] = this.img; + data['sub_title'] = this.subTitle; + data['type_list_key'] = this.typeListKey; + data['right_icon'] = this.rightIcon; + data['required_login'] = this.requiredLogin; + data['required_taobao_auth'] = this.requiredTaobaoAuth; + data['skip_identifier'] = this.skipIdentifier; + return data; + } +} + +class TypeList { + String name; + String key; + + TypeList({this.name, this.key}); + + TypeList.fromJson(Map json) { + name = json['name']; + key = json['key']; + } + + Map toJson() { + final Map data = new Map(); + data['name'] = this.name; + data['key'] = this.key; + return data; + } +} diff --git a/lib/widgets/custom/search/custom_search_widget.dart b/lib/widgets/custom/search/custom_search_widget.dart index f39dc3d..3dfcd90 100644 --- a/lib/widgets/custom/search/custom_search_widget.dart +++ b/lib/widgets/custom/search/custom_search_widget.dart @@ -1,13 +1,70 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:zhiying_base_widget/widgets/custom/search/model/custom_search_model.dart'; import 'package:zhiying_comm/zhiying_comm.dart'; /// /// 通用模块的搜索栏 /// class CustomSearchWidget extends StatelessWidget { + final Map data; + CustomSearchModel model; + + CustomSearchWidget(this.data, {Key key}) : super(key: key) { + try { + model = CustomSearchModel.fromJson(jsonDecode(data['data'])); + } catch (e, s) { + Logger.warn(e, s); + } + } + + // 点击事件 + void _onClickListener(BuildContext context, SkipModel skipModel) { + RouterUtil.route(skipModel, skipModel.toJson(), context); + } + @override Widget build(BuildContext context) { - return Container(); + return _buildStyle1Widget(context); + } + + /// 样式1 + Widget _buildStyle1Widget(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _onClickListener(context, model?.listStyle?.searchCss), + child: Container( + width: double.infinity, + decoration: BoxDecoration(color: HexColor.fromHex(model?.bgColor ?? '#FFFFFF')), + padding: const EdgeInsets.symmetric(horizontal: 12.5, vertical: 4), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(40), + color: HexColor.fromHex(model?.listStyle?.searchCss?.bgColor ?? '#F9F9F9'), + ), + padding: const EdgeInsets.symmetric(vertical: 6), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + /// 搜索按钮 + CachedNetworkImage( + imageUrl: model?.listStyle?.searchCss?.image ?? '', + height: 20, + width: 20, + ), + const SizedBox(width: 7.5), + + /// 提示文字 + Text( + model?.listStyle?.searchCss?.text ?? '搜索更多优惠商品', + style: TextStyle(fontSize: 14, color: HexColor.fromHex(model?.listStyle?.searchCss?.textColor ?? '#999999')), + ) + ], + ), + ), + ), + ); } } diff --git a/lib/widgets/custom/search/model/custom_search_model.dart b/lib/widgets/custom/search/model/custom_search_model.dart new file mode 100644 index 0000000..a9eb562 --- /dev/null +++ b/lib/widgets/custom/search/model/custom_search_model.dart @@ -0,0 +1,157 @@ +import 'package:zhiying_comm/zhiying_comm.dart'; + +class CustomSearchModel { + String name; + String desc; + String moduleType; + String moduleKey; + String isTopMargin; + String isLeftRightMargin; + String isShow; + String topMargin; + String leftRightMargin; + String bgColor; + ListStyle listStyle; + + CustomSearchModel({ + this.name, + this.desc, + this.moduleType, + this.moduleKey, + this.isTopMargin, + this.isLeftRightMargin, + this.isShow, + this.topMargin, + this.leftRightMargin, + this.bgColor, + this.listStyle, + }); + + CustomSearchModel.fromJson(Map json) { + name = json['name']; + desc = json['desc']; + moduleType = json['module_type']; + moduleKey = json['module_key']; + isTopMargin = json['is_top_margin']; + isLeftRightMargin = json['is_left_right_margin']; + isShow = json['is_show']; + topMargin = json['top_margin']; + leftRightMargin = json['left_right_margin']; + bgColor = json['bg_color']; + listStyle = json['list_style'] != null ? new ListStyle.fromJson(json['list_style']) : null; + } + + Map toJson() { + final Map data = new Map(); + data['name'] = this.name; + data['desc'] = this.desc; + data['module_type'] = this.moduleType; + data['module_key'] = this.moduleKey; + data['is_top_margin'] = this.isTopMargin; + data['is_left_right_margin'] = this.isLeftRightMargin; + data['is_show'] = this.isShow; + data['top_margin'] = this.topMargin; + data['left_right_margin'] = this.leftRightMargin; + data['bg_color'] = this.bgColor; + if (this.listStyle != null) { + data['list_style'] = this.listStyle.toJson(); + } + return data; + } +} + +class ListStyle { + SearchCss searchCss; + RightCss rightCss; + + ListStyle({this.searchCss, this.rightCss}); + + ListStyle.fromJson(Map json) { + searchCss = json['search_css'] != null ? new SearchCss.fromJson(json['search_css']) : null; + rightCss = json['right_css'] != null ? new RightCss.fromJson(json['right_css']) : null; + } + + Map toJson() { + final Map data = new Map(); + if (this.searchCss != null) { + data['search_css'] = this.searchCss.toJson(); + } + if (this.rightCss != null) { + data['right_css'] = this.rightCss.toJson(); + } + return data; + } +} + +class SearchCss extends SkipModel { + String name; + String text; + String image; + String bgColor; + String textColor; + String requiredLogin; + String requiredTaobaoAuth; + String skipIdentifier; + + SearchCss({this.name, this.text, this.image, this.bgColor, this.textColor, this.requiredLogin, this.requiredTaobaoAuth, this.skipIdentifier}); + + SearchCss.fromJson(Map json) { + super.fromJson(json); + name = json['name']; + text = json['text']; + image = json['image']; + bgColor = json['bg_color']; + textColor = json['text_color']; + requiredLogin = json['required_login']; + requiredTaobaoAuth = json['required_taobao_auth']; + skipIdentifier = json['skip_identifier']; + } + + Map toJson() { + final Map data = super.toJson(); + data['name'] = this.name; + data['text'] = this.text; + data['image'] = this.image; + data['bg_color'] = this.bgColor; + data['text_color'] = this.textColor; + data['required_login'] = this.requiredLogin; + data['required_taobao_auth'] = this.requiredTaobaoAuth; + data['skip_identifier'] = this.skipIdentifier; + return data; + } +} + +class RightCss extends SkipModel { + String name; + String text; + String type; + String image; + String requiredLogin; + String requiredTaobaoAuth; + String skipIdentifier; + + RightCss({this.name, this.text, this.type, this.image, this.requiredLogin, this.requiredTaobaoAuth, this.skipIdentifier}); + + RightCss.fromJson(Map json) { + super.fromJson(json); + name = json['name']; + text = json['text']; + type = json['type']; + image = json['image']; + requiredLogin = json['required_login']; + requiredTaobaoAuth = json['required_taobao_auth']; + skipIdentifier = json['skip_identifier']; + } + + Map toJson() { + final Map data = super.toJson(); + data['name'] = this.name; + data['text'] = this.text; + data['type'] = this.type; + data['image'] = this.image; + data['required_login'] = this.requiredLogin; + data['required_taobao_auth'] = this.requiredTaobaoAuth; + data['skip_identifier'] = this.skipIdentifier; + return data; + } +} diff --git a/lib/widgets/custom/slide_banner/bloc/bloc.dart b/lib/widgets/custom/slide_banner/bloc/bloc.dart new file mode 100644 index 0000000..ef7ca2a --- /dev/null +++ b/lib/widgets/custom/slide_banner/bloc/bloc.dart @@ -0,0 +1,5 @@ +export 'custom_slide_banner_bloc.dart'; +export 'custom_slide_banner_event.dart'; +export 'custom_slide_banner_state.dart'; +export 'custom_slide_banner_repository.dart'; +export '../model/custom_slide_banner_model.dart'; \ No newline at end of file diff --git a/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_bloc.dart b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_bloc.dart new file mode 100644 index 0000000..c6593bb --- /dev/null +++ b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_bloc.dart @@ -0,0 +1,43 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:flutter/cupertino.dart'; + +import 'package:zhiying_comm/util/empty_util.dart'; +import './bloc.dart'; + +class CustomSlideBannerBloc extends Bloc { + CustomSlideBannerRepository repository; + + CustomSlideBannerBloc({@required this.repository}); + + @override + CustomSlideBannerState get initialState => InitialCustomSlideBannerState(); + + @override + Stream mapEventToState(CustomSlideBannerEvent event) async* { + final currentState = state; + + /// 初始化 + if (event is CustomBannerInitEvent) { + print('---------HomeBannerInitEvent---------'); + yield* _mapInitEventToState(event); + } + } + + /// 初始化 + Stream _mapInitEventToState(CustomBannerInitEvent event) async* { + var parent = await repository.fetchPreantData(event.model); + if (!EmptyUtil.isEmpty(parent)) { + yield HomeSlideBannerLoadedState(datas: parent); + return; + } + var cached = await repository.fetchCachedDate(id: event.model['mod_id']); + if (!EmptyUtil.isEmpty(cached)) yield CustomSlideBannerCachedState(datas: cached); + var param = await repository.fetchData(id: event.model['mod_id']); + if (!EmptyUtil.isEmpty(param)) + yield HomeSlideBannerLoadedState(datas: param); + else + yield HomeSlideBannerLoadError(); + } +} diff --git a/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_event.dart b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_event.dart new file mode 100644 index 0000000..c4214d2 --- /dev/null +++ b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_event.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + + +abstract class CustomSlideBannerEvent extends Equatable { + const CustomSlideBannerEvent(); + @override + List get props => []; +} + +/// 初始事件 +class CustomBannerInitEvent extends CustomSlideBannerEvent{ + final Map model; + const CustomBannerInitEvent({this.model}); +} diff --git a/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_repository.dart b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_repository.dart new file mode 100644 index 0000000..07d57bb --- /dev/null +++ b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_repository.dart @@ -0,0 +1,45 @@ +import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; +import 'package:zhiying_base_widget/widgets/custom/slide_banner/bloc/bloc.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +class CustomSlideBannerRepository { + /// 获取缓存数据 + Future fetchCachedDate({@required int id}) async { + var cached = await NetUtil.getRequestCachedData('/api/v1/mod', params: { + 'ids': [id] + }); + if (!EmptyUtil.isEmpty(cached)) { + try { + return CustomSlideBannerModel.fromJson(cached); + } catch (e) {} + } + return null; + } + + /// 获取父页面传进来的数据 + Future fetchPreantData(@required Map model) async { + try { + if (!EmptyUtil.isEmpty(model)) { + return CustomSlideBannerModel.fromJson(jsonDecode(model['data'])); + } + } catch (e) {} + return null; + } + + /// 获取数据 + Future fetchData({@required int id}) async { + var params = await NetUtil.post('/api/v1/mod', + params: { + 'ids': [id] + }, + cache: true); + if (NetUtil.isSuccess(params) && !EmptyUtil.isEmpty(params[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { + try { + return CustomSlideBannerModel.fromJson(params[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); + } catch (e) {} + } + return null; + } +} diff --git a/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_state.dart b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_state.dart new file mode 100644 index 0000000..57fe581 --- /dev/null +++ b/lib/widgets/custom/slide_banner/bloc/custom_slide_banner_state.dart @@ -0,0 +1,44 @@ +import 'package:equatable/equatable.dart'; +import 'package:zhiying_base_widget/widgets/custom/slide_banner/model/custom_slide_banner_model.dart'; + +abstract class CustomSlideBannerState extends Equatable { + const CustomSlideBannerState(); + + @override + List get props => []; +} + +/// 初始化状态 +class InitialCustomSlideBannerState extends CustomSlideBannerState { + @override + List get props => []; +} + +/// 缓存数据 +class CustomSlideBannerCachedState extends CustomSlideBannerState { + CustomSlideBannerModel datas; + + CustomSlideBannerCachedState({this.datas}); + + @override + List get props => [this.datas]; +} + +/// 数据加载完毕状态 +class HomeSlideBannerLoadedState extends CustomSlideBannerState { + CustomSlideBannerModel datas; + + HomeSlideBannerLoadedState({this.datas}); + + HomeSlideBannerLoadedState copyWith({CustomSlideBannerModel newData}) { + return HomeSlideBannerLoadedState( + datas: newData ?? datas, + ); + } + + @override + List get props => [datas]; +} + +/// 数据加载失败 +class HomeSlideBannerLoadError extends CustomSlideBannerState {} diff --git a/lib/widgets/custom/slide_banner/custom_slide_banner.dart b/lib/widgets/custom/slide_banner/custom_slide_banner.dart new file mode 100644 index 0000000..60d2488 --- /dev/null +++ b/lib/widgets/custom/slide_banner/custom_slide_banner.dart @@ -0,0 +1,224 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_swiper/flutter_swiper.dart'; +import 'package:provider/provider.dart'; +import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; +import 'bloc/bloc.dart'; +import 'bloc/custom_slide_banner_repository.dart'; +import 'custom_slide_banner_sk.dart'; +import 'model/custom_slide_banner_model.dart'; + +/// +/// 可滑动 banner 轮播图 +/// +class CustomSlideBanner extends StatefulWidget { + final Map model; + + const CustomSlideBanner(this.model, {Key key}) : super(key: key); + + @override + _CustomSlideBannerState createState() => _CustomSlideBannerState(); +} + +class _CustomSlideBannerState extends State { + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (_) => CustomSlideBannerBloc(repository: CustomSlideBannerRepository())..add(CustomBannerInitEvent(model: widget?.model)), + child: CustomSlideBannerContainer(), + ); + } +} + +class CustomSlideBannerContainer extends StatefulWidget { + @override + _CustomSlideBannerContainerState createState() => _CustomSlideBannerContainerState(); +} + +class _CustomSlideBannerContainerState extends State { + /// 子元素点击事件 + void _itemOnClick(IndexCarouselList model) { + print('点击了 $model'); + RouterUtil.route(model, model.toJson(), context); + // Navigator.push(context, CupertinoPageRoute(builder: (_) => VipCenterPage(null))); + } + + SwiperController _swiperController; + + @override + void initState() { + _swiperController = SwiperController(); + super.initState(); + } + + @override + void dispose() { + _swiperController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocConsumer( + listener: (BuildContext context, CustomSlideBannerState state) { + if (state is HomeSlideBannerLoadError) { + print('数据加载出错'); + } + }, + buildWhen: (previous, current) { + /// 数据加载出错不进行build + if (current is HomeSlideBannerLoadError) { + return false; + } + return true; + }, + builder: (context, state) { + print('currente state = $state'); + if (state is HomeSlideBannerLoadedState) { + return _getMainWidget(state.datas); + } + if (state is CustomSlideBannerCachedState) { + return _getMainWidget(state.datas); + } + // 骨架屏 + return CustomSlideBannerSkeleton(); + }, + ); + } + + Widget _getMainWidget(CustomSlideBannerModel datas) { + Future.delayed(Duration.zero, () { + Provider.of(context, listen: false).switchBg(Container( + width: double.infinity, + height: 200, + color: Colors.redAccent, + )); + }); + + int size = datas?.indexCarouselList?.length ?? 0; + + return Container( + margin: EdgeInsets.all(10), + width: double.infinity, + height: 140, + child: Swiper( + controller: _swiperController, + itemBuilder: (BuildContext context, int index) { + IndexCarouselList items = datas.indexCarouselList[index]; + return Container( + width: double.infinity, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(7.5)), + child: ClipRRect( + borderRadius: BorderRadius.circular(7.5), + child: CachedNetworkImage( + imageUrl: items?.img ?? '', + fit: BoxFit.cover, + ), + ), + ); + }, + itemCount: size, + loop: size > 1 , + autoplay: true, + onTap: (index) => _itemOnClick(datas.indexCarouselList[index]), + pagination: _getSwiperStyleByType(datas, size), + onIndexChanged: (index) { + // print('color = ${datas?.indexCarouselList[index]?.bgColor}'); + Provider.of(context, listen: false).switchBg(Container( + width: double.infinity, + height: 200, + color: HexColor.fromHex(datas?.indexCarouselList[index]?.bgColor), + )); + }, + ), + ); + } + + /// 获取进度样式 + SwiperPlugin _getSwiperStyleByType(CustomSlideBannerModel model, int pageCount) { + + // 一张图片就不滑动 + if(pageCount <= 1){ + return null; + } + + if ('type_null' == model.pagination) { + return null; + } + + if ('type_number' == model.pagination) { + return _getNumswiperPlugin(pageCount, model.paginationSelectColor, model.paginationUnselectColor); + } + if ('type_point' == model.pagination) { + return _swiperCustomPaginationDito(pageCount, model.paginationSelectColor, model.paginationUnselectColor); + } + if ('type_bar' == model.pagination) { + return _swiperCustomPagination(pageCount, model.paginationSelectColor, model.paginationUnselectColor); + } + return null; + } + + /// 数字样式 + SwiperPlugin _getNumswiperPlugin(int pageCount, String selectColor, String unselectColor) { + return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) { + return Align( + alignment: Alignment(0.9, 0.9), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 18), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(3), color: HexColor.fromHex('#80333333')), + child: RichText( + text: TextSpan(text: '${config.activeIndex + 1}', style: TextStyle(fontSize: 12, color: HexColor.fromHex(selectColor)), children: [ + TextSpan(text: '/', style: TextStyle(fontSize: 12, color: HexColor.fromHex(unselectColor))), + TextSpan(text: '$pageCount', style: TextStyle(fontSize: 12, color: HexColor.fromHex(unselectColor))), + ]), + )), + ); + }); + } + + /// 自定义进度条 + SwiperPlugin _swiperCustomPagination(int pageCount, String selectColor, String unselectColor) { + List list = []; + for (int i = 0; i < pageCount; i++) { + list.add(i); + } + + return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) { + return Align( + alignment: Alignment(0.0, 0.9), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: list.map((index) { + var borderRadius; + if (index == 0) { + borderRadius = BorderRadius.only(topLeft: Radius.circular(2), bottomLeft: Radius.circular(2)); + } + if (index == list.length - 1) { + borderRadius = BorderRadius.only(topRight: Radius.circular(2), bottomRight: Radius.circular(2)); + } + + if (index == config.activeIndex) { + borderRadius = BorderRadius.all(Radius.circular(2)); + } + + return Container( + height: 4, + width: 25, + decoration: BoxDecoration(borderRadius: borderRadius, color: index == config.activeIndex ? HexColor.fromHex(selectColor) : HexColor.fromHex(unselectColor)), + ); + }).toList(), + ), + ); + }); + } + + /// 圆形进度条 + SwiperPlugin _swiperCustomPaginationDito(int pageCount, String selectColor, String unselectColor) { + return SwiperPagination( + margin: const EdgeInsets.only(), builder: DotSwiperPaginationBuilder(color: HexColor.fromHex(unselectColor), activeColor: HexColor.fromHex(selectColor), size: 8, activeSize: 8)); + } +} diff --git a/lib/widgets/custom/slide_banner/custom_slide_banner_creater.dart b/lib/widgets/custom/slide_banner/custom_slide_banner_creater.dart new file mode 100644 index 0000000..d1d2702 --- /dev/null +++ b/lib/widgets/custom/slide_banner/custom_slide_banner_creater.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +import 'custom_slide_banner.dart'; +import 'custom_slide_banner_sk.dart'; + +/// +/// 可以滚动Banner +/// +class CustomSlideBannerCreater extends WidgetCreater { + @override + List createSkeleton(Map model) { + return [CustomSlideBannerSkeleton()]; + } + + @override + List createWidgets(Map model) { + return [ + CustomSlideBanner(model), + ]; + } +} diff --git a/lib/widgets/custom/slide_banner/custom_slide_banner_sk.dart b/lib/widgets/custom/slide_banner/custom_slide_banner_sk.dart new file mode 100644 index 0000000..e99b8f6 --- /dev/null +++ b/lib/widgets/custom/slide_banner/custom_slide_banner_sk.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:shimmer/shimmer.dart'; + +class CustomSlideBannerSkeleton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + height: 200, + color: Colors.white, + child: Shimmer.fromColors( + baseColor: Colors.grey[300], + highlightColor: Colors.grey[100], + child: Container( + margin: EdgeInsets.all(10), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(10))), + ), + ), + ); + } +} diff --git a/lib/widgets/custom/slide_banner/model/custom_slide_banner_model.dart b/lib/widgets/custom/slide_banner/model/custom_slide_banner_model.dart new file mode 100644 index 0000000..c45b192 --- /dev/null +++ b/lib/widgets/custom/slide_banner/model/custom_slide_banner_model.dart @@ -0,0 +1,126 @@ +import 'package:zhiying_comm/zhiying_comm.dart'; + +class CustomSlideBannerModel { + String name; + String desc; + String pagination; + String moduleType; + String moduleKey; + String isTopMargin; + String isLeftRightMargin; + String isShow; + String carouselType; + String paginationSelectColor; + String paginationUnselectColor; + String barWidthHeightRatio; + String bgWidthHeightRatio; + String carouselTime; + String topMargin; + String leftRightMargin; + List indexCarouselList; + int moduleKeyId; + + CustomSlideBannerModel({ + this.name, + this.desc, + this.pagination, + this.moduleType, + this.moduleKey, + this.isTopMargin, + this.isLeftRightMargin, + this.isShow, + this.carouselType, + this.paginationSelectColor, + this.paginationUnselectColor, + this.barWidthHeightRatio, + this.bgWidthHeightRatio, + this.carouselTime, + this.topMargin, + this.leftRightMargin, + this.indexCarouselList, + this.moduleKeyId, + }); + + CustomSlideBannerModel.fromJson(Map json) { + name = json['name']; + desc = json['desc']; + pagination = json['pagination']; + moduleType = json['module_type']; + moduleKey = json['module_key']; + isTopMargin = json['is_top_margin']; + isLeftRightMargin = json['is_left_right_margin']; + isShow = json['is_show']; + carouselType = json['carousel_type']; + paginationSelectColor = json['pagination_select_color']; + paginationUnselectColor = json['pagination_unselect_color']; + barWidthHeightRatio = json['bar_width_height_ratio']; + bgWidthHeightRatio = json['bg_width_height_ratio']; + carouselTime = json['carousel_time']; + topMargin = json['top_margin']; + leftRightMargin = json['left_right_margin']; + if (json['index_carousel_list'] != null) { + indexCarouselList = new List(); + json['index_carousel_list'].forEach((v) { + indexCarouselList.add(new IndexCarouselList.fromJson(v)); + }); + } + moduleKeyId = json['module_key_id']; + } + + Map toJson() { + final Map data = new Map(); + data['name'] = this.name; + data['desc'] = this.desc; + data['pagination'] = this.pagination; + data['module_type'] = this.moduleType; + data['module_key'] = this.moduleKey; + data['is_top_margin'] = this.isTopMargin; + data['is_left_right_margin'] = this.isLeftRightMargin; + data['is_show'] = this.isShow; + data['carousel_type'] = this.carouselType; + data['pagination_select_color'] = this.paginationSelectColor; + data['pagination_unselect_color'] = this.paginationUnselectColor; + data['bar_width_height_ratio'] = this.barWidthHeightRatio; + data['bg_width_height_ratio'] = this.bgWidthHeightRatio; + data['carousel_time'] = this.carouselTime; + data['top_margin'] = this.topMargin; + data['left_right_margin'] = this.leftRightMargin; + if (this.indexCarouselList != null) { + data['index_carousel_list'] = this.indexCarouselList.map((v) => v.toJson()).toList(); + } + data['module_key_id'] = this.moduleKeyId; + return data; + } +} + +class IndexCarouselList extends SkipModel { + String name; + String img; + String bgColor; + String requiredLogin; + String requiredTaobaoAuth; + String skipIdentifier; + + IndexCarouselList({this.name, this.img, this.bgColor, this.requiredLogin, this.requiredTaobaoAuth, this.skipIdentifier}); + + IndexCarouselList.fromJson(Map json) { + super.fromJson(json); + name = json['name']; + img = json['img']; + bgColor = json['bg_color']; + requiredLogin = json['required_login']; + requiredTaobaoAuth = json['required_taobao_auth']; + skipIdentifier = json['skip_identifier']; + } + + Map toJson() { + final Map data = super.toJson(); + data['name'] = this.name; + data['img'] = this.img; + data['bg_color'] = this.bgColor; + data['required_login'] = this.requiredLogin; + data['required_taobao_auth'] = this.requiredTaobaoAuth; + data['skip_identifier'] = this.skipIdentifier; + return data; + } +} diff --git a/lib/widgets/goods_details/recommend/goods_detail_commend_list.dart b/lib/widgets/goods_details/recommend/goods_detail_commend_list.dart index e2d57fe..904c8d0 100644 --- a/lib/widgets/goods_details/recommend/goods_detail_commend_list.dart +++ b/lib/widgets/goods_details/recommend/goods_detail_commend_list.dart @@ -4,11 +4,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart'; +import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; import 'package:zhiying_base_widget/widgets/home/home_goods/bloc/home_goods_bloc.dart'; import 'package:zhiying_base_widget/widgets/home/home_goods/home_goods_item.dart'; import 'package:zhiying_base_widget/widgets/home/home_goods/home_goods_item_single.dart'; import 'package:zhiying_base_widget/widgets/home/home_goods/models/home_goods_model.dart'; import 'package:zhiying_base_widget/widgets/home/home_goods/models/home_goods_style_model.dart'; +import 'package:zhiying_base_widget/widgets/home/home_goods/skeleton/home_goods_sk.dart'; import 'package:zhiying_comm/util/base_bloc.dart'; class GoodsDetailCommendList extends StatefulWidget { @@ -40,16 +42,13 @@ class _GoodsDetailCommendListContainer extends StatefulWidget { final Map data; final String provider; - _GoodsDetailCommendListContainer(this.data, this.provider, {Key key}) - : super(key: key); + _GoodsDetailCommendListContainer(this.data, this.provider, {Key key}) : super(key: key); @override - _GoodsDetailCommendListContainerState createState() => - _GoodsDetailCommendListContainerState(); + _GoodsDetailCommendListContainerState createState() => _GoodsDetailCommendListContainerState(); } -class _GoodsDetailCommendListContainerState - extends State<_GoodsDetailCommendListContainer> { +class _GoodsDetailCommendListContainerState extends State<_GoodsDetailCommendListContainer> { HomeGoodsBloc _bloc; HomeGoodsStyleModel _style; @@ -70,8 +69,7 @@ class _GoodsDetailCommendListContainerState void didChangeDependencies() { super.didChangeDependencies(); print('didChangeDependencies'); - bool isNeedLoadMore = - Provider.of(context).scrollEnd; + bool isNeedLoadMore = Provider.of(context).scrollEnd; if (isNeedLoadMore && widget.provider != '') { print('HomeGoods loadmore...'); _bloc.loadMore(widget.provider); @@ -83,6 +81,10 @@ class _GoodsDetailCommendListContainerState return StreamBuilder>( stream: _bloc.outData, builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.data == null) { + return SliverToBoxAdapter(child: HomeGoodsSkeleton()); + } + List goods = snapshot.data; int column = 2; int count = ((goods?.length ?? 0) / column).ceil(); diff --git a/lib/widgets/goods_details/recommend/goods_detail_commend_widget.dart b/lib/widgets/goods_details/recommend/goods_detail_commend_widget.dart index a1b5135..304a929 100644 --- a/lib/widgets/goods_details/recommend/goods_detail_commend_widget.dart +++ b/lib/widgets/goods_details/recommend/goods_detail_commend_widget.dart @@ -8,9 +8,10 @@ import 'package:zhiying_comm/zhiying_comm.dart'; class GoodsDetailsRecommendWidget extends StatefulWidget { final Map data; + // Map style = {}; HomeGoodsStyleModel styleModel; - + GoodsDetailsRecommendWidget(this.data, {Key key}) : super(key: key) { try { styleModel = HomeGoodsStyleModel.fromJson(convert.jsonDecode(data['data'])); @@ -47,36 +48,39 @@ class _GoodsDetailsRecommendWidgetState extends State[ - CachedNetworkImage( - // imageUrl: _style.recListIcon ?? '', - // imageUrl: widget?.style['rec_icon'] ?? '', - imageUrl: widget?.styleModel?.recIcon ?? '', - width: 15, - height: 15, - ), - Padding( - padding: const EdgeInsets.only(left: 2.5), - child: Text( - // _style?.recListText ?? '', - // widget?.style['title'] ?? '', - widget?.styleModel?.title ?? '', - style: TextStyle( - // color: HexColor.fromHex(_style?.recListTextColor ?? 'FF4242'), - // color: HexColor.fromHex(widget?.style['title_color'] ?? ''), - color: HexColor.fromHex(widget?.styleModel?.titleColor ?? ''), - fontSize: 14, - ), + if (EmptyUtil.isEmpty(widget?.styleModel?.title)) + return Container(); + else + return Container( + width: double.infinity, + height: 50, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CachedNetworkImage( + // imageUrl: _style.recListIcon ?? '', + // imageUrl: widget?.style['rec_icon'] ?? '', + imageUrl: widget?.styleModel?.recIcon ?? '', + width: 15, + height: 15, ), - ) - ], - ), - ); + Padding( + padding: const EdgeInsets.only(left: 2.5), + child: Text( + // _style?.recListText ?? '', + // widget?.style['title'] ?? '', + widget?.styleModel?.title ?? '', + style: TextStyle( + // color: HexColor.fromHex(_style?.recListTextColor ?? 'FF4242'), + // color: HexColor.fromHex(widget?.style['title_color'] ?? ''), + color: HexColor.fromHex(widget?.styleModel?.titleColor ?? ''), + fontSize: 14, + ), + ), + ) + ], + ), + ); } } diff --git a/lib/widgets/home/home_goods/home_goods.dart b/lib/widgets/home/home_goods/home_goods.dart index 4273ac6..42e10da 100644 --- a/lib/widgets/home/home_goods/home_goods.dart +++ b/lib/widgets/home/home_goods/home_goods.dart @@ -99,7 +99,7 @@ class _HomeGoodsContainerState extends State<_HomeGoodsContainer> { // } Loading.dismiss(); List goods = snapshot.data; - int column = int.tryParse(_style.listColumn); + int column = int.tryParse(_style.listColumn ?? '1'); column = column <= 0 ? 1 : column; int count = ((goods?.length ?? 0) / column).ceil(); return SliverList( diff --git a/lib/widgets/home/home_slide_banner/home_slide_banner.dart b/lib/widgets/home/home_slide_banner/home_slide_banner.dart index c945ffe..d2544a0 100644 --- a/lib/widgets/home/home_slide_banner/home_slide_banner.dart +++ b/lib/widgets/home/home_slide_banner/home_slide_banner.dart @@ -117,9 +117,15 @@ class _HomeSlideBannerContainerState extends State { IndexCarousel items = datas.index_carousel_list[index]; return Container( width: double.infinity, - child: CachedNetworkImage( - imageUrl: items?.img ?? '', - fit: BoxFit.cover, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7.5) + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(7.5), + child: CachedNetworkImage( + imageUrl: items?.img ?? '', + fit: BoxFit.cover, + ), ), ); }, diff --git a/lib/widgets/mine/mine_header/mine_header_container.dart b/lib/widgets/mine/mine_header/mine_header_container.dart index 72bf4db..d01c268 100644 --- a/lib/widgets/mine/mine_header/mine_header_container.dart +++ b/lib/widgets/mine/mine_header/mine_header_container.dart @@ -11,6 +11,9 @@ import 'package:zhiying_base_widget/widgets/mine/mine_header/model/mine_profile_ import 'package:zhiying_comm/util/base_bloc.dart'; import 'package:zhiying_comm/zhiying_comm.dart'; +/// +/// 我的页面:头部wiget +/// class MineHeaderContainer extends StatefulWidget { final Map data; Map json;