@@ -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<CustomItemPageEvent, CustomItemPageState> { | |||||
// CustomItemPageBloc() : super(CustomItemPageInitial()); | |||||
CustomItemPageRepository repository; | |||||
CustomItemPageBloc(this.repository); | |||||
@override | |||||
CustomItemPageState get initialState => CustomItemPageInitial(); | |||||
@override | |||||
Stream<CustomItemPageState> 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<CustomItemPageState> _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<CustomItemPageState> _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<CustomItemPageState> _mapLoadEventToState(CustomItemPageLoadEvent event) async* {} | |||||
} |
@@ -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 {} |
@@ -0,0 +1,56 @@ | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class CustomItemPageRepository { | |||||
final Map<String, dynamic> data; | |||||
final int tabIndex; | |||||
final String modId; | |||||
final String modPid; | |||||
CustomItemPageRepository(this.data, this.tabIndex, this.modId, this.modPid); | |||||
/// 获取网络Style | |||||
Future<List<Map<String, dynamic>>> 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<String, dynamic>.from(e)).toList(); | |||||
} | |||||
} | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取缓存Style | |||||
Future<List<Map<String, dynamic>>> 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<String, dynamic>.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'; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,32 @@ | |||||
import 'package:meta/meta.dart'; | |||||
@immutable | |||||
abstract class CustomItemPageState {} | |||||
/// 骨架图状态 | |||||
class CustomItemPageInitial extends CustomItemPageState {} | |||||
/// 数据加载成功 | |||||
class CustomItemPageLoadedState extends CustomItemPageState { | |||||
final List<Map<String, dynamic>> 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 {} |
@@ -8,12 +8,16 @@ class CustomPageRepository { | |||||
/// 初始化 | /// 初始化 | ||||
Future<List<Map<String, dynamic>>> fetchInitData() async { | Future<List<Map<String, dynamic>>> fetchInitData() async { | ||||
try { | 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)) { | 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<String, dynamic>.from(e)).toList(); | |||||
} | |||||
} | |||||
} | } | ||||
} catch (e, s) { | } catch (e, s) { | ||||
Logger.error(e, s); | Logger.error(e, s); | ||||
@@ -23,7 +27,19 @@ class CustomPageRepository { | |||||
/// 缓存数据 | /// 缓存数据 | ||||
Future<List<Map<String, dynamic>>> fetchCacheData() async { | Future<List<Map<String, dynamic>>> 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<String, dynamic>.from(e)).toList(); | |||||
} | |||||
} | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | Logger.error(e, s); | ||||
} | } | ||||
return null; | return null; | ||||
@@ -1,7 +1,11 @@ | |||||
import 'package:meta/meta.dart'; | import 'package:meta/meta.dart'; | ||||
import 'package:equatable/equatable.dart'; | |||||
@immutable | @immutable | ||||
abstract class CustomPageState {} | |||||
abstract class CustomPageState extends Equatable{ | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 初始化 | /// 初始化 | ||||
class CustomPageInitialState extends CustomPageState {} | class CustomPageInitialState extends CustomPageState {} | ||||
@@ -10,6 +14,8 @@ class CustomPageInitialState extends CustomPageState {} | |||||
class CustomPageLoadedState extends CustomPageState { | class CustomPageLoadedState extends CustomPageState { | ||||
List<Map<String, dynamic>> model; | List<Map<String, dynamic>> model; | ||||
CustomPageLoadedState({this.model}); | CustomPageLoadedState({this.model}); | ||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | } | ||||
/// 刷新成功 | /// 刷新成功 | ||||
@@ -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<String, dynamic> 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<CustomItemPageBloc>( | |||||
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<String, dynamic> 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<CustomItemPageBloc>(context).add(CustomItemPageInitEvent()); | |||||
} | |||||
/// 刷新 | |||||
void _refreshEvent() { | |||||
BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageRefreshEvent()); | |||||
} | |||||
/// 下拉更多 | |||||
void _loadEvent() { | |||||
// BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageLoadEvent()); | |||||
Provider.of<MainPageNotifier>(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<CustomItemPageBloc, CustomItemPageState>( | |||||
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<Map<String, dynamic>> 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<Widget> _buildContentWidgets(final List<Map<String, dynamic>> datas) { | |||||
List<Widget> result = []; | |||||
for (int i = 0; i < datas.length; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
result.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: true, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
return result; | |||||
} | |||||
/// 空数据 | |||||
Widget _buildEmptyWidget() { | |||||
return Container(); | |||||
} | |||||
/// 骨架图 | |||||
Widget _buildSkeletonWidget() { | |||||
return Container(); | |||||
} | |||||
} |
@@ -1,17 +1,22 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:pull_to_refresh/pull_to_refresh.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/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:zhiying_comm/zhiying_comm.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:provider/provider.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 'package:flutter_bloc/flutter_bloc.dart'; | ||||
import 'bloc/custom_page_bloc.dart'; | import 'bloc/custom_page_bloc.dart'; | ||||
import 'bloc/custom_page_state.dart'; | import 'bloc/custom_page_state.dart'; | ||||
import 'bloc/custom_page_event.dart'; | import 'bloc/custom_page_event.dart'; | ||||
import 'bloc/custom_page_repository.dart'; | import 'bloc/custom_page_repository.dart'; | ||||
import 'dart:ui'; | import 'dart:ui'; | ||||
import 'package:fluttertoast/fluttertoast.dart'; | |||||
/// | /// | ||||
/// 通用模块页面 | /// 通用模块页面 | ||||
@@ -24,55 +29,39 @@ class CustomPage extends StatelessWidget { | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
// return NestedScrollDemoPage(); | // return NestedScrollDemoPage(); | ||||
return BlocProvider<CustomPageBloc>( | |||||
create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()), | |||||
child: _CommonPageContainer(), | |||||
// ), | |||||
return MultiProvider( | |||||
providers: [ | |||||
ChangeNotifierProvider.value(value: MainPageBgNotifier()), | |||||
], | |||||
child: BlocProvider<CustomPageBloc>( | |||||
create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()), | |||||
child: _CommonPageContainer(data), | |||||
// ), | |||||
), | |||||
); | ); | ||||
} | } | ||||
} | } | ||||
class _CommonPageContainer extends StatefulWidget { | class _CommonPageContainer extends StatefulWidget { | ||||
final Map<String, dynamic> data; | |||||
_CommonPageContainer(this.data); | |||||
@override | @override | ||||
__CommonPageContainerState createState() => __CommonPageContainerState(); | __CommonPageContainerState createState() => __CommonPageContainerState(); | ||||
} | } | ||||
class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin { | class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin { | ||||
ScrollController _controller; | |||||
ScrollController _controller2; | |||||
RefreshController _refreshController; | |||||
TabController _tabController; | TabController _tabController; | ||||
bool _isEnded = false; | |||||
/// 回到顶点 | |||||
void _scrollTop() { | |||||
// _controller.jumpTo(0); | |||||
_controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.linear); | |||||
} | |||||
/// 刷新 | /// 刷新 | ||||
void _onRefreshEvent() async { | void _onRefreshEvent() async { | ||||
BlocProvider.of<CustomPageBloc>(context).add(CustomPageRefreshEvent()); | BlocProvider.of<CustomPageBloc>(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 | @override | ||||
void dispose() { | void dispose() { | ||||
_controller?.dispose(); | |||||
_refreshController?.dispose(); | |||||
_tabController?.dispose(); | _tabController?.dispose(); | ||||
_controller2?.dispose(); | |||||
super.dispose(); | super.dispose(); | ||||
} | } | ||||
@@ -87,244 +76,43 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single | |||||
return false; | return false; | ||||
} | } | ||||
if (current is CustomPageRefreshSuccessState) { | if (current is CustomPageRefreshSuccessState) { | ||||
_refreshController.refreshCompleted(resetFooterState: true); | |||||
// _refreshController.refreshCompleted(resetFooterState: true); | |||||
return false; | return false; | ||||
} | } | ||||
if (current is CustomPageRefreshErrorState) { | if (current is CustomPageRefreshErrorState) { | ||||
_refreshController.refreshFailed(); | |||||
// _refreshController.refreshFailed(); | |||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
}, | }, | ||||
builder: (context, state) { | 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: <Widget>[ | |||||
_buildQucikEntry(), | |||||
_buildSearch(), | |||||
_buildSliverBanner(), | |||||
_buildGoodsList(), | |||||
], | |||||
), | |||||
), | |||||
)), | |||||
), | |||||
) | |||||
/// 初始化失败 | |||||
if (state is CustomPageInitErrorState) { | |||||
return _buildEmptyWidget(); | |||||
} | |||||
], | |||||
), | |||||
/// 骨架图 | |||||
return _buildSkeletonWidget(); | |||||
}, | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
/// 有数据2 | |||||
Widget _buildMain2Widget(){ | |||||
/// 有数据 | |||||
Widget _buildMainWidget(List<Map<String, dynamic>> model) { | |||||
return Scaffold( | return Scaffold( | ||||
appBar: AppBar(title: Text('标题'),centerTitle: true,), | |||||
appBar: _buildAppbar(model?.first), | |||||
backgroundColor: HexColor.fromHex('#F9F9F9'), | backgroundColor: HexColor.fromHex('#F9F9F9'), | ||||
floatingActionButton: _buildFloatWidget(), | |||||
// floatingActionButton: _buildFloatWidget(), | |||||
floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100), | floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100), | ||||
body: Column( | |||||
children: <Widget>[ | |||||
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: <Widget>[ | |||||
_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), | onPressed: () => Navigator.maybePop(context), | ||||
), | ), | ||||
title: Text( | 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, | centerTitle: true, | ||||
elevation: 0, | elevation: 0, | ||||
@@ -383,8 +171,179 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single | |||||
], | ], | ||||
)); | )); | ||||
} | } | ||||
/// 数据,生成第一层widget | |||||
List<Widget> _buildFirstWidget(List<Map<String, dynamic>> model) { | |||||
List<Widget> 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<String, dynamic> 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<String, dynamic>.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<String, dynamic> model) { | |||||
if (EmptyUtil.isEmpty(model)) return null; | |||||
String mobName = model['mod_name']; | |||||
if (!mobName.contains('_appbar')) return null; | |||||
Map<String, dynamic> data = Map<String, dynamic>(); | |||||
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<Widget> _buildTabBar(final Map<String, dynamic> model) { | |||||
Map<String, dynamic> data = Map<String, dynamic>(); | |||||
List<Map<String, dynamic>> listStyle = []; | |||||
List<Widget> 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<Widget> _buildTabBarViewChildren(final List<Map<String, dynamic>> listStyle, final String modId, final String modPid) { | |||||
List<Widget> 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 { | class _CustomFloatingActionButtonLocation extends FloatingActionButtonLocation { | ||||
FloatingActionButtonLocation location; | FloatingActionButtonLocation location; | ||||
double offsetX; // X方向的偏移量 | double offsetX; // X方向的偏移量 | ||||
@@ -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/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/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/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/appbar/goods_details_appbar_widget.dart'; | ||||
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
@@ -35,7 +36,7 @@ class _GoodsDetailsPageState extends State<GoodsDetailsPage> { | |||||
return MultiProvider( | return MultiProvider( | ||||
providers: [ | providers: [ | ||||
/// 滑动通知 | /// 滑动通知 | ||||
ChangeNotifierProvider.value(value: GoodsDetailsPageNotifier()), | |||||
ChangeNotifierProvider.value(value: MainPageNotifier()), | |||||
ChangeNotifierProvider.value(value: GoodsDetailsAppBarColorNotifier()), | ChangeNotifierProvider.value(value: GoodsDetailsAppBarColorNotifier()), | ||||
], | ], | ||||
child: BlocProvider<GoodsDetailsPageBloc>( | child: BlocProvider<GoodsDetailsPageBloc>( | ||||
@@ -83,10 +84,10 @@ class _GoodsDetailsContainerState extends State<GoodsDetailsContainer> { | |||||
if (_controller.offset >= _controller.position.maxScrollExtent && !_isEnded) { | if (_controller.offset >= _controller.position.maxScrollExtent && !_isEnded) { | ||||
// 滑动到底部 | // 滑动到底部 | ||||
_isEnded = true; | _isEnded = true; | ||||
Provider.of<GoodsDetailsPageNotifier>(context, listen: false).loadMore(); | |||||
Provider.of<MainPageNotifier>(context, listen: false).loadMore(); | |||||
} else if (_controller.offset < _controller.position.maxScrollExtent && _isEnded) { | } else if (_controller.offset < _controller.position.maxScrollExtent && _isEnded) { | ||||
_isEnded = false; | _isEnded = false; | ||||
Provider.of<GoodsDetailsPageNotifier>(context, listen: false).reset(); | |||||
Provider.of<MainPageNotifier>(context, listen: false).reset(); | |||||
} | } | ||||
if (_controller.offset >= 0 && _controller.offset <= BANNER_HEIGHT) { | if (_controller.offset >= 0 && _controller.offset <= BANNER_HEIGHT) { | ||||
@@ -1,16 +1,16 @@ | |||||
import 'package:flutter/material.dart'; | 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(); | |||||
// } | |||||
// } |
@@ -173,9 +173,9 @@ class _MainPageContainerState extends State<_MainPageContainer> { | |||||
list.add(SliverToBoxAdapter( | list.add(SliverToBoxAdapter( | ||||
child: Container( | child: Container( | ||||
height: 200, | height: 200, | ||||
child: Center( | |||||
child: Text('暂时无数据哦~'), | |||||
), | |||||
// child: Center( | |||||
// child: Text('暂时无数据哦~'), | |||||
// ), | |||||
), | ), | ||||
)); | )); | ||||
} | } | ||||
@@ -1,11 +1,9 @@ | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
/// | /// | ||||
/// 通用模块的tabbar | |||||
/// 首页的骨架图 | |||||
/// | /// | ||||
class CustomTabBarWidget extends StatelessWidget { | |||||
class MainPageSkeleton extends StatelessWidget { | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return Container(); | return Container(); |
@@ -265,16 +265,16 @@ class OfficalWxchat { | |||||
} | } | ||||
class OfficalWxchatList { | class OfficalWxchatList { | ||||
String type; | |||||
String index; | |||||
String text; | String text; | ||||
String subText; | String subText; | ||||
String wechatAccount; | String wechatAccount; | ||||
String qrcode; | 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<String, dynamic> json) { | OfficalWxchatList.fromJson(Map<String, dynamic> json) { | ||||
type = json['type']; | |||||
index = json['index']; | |||||
text = json['text']; | text = json['text']; | ||||
subText = json['sub_text']; | subText = json['sub_text']; | ||||
wechatAccount = json['wechat_account']; | wechatAccount = json['wechat_account']; | ||||
@@ -283,7 +283,7 @@ class OfficalWxchatList { | |||||
Map<String, dynamic> toJson() { | Map<String, dynamic> toJson() { | ||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
data['type'] = this.type; | |||||
data['index'] = this.index; | |||||
data['text'] = this.text; | data['text'] = this.text; | ||||
data['sub_text'] = this.subText; | data['sub_text'] = this.subText; | ||||
data['wechat_account'] = this.wechatAccount; | data['wechat_account'] = this.wechatAccount; | ||||
@@ -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/webview/base_webview.dart'; | ||||
import 'package:zhiying_base_widget/pages/wechat_teacher_page/wechat_teacher_page.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/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/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/price/goods_details_price_widget.dart'; | ||||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_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 | /// 可滚动banner | ||||
WidgetFactory.regist('index_carousel', HomeSlideBannerCreater()); | WidgetFactory.regist('index_carousel', HomeSlideBannerCreater()); | ||||
/// 首页商品推荐列表 | |||||
WidgetFactory.regist('index_recommend_list', GoodsListCreater()); | 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 | /// 不可以滚动banner | ||||
WidgetFactory.regist('index_banner_one', HomeBannerCreater()); | WidgetFactory.regist('index_banner_one', HomeBannerCreater()); | ||||
@@ -261,8 +263,7 @@ class BaseWidgetRegister { | |||||
WidgetFactory.regist('search_index_host_keyword', | WidgetFactory.regist('search_index_host_keyword', | ||||
DefaultWidgetCreater((model) => SearchHotTagWidget(model))); | 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))); | DefaultWidgetCreater((model) => HotRankTableBar(model))); | ||||
WidgetFactory.regist('hot_rank_tab_view', | WidgetFactory.regist('hot_rank_tab_view', | ||||
DefaultWidgetCreater((model) => HotRankingList(model))); | 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()); | |||||
} | } | ||||
} | } |
@@ -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<Widget> createWidgets(Map<String, dynamic> model) { | |||||
return [CustomAppBarWidget(model)]; | |||||
} | |||||
@override | |||||
bool isSliverChild() { | |||||
return true; | |||||
} | |||||
} |
@@ -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<String, dynamic> data; | |||||
Map<String, dynamic> 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, | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -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'; |
@@ -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<CustomQuickEntryEvent, CustomQuickEntryState> { | |||||
CustomQuickEntryRepository repository; | |||||
CustomQuickEntryBloc({@required this.repository}); | |||||
@override | |||||
CustomQuickEntryState get initialState => InitialCustomQuickEntryState(); | |||||
@override | |||||
Stream<CustomQuickEntryState> mapEventToState(CustomQuickEntryEvent event) async* { | |||||
/// 初始化 | |||||
if (event is CustomQuickEntryInitEvent) { | |||||
yield* _mapHomeQuickEntryInitToState(event); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<CustomQuickEntryState> _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(); | |||||
// } | |||||
} | |||||
} |
@@ -0,0 +1,18 @@ | |||||
import 'package:equatable/equatable.dart'; | |||||
abstract class CustomQuickEntryEvent extends Equatable { | |||||
const CustomQuickEntryEvent(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 初始事件 | |||||
class CustomQuickEntryInitEvent extends CustomQuickEntryEvent { | |||||
final Map<String, dynamic> model; | |||||
const CustomQuickEntryInitEvent({this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} |
@@ -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<CustomQuickEntryModel> 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<String, dynamic> data = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]; | |||||
return _getHomeQuickEntryModel(data); | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取父页面传进来的数据 | |||||
Future<CustomQuickEntryModel> 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<CustomQuickEntryModel> 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; | |||||
} | |||||
} |
@@ -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<Object> get props => []; | |||||
} | |||||
/// 初始化状态 | |||||
class InitialCustomQuickEntryState extends CustomQuickEntryState { | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 加载数据完毕 | |||||
class CustomQuickEntryLoadedState extends CustomQuickEntryState { | |||||
final CustomQuickEntryModel model; | |||||
const CustomQuickEntryLoadedState({@required this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | |||||
/// 加载缓存数据 | |||||
class CustomQuickEntryCachedState extends CustomQuickEntryState { | |||||
final CustomQuickEntryModel model; | |||||
const CustomQuickEntryCachedState({@required this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | |||||
/// 加载数据出错 | |||||
class CustomQuickEntryErrorState extends CustomQuickEntryState {} |
@@ -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, | |||||
); | |||||
} | |||||
} | |||||
@@ -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<String, dynamic> model; | |||||
const CustomQuickEntry(this.model); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocProvider<CustomQuickEntryBloc>( | |||||
create: (_) => CustomQuickEntryBloc(repository: CustomQuickEntryRepository())..add(CustomQuickEntryInitEvent(model: model)), | |||||
child: _CustomQuickEntryContainer(model), | |||||
); | |||||
} | |||||
} | |||||
class _CustomQuickEntryContainer extends StatefulWidget { | |||||
final Map<String, dynamic> 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<CustomQuickEntryBloc, CustomQuickEntryState>( | |||||
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: <Widget>[ | |||||
/// 图标 | |||||
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, | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -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<Widget> createSkeleton(Map<String, dynamic> model) { | |||||
return [CustomQuickEntrySkeleton()]; | |||||
} | |||||
@override | |||||
List<Widget> createWidgets(Map<String, dynamic> model) { | |||||
return [CustomQuickEntry(model)]; | |||||
} | |||||
} |
@@ -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: <Widget>[ | |||||
// 图片 | |||||
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,), | |||||
], | |||||
), | |||||
)); | |||||
} | |||||
} |
@@ -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> listStyle; | |||||
List<TypeList> 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<String, dynamic> 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<ListStyle>(); | |||||
json['list_style'].forEach((v) { | |||||
listStyle.add(new ListStyle.fromJson(v)); | |||||
}); | |||||
} | |||||
if (json['type_list'] != null) { | |||||
typeList = new List<TypeList>(); | |||||
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<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
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<String, dynamic> 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<String, dynamic> toJson() { | |||||
final Map<String, dynamic> 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<String, dynamic> json) { | |||||
name = json['name']; | |||||
key = json['key']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['name'] = this.name; | |||||
data['key'] = this.key; | |||||
return data; | |||||
} | |||||
} |
@@ -1,13 +1,70 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | 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'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
/// | /// | ||||
/// 通用模块的搜索栏 | /// 通用模块的搜索栏 | ||||
/// | /// | ||||
class CustomSearchWidget extends StatelessWidget { | class CustomSearchWidget extends StatelessWidget { | ||||
final Map<String, dynamic> 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 | @override | ||||
Widget build(BuildContext context) { | 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: <Widget>[ | |||||
/// 搜索按钮 | |||||
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')), | |||||
) | |||||
], | |||||
), | |||||
), | |||||
), | |||||
); | |||||
} | } | ||||
} | } |
@@ -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<String, dynamic> 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<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
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<String, dynamic> 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<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
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<String, dynamic> 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<String, dynamic> toJson() { | |||||
final Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> toJson() { | |||||
final Map<String, dynamic> 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; | |||||
} | |||||
} |
@@ -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'; |
@@ -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<CustomSlideBannerEvent, CustomSlideBannerState> { | |||||
CustomSlideBannerRepository repository; | |||||
CustomSlideBannerBloc({@required this.repository}); | |||||
@override | |||||
CustomSlideBannerState get initialState => InitialCustomSlideBannerState(); | |||||
@override | |||||
Stream<CustomSlideBannerState> mapEventToState(CustomSlideBannerEvent event) async* { | |||||
final currentState = state; | |||||
/// 初始化 | |||||
if (event is CustomBannerInitEvent) { | |||||
print('---------HomeBannerInitEvent---------'); | |||||
yield* _mapInitEventToState(event); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<CustomSlideBannerState> _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(); | |||||
} | |||||
} |
@@ -0,0 +1,14 @@ | |||||
import 'package:equatable/equatable.dart'; | |||||
abstract class CustomSlideBannerEvent extends Equatable { | |||||
const CustomSlideBannerEvent(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 初始事件 | |||||
class CustomBannerInitEvent extends CustomSlideBannerEvent{ | |||||
final Map<String, dynamic> model; | |||||
const CustomBannerInitEvent({this.model}); | |||||
} |
@@ -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<CustomSlideBannerModel> 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<CustomSlideBannerModel> fetchPreantData(@required Map<String, dynamic> model) async { | |||||
try { | |||||
if (!EmptyUtil.isEmpty(model)) { | |||||
return CustomSlideBannerModel.fromJson(jsonDecode(model['data'])); | |||||
} | |||||
} catch (e) {} | |||||
return null; | |||||
} | |||||
/// 获取数据 | |||||
Future<CustomSlideBannerModel> 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; | |||||
} | |||||
} |
@@ -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<Object> get props => []; | |||||
} | |||||
/// 初始化状态 | |||||
class InitialCustomSlideBannerState extends CustomSlideBannerState { | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 缓存数据 | |||||
class CustomSlideBannerCachedState extends CustomSlideBannerState { | |||||
CustomSlideBannerModel datas; | |||||
CustomSlideBannerCachedState({this.datas}); | |||||
@override | |||||
List<Object> get props => [this.datas]; | |||||
} | |||||
/// 数据加载完毕状态 | |||||
class HomeSlideBannerLoadedState extends CustomSlideBannerState { | |||||
CustomSlideBannerModel datas; | |||||
HomeSlideBannerLoadedState({this.datas}); | |||||
HomeSlideBannerLoadedState copyWith({CustomSlideBannerModel newData}) { | |||||
return HomeSlideBannerLoadedState( | |||||
datas: newData ?? datas, | |||||
); | |||||
} | |||||
@override | |||||
List<Object> get props => [datas]; | |||||
} | |||||
/// 数据加载失败 | |||||
class HomeSlideBannerLoadError extends CustomSlideBannerState {} |
@@ -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<String, dynamic> model; | |||||
const CustomSlideBanner(this.model, {Key key}) : super(key: key); | |||||
@override | |||||
_CustomSlideBannerState createState() => _CustomSlideBannerState(); | |||||
} | |||||
class _CustomSlideBannerState extends State<CustomSlideBanner> { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocProvider<CustomSlideBannerBloc>( | |||||
create: (_) => CustomSlideBannerBloc(repository: CustomSlideBannerRepository())..add(CustomBannerInitEvent(model: widget?.model)), | |||||
child: CustomSlideBannerContainer(), | |||||
); | |||||
} | |||||
} | |||||
class CustomSlideBannerContainer extends StatefulWidget { | |||||
@override | |||||
_CustomSlideBannerContainerState createState() => _CustomSlideBannerContainerState(); | |||||
} | |||||
class _CustomSlideBannerContainerState extends State<CustomSlideBannerContainer> { | |||||
/// 子元素点击事件 | |||||
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<CustomSlideBannerBloc, CustomSlideBannerState>( | |||||
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<MainPageBgNotifier>(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<MainPageBgNotifier>(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)); | |||||
} | |||||
} |
@@ -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<Widget> createSkeleton(Map<String, dynamic> model) { | |||||
return [CustomSlideBannerSkeleton()]; | |||||
} | |||||
@override | |||||
List<Widget> createWidgets(Map<String, dynamic> model) { | |||||
return [ | |||||
CustomSlideBanner(model), | |||||
]; | |||||
} | |||||
} |
@@ -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))), | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -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> 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<String, dynamic> 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<IndexCarouselList>(); | |||||
json['index_carousel_list'].forEach((v) { | |||||
indexCarouselList.add(new IndexCarouselList.fromJson(v)); | |||||
}); | |||||
} | |||||
moduleKeyId = json['module_key_id']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
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<String, dynamic> 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<String, dynamic> toJson() { | |||||
final Map<String, dynamic> 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; | |||||
} | |||||
} |
@@ -4,11 +4,13 @@ import 'package:flutter/cupertino.dart'; | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:provider/provider.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/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/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.dart'; | ||||
import 'package:zhiying_base_widget/widgets/home/home_goods/home_goods_item_single.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_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/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'; | import 'package:zhiying_comm/util/base_bloc.dart'; | ||||
class GoodsDetailCommendList extends StatefulWidget { | class GoodsDetailCommendList extends StatefulWidget { | ||||
@@ -40,16 +42,13 @@ class _GoodsDetailCommendListContainer extends StatefulWidget { | |||||
final Map<String, dynamic> data; | final Map<String, dynamic> data; | ||||
final String provider; | final String provider; | ||||
_GoodsDetailCommendListContainer(this.data, this.provider, {Key key}) | |||||
: super(key: key); | |||||
_GoodsDetailCommendListContainer(this.data, this.provider, {Key key}) : super(key: key); | |||||
@override | @override | ||||
_GoodsDetailCommendListContainerState createState() => | |||||
_GoodsDetailCommendListContainerState(); | |||||
_GoodsDetailCommendListContainerState createState() => _GoodsDetailCommendListContainerState(); | |||||
} | } | ||||
class _GoodsDetailCommendListContainerState | |||||
extends State<_GoodsDetailCommendListContainer> { | |||||
class _GoodsDetailCommendListContainerState extends State<_GoodsDetailCommendListContainer> { | |||||
HomeGoodsBloc _bloc; | HomeGoodsBloc _bloc; | ||||
HomeGoodsStyleModel _style; | HomeGoodsStyleModel _style; | ||||
@@ -70,8 +69,7 @@ class _GoodsDetailCommendListContainerState | |||||
void didChangeDependencies() { | void didChangeDependencies() { | ||||
super.didChangeDependencies(); | super.didChangeDependencies(); | ||||
print('didChangeDependencies'); | print('didChangeDependencies'); | ||||
bool isNeedLoadMore = | |||||
Provider.of<GoodsDetailsPageNotifier>(context).scrollEnd; | |||||
bool isNeedLoadMore = Provider.of<MainPageNotifier>(context).scrollEnd; | |||||
if (isNeedLoadMore && widget.provider != '') { | if (isNeedLoadMore && widget.provider != '') { | ||||
print('HomeGoods loadmore...'); | print('HomeGoods loadmore...'); | ||||
_bloc.loadMore(widget.provider); | _bloc.loadMore(widget.provider); | ||||
@@ -83,6 +81,10 @@ class _GoodsDetailCommendListContainerState | |||||
return StreamBuilder<List<HomeGoodsModel>>( | return StreamBuilder<List<HomeGoodsModel>>( | ||||
stream: _bloc.outData, | stream: _bloc.outData, | ||||
builder: (BuildContext context, AsyncSnapshot snapshot) { | builder: (BuildContext context, AsyncSnapshot snapshot) { | ||||
if (snapshot.data == null) { | |||||
return SliverToBoxAdapter(child: HomeGoodsSkeleton()); | |||||
} | |||||
List<HomeGoodsModel> goods = snapshot.data; | List<HomeGoodsModel> goods = snapshot.data; | ||||
int column = 2; | int column = 2; | ||||
int count = ((goods?.length ?? 0) / column).ceil(); | int count = ((goods?.length ?? 0) / column).ceil(); | ||||
@@ -8,9 +8,10 @@ import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class GoodsDetailsRecommendWidget extends StatefulWidget { | class GoodsDetailsRecommendWidget extends StatefulWidget { | ||||
final Map<String, dynamic> data; | final Map<String, dynamic> data; | ||||
// Map<String, dynamic> style = {}; | // Map<String, dynamic> style = {}; | ||||
HomeGoodsStyleModel styleModel; | HomeGoodsStyleModel styleModel; | ||||
GoodsDetailsRecommendWidget(this.data, {Key key}) : super(key: key) { | GoodsDetailsRecommendWidget(this.data, {Key key}) : super(key: key) { | ||||
try { | try { | ||||
styleModel = HomeGoodsStyleModel.fromJson(convert.jsonDecode(data['data'])); | styleModel = HomeGoodsStyleModel.fromJson(convert.jsonDecode(data['data'])); | ||||
@@ -47,36 +48,39 @@ class _GoodsDetailsRecommendWidgetState extends State<GoodsDetailsRecommendWidge | |||||
} | } | ||||
Widget _createTitle() { | Widget _createTitle() { | ||||
return Container( | |||||
width: double.infinity, | |||||
height: 50, | |||||
child: Row( | |||||
crossAxisAlignment: CrossAxisAlignment.center, | |||||
mainAxisAlignment: MainAxisAlignment.center, | |||||
children: <Widget>[ | |||||
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: <Widget>[ | |||||
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, | |||||
), | |||||
), | |||||
) | |||||
], | |||||
), | |||||
); | |||||
} | } | ||||
} | } |
@@ -99,7 +99,7 @@ class _HomeGoodsContainerState extends State<_HomeGoodsContainer> { | |||||
// } | // } | ||||
Loading.dismiss(); | Loading.dismiss(); | ||||
List<HomeGoodsModel> goods = snapshot.data; | List<HomeGoodsModel> goods = snapshot.data; | ||||
int column = int.tryParse(_style.listColumn); | |||||
int column = int.tryParse(_style.listColumn ?? '1'); | |||||
column = column <= 0 ? 1 : column; | column = column <= 0 ? 1 : column; | ||||
int count = ((goods?.length ?? 0) / column).ceil(); | int count = ((goods?.length ?? 0) / column).ceil(); | ||||
return SliverList( | return SliverList( | ||||
@@ -117,9 +117,15 @@ class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> { | |||||
IndexCarousel items = datas.index_carousel_list[index]; | IndexCarousel items = datas.index_carousel_list[index]; | ||||
return Container( | return Container( | ||||
width: double.infinity, | 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, | |||||
), | |||||
), | ), | ||||
); | ); | ||||
}, | }, | ||||
@@ -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/util/base_bloc.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
/// | |||||
/// 我的页面:头部wiget | |||||
/// | |||||
class MineHeaderContainer extends StatefulWidget { | class MineHeaderContainer extends StatefulWidget { | ||||
final Map<String, dynamic> data; | final Map<String, dynamic> data; | ||||
Map<String, dynamic> json; | Map<String, dynamic> json; | ||||