# Conflicts: # .dart_tool/package_config.json # lib/register.darttags/0.0.1
@@ -770,7 +770,7 @@ | |||
"languageVersion": "2.1" | |||
} | |||
], | |||
"generated": "2020-09-19T06:19:07.938950Z", | |||
"generated": "2020-09-21T02:27:30.928433Z", | |||
"generator": "pub", | |||
"generatorVersion": "2.7.2" | |||
} |
@@ -1,6 +0,0 @@ | |||
<component name="ProjectRunConfigurationManager"> | |||
<configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter"> | |||
<option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" /> | |||
<method /> | |||
</configuration> | |||
</component> |
@@ -1,13 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="SaveActionSettings"> | |||
<option name="actions"> | |||
<set> | |||
<option value="activate" /> | |||
<option value="organizeImports" /> | |||
<option value="reformat" /> | |||
</set> | |||
</option> | |||
<option name="configurationPath" value="" /> | |||
</component> | |||
</project> |
@@ -0,0 +1,160 @@ | |||
#!/usr/bin/env bash | |||
############################################################################## | |||
## | |||
## Gradle start up script for UN*X | |||
## | |||
############################################################################## | |||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
DEFAULT_JVM_OPTS="" | |||
APP_NAME="Gradle" | |||
APP_BASE_NAME=`basename "$0"` | |||
# Use the maximum available, or set MAX_FD != -1 to use that value. | |||
MAX_FD="maximum" | |||
warn ( ) { | |||
echo "$*" | |||
} | |||
die ( ) { | |||
echo | |||
echo "$*" | |||
echo | |||
exit 1 | |||
} | |||
# OS specific support (must be 'true' or 'false'). | |||
cygwin=false | |||
msys=false | |||
darwin=false | |||
case "`uname`" in | |||
CYGWIN* ) | |||
cygwin=true | |||
;; | |||
Darwin* ) | |||
darwin=true | |||
;; | |||
MINGW* ) | |||
msys=true | |||
;; | |||
esac | |||
# Attempt to set APP_HOME | |||
# Resolve links: $0 may be a link | |||
PRG="$0" | |||
# Need this for relative symlinks. | |||
while [ -h "$PRG" ] ; do | |||
ls=`ls -ld "$PRG"` | |||
link=`expr "$ls" : '.*-> \(.*\)$'` | |||
if expr "$link" : '/.*' > /dev/null; then | |||
PRG="$link" | |||
else | |||
PRG=`dirname "$PRG"`"/$link" | |||
fi | |||
done | |||
SAVED="`pwd`" | |||
cd "`dirname \"$PRG\"`/" >/dev/null | |||
APP_HOME="`pwd -P`" | |||
cd "$SAVED" >/dev/null | |||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |||
# Determine the Java command to use to start the JVM. | |||
if [ -n "$JAVA_HOME" ] ; then | |||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |||
# IBM's JDK on AIX uses strange locations for the executables | |||
JAVACMD="$JAVA_HOME/jre/sh/java" | |||
else | |||
JAVACMD="$JAVA_HOME/bin/java" | |||
fi | |||
if [ ! -x "$JAVACMD" ] ; then | |||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |||
Please set the JAVA_HOME variable in your environment to match the | |||
location of your Java installation." | |||
fi | |||
else | |||
JAVACMD="java" | |||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
Please set the JAVA_HOME variable in your environment to match the | |||
location of your Java installation." | |||
fi | |||
# Increase the maximum file descriptors if we can. | |||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | |||
MAX_FD_LIMIT=`ulimit -H -n` | |||
if [ $? -eq 0 ] ; then | |||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |||
MAX_FD="$MAX_FD_LIMIT" | |||
fi | |||
ulimit -n $MAX_FD | |||
if [ $? -ne 0 ] ; then | |||
warn "Could not set maximum file descriptor limit: $MAX_FD" | |||
fi | |||
else | |||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |||
fi | |||
fi | |||
# For Darwin, add options to specify how the application appears in the dock | |||
if $darwin; then | |||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |||
fi | |||
# For Cygwin, switch paths to Windows format before running java | |||
if $cygwin ; then | |||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |||
JAVACMD=`cygpath --unix "$JAVACMD"` | |||
# We build the pattern for arguments to be converted via cygpath | |||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |||
SEP="" | |||
for dir in $ROOTDIRSRAW ; do | |||
ROOTDIRS="$ROOTDIRS$SEP$dir" | |||
SEP="|" | |||
done | |||
OURCYGPATTERN="(^($ROOTDIRS))" | |||
# Add a user-defined pattern to the cygpath arguments | |||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |||
fi | |||
# Now convert the arguments - kludge to limit ourselves to /bin/sh | |||
i=0 | |||
for arg in "$@" ; do | |||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |||
else | |||
eval `echo args$i`="\"$arg\"" | |||
fi | |||
i=$((i+1)) | |||
done | |||
case $i in | |||
(0) set -- ;; | |||
(1) set -- "$args0" ;; | |||
(2) set -- "$args0" "$args1" ;; | |||
(3) set -- "$args0" "$args1" "$args2" ;; | |||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |||
esac | |||
fi | |||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | |||
function splitJvmOpts() { | |||
JVM_OPTS=("$@") | |||
} | |||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | |||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | |||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
@@ -0,0 +1,90 @@ | |||
@if "%DEBUG%" == "" @echo off | |||
@rem ########################################################################## | |||
@rem | |||
@rem Gradle startup script for Windows | |||
@rem | |||
@rem ########################################################################## | |||
@rem Set local scope for the variables with windows NT shell | |||
if "%OS%"=="Windows_NT" setlocal | |||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
set DEFAULT_JVM_OPTS= | |||
set DIRNAME=%~dp0 | |||
if "%DIRNAME%" == "" set DIRNAME=. | |||
set APP_BASE_NAME=%~n0 | |||
set APP_HOME=%DIRNAME% | |||
@rem Find java.exe | |||
if defined JAVA_HOME goto findJavaFromJavaHome | |||
set JAVA_EXE=java.exe | |||
%JAVA_EXE% -version >NUL 2>&1 | |||
if "%ERRORLEVEL%" == "0" goto init | |||
echo. | |||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
echo. | |||
echo Please set the JAVA_HOME variable in your environment to match the | |||
echo location of your Java installation. | |||
goto fail | |||
:findJavaFromJavaHome | |||
set JAVA_HOME=%JAVA_HOME:"=% | |||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |||
if exist "%JAVA_EXE%" goto init | |||
echo. | |||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |||
echo. | |||
echo Please set the JAVA_HOME variable in your environment to match the | |||
echo location of your Java installation. | |||
goto fail | |||
:init | |||
@rem Get command-line arguments, handling Windowz variants | |||
if not "%OS%" == "Windows_NT" goto win9xME_args | |||
if "%@eval[2+2]" == "4" goto 4NT_args | |||
:win9xME_args | |||
@rem Slurp the command line arguments. | |||
set CMD_LINE_ARGS= | |||
set _SKIP=2 | |||
:win9xME_args_slurp | |||
if "x%~1" == "x" goto execute | |||
set CMD_LINE_ARGS=%* | |||
goto execute | |||
:4NT_args | |||
@rem Get arguments from the 4NT Shell from JP Software | |||
set CMD_LINE_ARGS=%$ | |||
:execute | |||
@rem Setup the command line | |||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |||
@rem Execute Gradle | |||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | |||
:end | |||
@rem End local scope for the variables with windows NT shell | |||
if "%ERRORLEVEL%"=="0" goto mainEnd | |||
:fail | |||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |||
rem the _cmd.exe /c_ return code! | |||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |||
exit /b 1 | |||
:mainEnd | |||
if "%OS%"=="Windows_NT" endlocal | |||
:omega |
@@ -0,0 +1,39 @@ | |||
import 'dart:async'; | |||
import 'package:bloc/bloc.dart'; | |||
import 'package:equatable/equatable.dart'; | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_repository.dart'; | |||
import 'package:zhiying_comm/util/empty_util.dart'; | |||
part 'goods_details_page_event.dart'; | |||
part 'goods_details_page_state.dart'; | |||
class GoodsDetailsPageBloc extends Bloc<GoodsDetailsPageEvent, GoodsDetailsPageState> { | |||
// GoodsDetailsPageBloc() : super(GoodsDetailsPageInitial()); | |||
@override | |||
GoodsDetailsPageState get initialState => GoodsDetailsPageInitial(); | |||
GoodsDetailsPageRepository repository; | |||
GoodsDetailsPageBloc({@required this.repository}); | |||
@override | |||
Stream<GoodsDetailsPageState> mapEventToState( | |||
GoodsDetailsPageEvent event, | |||
) async* { | |||
if (event is GoodsDetailsPageInitEvent) { | |||
yield* _mapInitEventToState(event); | |||
} | |||
} | |||
Stream<GoodsDetailsPageState> _mapInitEventToState(GoodsDetailsPageInitEvent event) async* { | |||
var result = await repository.fetchInitData(event.model); | |||
if (!EmptyUtil.isEmpty(result)) | |||
yield GoodsDetailsPageLoadedState(model: result); | |||
else | |||
yield GoodsDetailsPageErrorState(); | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
part of 'goods_details_page_bloc.dart'; | |||
abstract class GoodsDetailsPageEvent extends Equatable { | |||
const GoodsDetailsPageEvent(); | |||
} | |||
/// 初始化 | |||
class GoodsDetailsPageInitEvent extends GoodsDetailsPageEvent { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsPageInitEvent({this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} |
@@ -0,0 +1,40 @@ | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class GoodsDetailsPageRepository { | |||
List<Map<String, dynamic>> _pageData = []; | |||
/// 初始化 | |||
Future<List<Map<String, dynamic>>> fetchInitData(Map<String, dynamic> model) async { | |||
int id = 13; | |||
var result = await NetUtil.post('/api/v1/mod', | |||
method: NetMethod.POST, | |||
params: Map<String, dynamic>.from({ | |||
'ids': [id] | |||
})); | |||
try { | |||
if(NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||
return _loadData(id, result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); | |||
} | |||
} catch (e) { | |||
Logger.log(e); | |||
} | |||
return null; | |||
} | |||
/// 处理数据 | |||
List<Map<String, dynamic>> _loadData(int id, dynamic data) { | |||
String key = id.toString(); | |||
Map<String, dynamic> json = Map<String, dynamic>.from(data); | |||
if (json.containsKey(key)) { | |||
List<dynamic> list = json[key]; | |||
_pageData = list.map((item) { | |||
return Map<String, dynamic>.from(item); | |||
}).toList(); | |||
return _pageData; | |||
} | |||
return null; | |||
} | |||
/// 获取缓存数据? | |||
} |
@@ -0,0 +1,24 @@ | |||
part of 'goods_details_page_bloc.dart'; | |||
abstract class GoodsDetailsPageState extends Equatable { | |||
const GoodsDetailsPageState(); | |||
@override | |||
List<Object> get props => []; | |||
} | |||
/// 初始化状态 | |||
class GoodsDetailsPageInitial extends GoodsDetailsPageState {} | |||
/// 数据加载完毕状态 | |||
class GoodsDetailsPageLoadedState extends GoodsDetailsPageState { | |||
final List<Map<String, dynamic>> model; | |||
const GoodsDetailsPageLoadedState({this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} | |||
/// 数据加载出错 | |||
class GoodsDetailsPageErrorState extends GoodsDetailsPageState {} |
@@ -0,0 +1,193 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||
import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_bloc.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/notifier/goods_details_page_notifier.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:provider/provider.dart'; | |||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||
import 'dart:ui'; | |||
class GoodsDetailsPage extends StatefulWidget { | |||
final Map<String, dynamic> data; | |||
GoodsDetailsPage(this.data, {Key key}) : super(key: key); | |||
@override | |||
_GoodsDetailsPageState createState() => _GoodsDetailsPageState(); | |||
} | |||
class _GoodsDetailsPageState extends State<GoodsDetailsPage> { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Scaffold( | |||
backgroundColor: HexColor.fromHex('#FFF1F1F1'), | |||
body: MultiProvider( | |||
providers: [ | |||
/// 滑动通知 | |||
ChangeNotifierProvider.value(value: GoodsDetailsPageNotifier()), | |||
], | |||
child: BlocProvider<GoodsDetailsPageBloc>( | |||
create: (_) => GoodsDetailsPageBloc(repository: GoodsDetailsPageRepository())..add(GoodsDetailsPageInitEvent(model: widget?.data)), | |||
child: GoodsDetailsContainer(widget?.data), | |||
), | |||
), | |||
); | |||
} | |||
} | |||
class GoodsDetailsContainer extends StatefulWidget { | |||
final Map<String, dynamic> data; | |||
const GoodsDetailsContainer(this.data); | |||
@override | |||
_GoodsDetailsContainerState createState() => _GoodsDetailsContainerState(); | |||
} | |||
class _GoodsDetailsContainerState extends State<GoodsDetailsContainer> { | |||
bool _isEnded = false; | |||
ScrollController _controller = ScrollController(); | |||
RefreshController _refreshController = RefreshController(initialRefresh: false); | |||
void _onLoading() async { | |||
// await Future.delayed(Duration(milliseconds: 1000)); | |||
// if (mounted) setState(() {}); | |||
// _refreshController.loadComplete(); | |||
} | |||
/// 返回上一页 | |||
void _openPop() { | |||
print('返回上一页'); | |||
Navigator.maybePop(context); | |||
} | |||
@override | |||
void dispose() { | |||
_controller.dispose(); | |||
super.dispose(); | |||
} | |||
@override | |||
void initState() { | |||
_controller.addListener(() { | |||
// print('${_controller.offset} ${_controller.position.maxScrollExtent}'); | |||
if (_controller.offset >= _controller.position.maxScrollExtent && !_isEnded) { | |||
// 滑动到底部 | |||
_isEnded = true; | |||
Provider.of<GoodsDetailsPageNotifier>(context, listen: false).loadMore(); | |||
} else if (_controller.offset < _controller.position.maxScrollExtent && _isEnded) { | |||
_isEnded = false; | |||
Provider.of<GoodsDetailsPageNotifier>(context, listen: false).reset(); | |||
} | |||
}); | |||
super.initState(); | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
return MediaQuery.removePadding( | |||
removeTop: true, | |||
context: context, | |||
child: Container( | |||
width: double.infinity, | |||
child: BlocConsumer<GoodsDetailsPageBloc, GoodsDetailsPageState>( | |||
listener: (BuildContext context, GoodsDetailsPageState state) { | |||
if (state is GoodsDetailsPageErrorState) { | |||
print('数据加载出错'); | |||
} | |||
}, | |||
buildWhen: (previous, current) { | |||
/// 数据加载出错不进行build | |||
if (current is GoodsDetailsPageErrorState) { | |||
return false; | |||
} | |||
return true; | |||
}, | |||
builder: (context, state) { | |||
print('currente state = $state'); | |||
if (state is GoodsDetailsPageLoadedState) { | |||
return _getMainWidget(state?.model); | |||
} | |||
return _getMainWidget(null); | |||
}, | |||
), | |||
), | |||
); | |||
} | |||
/// 主视图 | |||
Widget _getMainWidget(List<Map<String, dynamic>> datas) { | |||
return Stack( | |||
fit: StackFit.passthrough, | |||
children: <Widget>[ | |||
/// 主体布局 | |||
SmartRefresher( | |||
enablePullDown: true, | |||
enablePullUp: false, | |||
header: WaterDropHeader(), | |||
controller: _refreshController, | |||
onLoading: _onLoading, | |||
child: CustomScrollView( | |||
controller: _controller, | |||
slivers: _createContent(context, datas ?? []), | |||
), | |||
), | |||
/// appBar | |||
Align( | |||
alignment: Alignment.topCenter, | |||
child: _getAppBarWidget()), | |||
/// 底部 | |||
Align(alignment: Alignment.bottomCenter, child: GoodsDetailsFooterWidget(null)) | |||
], | |||
); | |||
} | |||
List<Widget> _createContent(BuildContext context, List<Map<String, dynamic>> datas) { | |||
List<Widget> list = List(); | |||
for (int i = 0; i < datas.length; i++) { | |||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||
print('item.modName ${item.modName}'); | |||
list.addAll(WidgetFactory.create( | |||
item.modName, | |||
isSliver: true, | |||
model: datas[i], | |||
)); | |||
} | |||
if (list.length <= 0) { | |||
list.add(SliverToBoxAdapter( | |||
child: Container( | |||
height: 200, | |||
child: Center( | |||
child: Text('暂时无数据哦~'), | |||
), | |||
), | |||
)); | |||
} | |||
return list; | |||
} | |||
/// appBar | |||
Widget _getAppBarWidget() { | |||
return Container( | |||
width: double.infinity, | |||
height: 40, | |||
margin: EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top), | |||
child: AppBar( | |||
backgroundColor: Colors.transparent, | |||
elevation: 0, | |||
leading: IconButton( | |||
icon: Icon( | |||
Icons.arrow_back_ios, | |||
size: 22, | |||
color: HexColor.fromHex('#FFFFFF'), | |||
), | |||
onPressed: () => _openPop(), | |||
), | |||
), | |||
); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
import 'package:flutter/material.dart'; | |||
class GoodsDetailsPageNotifier with ChangeNotifier { | |||
bool scrollEnd = false; | |||
// 加载更多数据 | |||
void loadMore() { | |||
scrollEnd = true; | |||
notifyListeners(); | |||
} | |||
void reset() { | |||
scrollEnd = false; | |||
notifyListeners(); | |||
} | |||
} |
@@ -1,3 +1,5 @@ | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | |||
import 'package:zhiying_base_widget/pages/home_page/home_page.dart'; | |||
import 'package:zhiying_base_widget/pages/main_page/main_page.dart'; | |||
import 'package:zhiying_base_widget/pages/mine_detail_page/mine_detail_page.dart'; | |||
@@ -5,10 +7,19 @@ import 'package:zhiying_base_widget/pages/orders_page/orders_page.dart'; | |||
import 'package:zhiying_base_widget/pages/setting_page/setting_page.dart'; | |||
import 'package:zhiying_base_widget/pages/wallet_page/wallet_page.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_auth/home_auth_creater.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/price/goods_details_price_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/store_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/upgrade_tip/upgrade_tip_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_banner/home_banner_creater.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_banner/home_banner_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_goods/home_goods_creater.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/home_notice_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/model/home_notice_model.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_slide_banner/home_slide_banner_creater.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_sreach/home_sreach_creater.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_sreach/home_sreach_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/mine/mine_data/mine_data.dart'; | |||
import 'package:zhiying_base_widget/widgets/mine/mine_header/mine_header.dart'; | |||
import 'package:zhiying_base_widget/widgets/mine/mine_nav/mine_nav_bg.dart'; | |||
@@ -16,10 +27,14 @@ import 'package:zhiying_base_widget/widgets/mine/mine_nav/mine_nav_creater.dart' | |||
import 'package:zhiying_base_widget/widgets/mine/mine_quick_entry/mine_quick_entry.dart'; | |||
import 'package:zhiying_base_widget/widgets/others/normal_nav/normal_nav_creater.dart'; | |||
import 'package:zhiying_base_widget/widgets/wallet/wallet_data/wallet_data.dart'; | |||
import 'package:zhiying_base_widget/widgets/wallet/wallet_detail/wallet_detail.dart'; | |||
import 'package:zhiying_base_widget/widgets/wallet/wallet_income/wallet_income.dart'; | |||
import 'package:zhiying_comm/util/defalut_widget_creater.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'widgets/goods_details/coupon/counpon_widget.dart'; | |||
import 'widgets/goods_details/evaluate/goods_details_evaluate_widget.dart'; | |||
import 'widgets/goods_details/title/goods_details_title_widget.dart'; | |||
import 'widgets/home/home_quick_entry/home_quick_entry.dart'; | |||
class BaseWidgetRegister { | |||
@@ -35,15 +50,17 @@ class BaseWidgetRegister { | |||
PageFactory.regist('index', (model) => MainPage(model)); | |||
PageFactory.regist('profile', (model) => MainPage(model)); | |||
PageFactory.regist('category', (model) => WalletPage()); | |||
PageFactory.regist('goods_details', (model) => GoodsDetailsPage(model)); | |||
// PageFactory.regist('login', (model) => LoginPage(model)); | |||
// PageFactory.regist('login_quick', (model) => LoginQuickPage(model)); | |||
// PageFactory.regist('login_account', (model) => LoginAccountPage(model)); | |||
// PageFactory.regist('login_invite', (model) => LoginInvitePage()); | |||
PageFactory.regist( | |||
'pub.flutter.profile_settings', (model) => MineDetailPage()); | |||
PageFactory.regist('pub.flutter.profile_settings', (model) => MineDetailPage()); | |||
PageFactory.regist('pub.flutter.settings', (model) => SettingPage(model)); | |||
PageFactory.regist('pub.flutter.my_orders', (model) => OrdersPage(model)); | |||
} | |||
// 注册控件 | |||
@@ -53,36 +70,56 @@ class BaseWidgetRegister { | |||
WidgetFactory.regist('normal_nav', NormalNavCreater()); | |||
// ==================== 首页 | |||
// WidgetFactory.regist('index_title', NormalNavCreater()); | |||
// WidgetFactory.regist( | |||
// 'index_search', DefaultWidgetCreater((model) => MineData())); | |||
// /// 可滚动banner | |||
// WidgetFactory.regist('index_title', NormalNavCreater()); | |||
/// 首页搜索栏 | |||
// WidgetFactory.regist('index_search', HomeSreachCreater()); | |||
// WidgetFactory.regist('index_search', DefaultWidgetCreater((model) => HomeSreachWidget(model))); | |||
/// 可滚动banner | |||
WidgetFactory.regist('index_carousel', HomeSlideBannerCreater()); | |||
WidgetFactory.regist('index_recommend_list', GoodsListCreater()); | |||
// /// 首页快速入口 | |||
WidgetFactory.regist( | |||
'multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model))); | |||
// | |||
// /// 不可以滚动banner | |||
/// 首页快速入口 | |||
WidgetFactory.regist('multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model))); | |||
/// 滚动公告 | |||
WidgetFactory.regist('index_placard', DefaultWidgetCreater((model) => HomeNoticeWidget(model))); | |||
/// 不可以滚动banner | |||
WidgetFactory.regist('index_banner_one', HomeBannerCreater()); | |||
WidgetFactory.regist('index_banner_two', HomeBannerCreater()); | |||
WidgetFactory.regist('index_taobao_auth_tip', HomeAuthCreater()); | |||
/// ==================== 商品详情 ==================== /// | |||
// 商品详情轮播图 | |||
WidgetFactory.regist('product_detail_carousel', DefaultWidgetCreater((model) => GoodsDetailsSlideBannerWidget(model))); | |||
// 商品详情下载APP提示 | |||
WidgetFactory.regist('product_detail_download_tips', DefaultWidgetCreater((model) => UpgradeTipWidget(model))); | |||
// 商品详情价格显示 | |||
WidgetFactory.regist('product_detail_price', DefaultWidgetCreater((model) => GoodsDetailsPriceWidget(model))); | |||
// 商品详情标题 | |||
WidgetFactory.regist('product_detail_title', DefaultWidgetCreater((model) => GoodsDetailsTitleWidget(model))); | |||
// 商品详情优惠劵 | |||
WidgetFactory.regist('product_detail_coupon', DefaultWidgetCreater((model) => CounponWidget(model))); | |||
// 商品详情店铺 | |||
WidgetFactory.regist('product_detail_shop', DefaultWidgetCreater((model) => StoreWidget(model))); | |||
// 商品详情宝贝评价 | |||
WidgetFactory.regist('product_detail_comment', DefaultWidgetCreater((model) => GoodsDetailsEvaluateWidget(model))); | |||
// 商品详情图片 | |||
// WidgetFactory.regist('product_detail_img_list', MineNavCreater()); | |||
// 商品详情底部推荐列表 | |||
// WidgetFactory.regist('product_detail_bottom_rec', DefaultWidgetCreater((model) => GoodsDetailsEvaluateWidget(model))); | |||
// 商品详情底部 | |||
WidgetFactory.regist('product_detail_bottom', DefaultWidgetCreater((model) => GoodsDetailsFooterWidget(model))); | |||
// ==================== 个人中心 | |||
WidgetFactory.regist('profile_appbar', MineNavCreater()); | |||
WidgetFactory.regist('profile_background', | |||
DefaultWidgetCreater((model) => MineNavBg(model))); | |||
WidgetFactory.regist( | |||
'profile_header', DefaultWidgetCreater((model) => MineHeader(model))); | |||
WidgetFactory.regist( | |||
'profile_earning', DefaultWidgetCreater((model) => MineData(model))); | |||
WidgetFactory.regist('profile_functions', | |||
DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||
WidgetFactory.regist('profile_my_functions', | |||
DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||
WidgetFactory.regist('profile_carousel', | |||
DefaultWidgetCreater((model) => HomeBannerWidget(model))); | |||
WidgetFactory.regist('profile_background', DefaultWidgetCreater((model) => MineNavBg(model))); | |||
WidgetFactory.regist('profile_header', DefaultWidgetCreater((model) => MineHeader(model))); | |||
WidgetFactory.regist('profile_earning', DefaultWidgetCreater((model) => MineData(model))); | |||
WidgetFactory.regist('profile_functions', DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||
WidgetFactory.regist('profile_my_functions', DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||
WidgetFactory.regist('profile_carousel', DefaultWidgetCreater((model) => HomeBannerWidget(model))); | |||
// ==================== 钱包 | |||
WidgetFactory.regist( | |||
@@ -90,8 +127,9 @@ class BaseWidgetRegister { | |||
// WidgetFactory.regist( | |||
// 'wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); | |||
WidgetFactory.regist('wallet_detail', HomeAuthCreater()); | |||
WidgetFactory.regist('wallet_data', DefaultWidgetCreater((model) => WalletData())); | |||
WidgetFactory.regist('wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); | |||
WidgetFactory.regist( | |||
'wallet_income', DefaultWidgetCreater((model) => WalletIncome())); | |||
WidgetFactory.regist('wallet_income', DefaultWidgetCreater((model) => WalletIncome())); | |||
} | |||
} |
@@ -0,0 +1,61 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// | |||
/// 优惠券说明 | |||
/// | |||
class CounponDescriptionWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const CounponDescriptionWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
margin: const EdgeInsets.symmetric(horizontal: 12.5), | |||
width: double.infinity, | |||
child:_getMainWidget(), | |||
); | |||
} | |||
/// 主widget | |||
Widget _getMainWidget() { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.start, | |||
children: <Widget>[ | |||
/// 领券立减 | |||
Padding(padding: const EdgeInsets.only(right: 5), child: _getButtom1Widget()), | |||
/// 收货后返现 | |||
Padding(padding: const EdgeInsets.only(right: 5), child: _getButtom2Widget()), | |||
], | |||
); | |||
} | |||
/// 领券立减 | |||
Widget _getButtom1Widget() { | |||
return Container( | |||
decoration: BoxDecoration( | |||
color: HexColor.fromHex('#FFE0E0'), | |||
borderRadius: BorderRadius.circular(50), | |||
), | |||
padding: const EdgeInsets.only(left: 14, right: 14, top: 3, bottom: 3), | |||
child: Text('领券立减100元', style: TextStyle(color: HexColor.fromHex('#FF4242'), fontSize: 11))); | |||
} | |||
/// 收货后返现 | |||
Widget _getButtom2Widget() { | |||
return Container( | |||
decoration: BoxDecoration( | |||
color: HexColor.fromHex('#FFEFDA'), | |||
borderRadius: BorderRadius.circular(50), | |||
), | |||
padding: const EdgeInsets.only(left: 14, right: 14, top: 3, bottom: 3), | |||
child: Text('收货后返现5.5元', style: TextStyle(color: HexColor.fromHex('#B78107'), fontSize: 11))); | |||
} | |||
} |
@@ -0,0 +1,3 @@ | |||
export 'counpon_bloc.dart'; | |||
export 'counpon_event.dart'; | |||
export 'counpon_state.dart'; |
@@ -0,0 +1,30 @@ | |||
import 'dart:async'; | |||
import 'dart:math'; | |||
import 'package:bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/bloc/counpon_repository.dart'; | |||
import 'bloc.dart'; | |||
class CounponBloc extends Bloc<CounponEvent, CounponState> { | |||
@override | |||
CounponState get initialState => CounponInitial(); | |||
CounponRepository repository; | |||
CounponBloc({this.repository}); | |||
@override | |||
Stream<CounponState> mapEventToState( | |||
CounponEvent event, | |||
) async* { | |||
if (event is CounponInitEvent) { | |||
yield* _mapInitEnvetTostate(event); | |||
} | |||
} | |||
/// 获取数据 | |||
Stream<CounponState> _mapInitEnvetTostate(CounponInitEvent event) async* { | |||
var result = await repository.fetchParentData(event); | |||
yield CounponLoadedState(model: result); | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
import 'package:equatable/equatable.dart'; | |||
abstract class CounponEvent extends Equatable { | |||
const CounponEvent(); | |||
} | |||
/// 初始化请求 | |||
class CounponInitEvent extends CounponEvent { | |||
final Map<String, dynamic> model; | |||
const CounponInitEvent({this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} |
@@ -0,0 +1,11 @@ | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/model/counpon_model.dart'; | |||
class CounponRepository { | |||
/// 获取父页面传进来的数据 | |||
Future<CounponModel> fetchParentData(CounponInitEvent event) async{ | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
import 'package:equatable/equatable.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/model/counpon_model.dart'; | |||
abstract class CounponState extends Equatable { | |||
const CounponState(); | |||
} | |||
class CounponInitial extends CounponState { | |||
@override | |||
List<Object> get props => []; | |||
} | |||
class CounponLoadedState extends CounponState { | |||
CounponModel model; | |||
CounponLoadedState({this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} | |||
class CounponErrorState extends CounponState { | |||
@override | |||
List<Object> get props => []; | |||
} |
@@ -0,0 +1,26 @@ | |||
import 'package:shimmer/shimmer.dart'; | |||
import 'package:flutter/material.dart'; | |||
class CounponSkeleton extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
margin: const EdgeInsets.only(left: 12.5, right: 12.5), | |||
width: double.infinity, | |||
height: 70, | |||
child: _shimmerWidget(width: double.infinity, height: 65, radius: 7.5), | |||
); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} |
@@ -0,0 +1,104 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/bloc/counpon_repository.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/counpon_sk.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/model/counpon_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||
/// | |||
/// 优惠券widget | |||
/// | |||
class CounponWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const CounponWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container(); | |||
// return BlocProvider<CounponBloc>( | |||
// create: (_) => CounponBloc(repository: CounponRepository())..add(CounponInitEvent(model: model)), | |||
// child: CounponContainer(), | |||
// ); | |||
} | |||
} | |||
class CounponContainer extends StatefulWidget { | |||
@override | |||
_CounponContainerState createState() => _CounponContainerState(); | |||
} | |||
class _CounponContainerState extends State<CounponContainer> { | |||
/// 点击领取 | |||
void _onJump(CounponModel model) {} | |||
@override | |||
Widget build(BuildContext context) { | |||
BlocConsumer<CounponBloc, CounponState>( | |||
listener: (context, state) {}, | |||
buildWhen: (prev, current) { | |||
if (current is CounponErrorState) { | |||
return false; | |||
} | |||
return true; | |||
}, | |||
builder: (context, state) { | |||
if (state is CounponLoadedState) { | |||
// return _getMainWdiget(state.model); | |||
} | |||
// return CounponSkeleton(); | |||
return Container(); | |||
}, | |||
); | |||
} | |||
/// 主视图 | |||
Widget _getMainWdiget(CounponModel model) { | |||
return GestureDetector( | |||
onTap: () => _onJump(model), | |||
behavior: HitTestBehavior.opaque, | |||
child: Container( | |||
width: double.infinity, | |||
margin: const EdgeInsets.only(left: 12.5, right: 12.5), | |||
padding: const EdgeInsets.only(left: 18.5), | |||
alignment: Alignment.centerLeft, | |||
child: Row( | |||
children: <Widget>[ | |||
/// 价格 | |||
_getPriceWidget(model), | |||
const SizedBox(width: 7.5), | |||
/// 有效期 | |||
_getTimeWidget(model) | |||
], | |||
), | |||
), | |||
); | |||
} | |||
/// 价格 | |||
Widget _getPriceWidget(CounponModel model) { | |||
return Row( | |||
children: <Widget>[ | |||
/// 价格类型 | |||
Text('¥', style: TextStyle(fontSize: 15, color: HexColor.fromHex('#FFFFFF'))), | |||
/// 价格 | |||
Text('100', style: TextStyle(fontSize: 30, color: HexColor.fromHex('#FFFFFF'))), | |||
], | |||
); | |||
} | |||
/// 名称与有效期 | |||
Widget _getTimeWidget(CounponModel model) { | |||
return Column( | |||
children: <Widget>[ | |||
/// 标题 | |||
Text('优惠券', style: TextStyle(fontSize: 17, color: HexColor.fromHex('#FFFFFF'))), | |||
/// 到期时间 | |||
Text('有效期至2020-10-01', style: TextStyle(fontSize: 10, color: HexColor.fromHex('#FFFFFF'))) | |||
], | |||
); | |||
} | |||
} |
@@ -0,0 +1,2 @@ | |||
class CounponModel{} |
@@ -0,0 +1,27 @@ | |||
import 'package:shimmer/shimmer.dart'; | |||
import 'package:flutter/material.dart'; | |||
/// | |||
/// 商品详情评论骨架屏幕 | |||
/// | |||
class GoodsDetailsEvaluateSkeleton extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container(); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} | |||
@@ -0,0 +1,38 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// | |||
/// 商品详情评价Widget | |||
/// | |||
class GoodsDetailsEvaluateWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsEvaluateWidget(this.model); | |||
/// 点击查看更多 | |||
void _openLookMore() {} | |||
@override | |||
Widget build(BuildContext context) { | |||
return GestureDetector( | |||
onTap: () => _openLookMore(), | |||
behavior: HitTestBehavior.opaque, | |||
child: Container( | |||
width: double.infinity, | |||
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 12.5, right: 12.5), | |||
child: getMainWidget(), | |||
), | |||
); | |||
} | |||
/// 评价以及查看更多 | |||
Widget getMainWidget() { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
Text('宝贝评价', style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 12)), | |||
Text('查看更多 >', style: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 11)), | |||
], | |||
); | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
import 'package:shimmer/shimmer.dart'; | |||
import 'package:flutter/material.dart'; | |||
class GoodsDetailsFooterSkeleton extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
width: double.infinity, | |||
padding: const EdgeInsets.only(left: 21, right: 12.5, top: 12.5, bottom: 12.5), | |||
child: Row( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
Row( | |||
children: <Widget>[ | |||
_shimmerWidget(width: 30, height: 30,), | |||
const SizedBox(width: 35), | |||
_shimmerWidget(width: 30, height: 30,), | |||
], | |||
), | |||
_shimmerWidget( height: 44, width: 230, radius: 22), | |||
], | |||
), | |||
); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} |
@@ -0,0 +1,169 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// | |||
/// 商品详情底部Widget | |||
/// | |||
class GoodsDetailsFooterWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsFooterWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return GooddsDetailsFooterContainer(); | |||
} | |||
} | |||
class GooddsDetailsFooterContainer extends StatefulWidget { | |||
@override | |||
_GooddsDetailsFooterContainerState createState() => _GooddsDetailsFooterContainerState(); | |||
} | |||
class _GooddsDetailsFooterContainerState extends State<GooddsDetailsFooterContainer> { | |||
/// 打开首页 | |||
void _openHome() {} | |||
/// 收藏 | |||
void _collectOnClick() {} | |||
/// 分享 | |||
void _shareOnClick() {} | |||
/// 自购省 | |||
void _savemoneyOnClick() {} | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
height: 70, | |||
width: double.infinity, | |||
padding: const EdgeInsets.only(bottom: 10, top: 12.5, left: 21, right: 12.5), | |||
decoration: BoxDecoration( | |||
boxShadow:[ | |||
BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0), blurRadius: 5.0, spreadRadius: 2.0), | |||
BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0)), | |||
], | |||
color: Colors.white | |||
), | |||
child: _getMainWidet(), | |||
); | |||
} | |||
/// 主Widget | |||
Widget _getMainWidet() { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
crossAxisAlignment: CrossAxisAlignment.center, | |||
children: <Widget>[ | |||
/// 首页与收藏 | |||
_getLeftWidget(), | |||
/// 分享赚与自购省 | |||
_getRightWidget(), | |||
], | |||
); | |||
} | |||
/// 首页 和 收藏 | |||
Widget _getLeftWidget() { | |||
return Row( | |||
crossAxisAlignment: CrossAxisAlignment.center, | |||
mainAxisAlignment: MainAxisAlignment.start, | |||
children: <Widget>[ | |||
GestureDetector( | |||
behavior: HitTestBehavior.opaque, | |||
onTap: () => _openHome(), | |||
child: Padding( | |||
padding: const EdgeInsets.only(right: 35), | |||
child: _getCustomWidget('首页', '999999', null), | |||
)), | |||
GestureDetector( | |||
behavior: HitTestBehavior.opaque, | |||
onTap: () => _collectOnClick(), | |||
child: Padding(padding: const EdgeInsets.only(right: 0), child: _getCustomWidget('收藏', '999999', null))) | |||
], | |||
); | |||
} | |||
/// 分享赚与自购省 | |||
Widget _getRightWidget() { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.end, | |||
crossAxisAlignment: CrossAxisAlignment.center, | |||
children: <Widget>[_getFxzButton(), _getZgsButton()], | |||
); | |||
} | |||
/// 分享赚, | |||
Widget _getFxzButton() { | |||
return GestureDetector( | |||
onTap: () => _shareOnClick(), | |||
child: Container( | |||
alignment: Alignment.center, | |||
padding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), | |||
decoration: BoxDecoration( | |||
gradient: LinearGradient(colors: [HexColor.fromHex('#FFCA66'), HexColor.fromHex('#FFD961')], begin: Alignment.centerLeft, end: Alignment.centerRight), | |||
borderRadius: BorderRadius.only( | |||
bottomLeft: Radius.circular(25), | |||
topLeft: Radius.circular(25) | |||
) | |||
), | |||
child: Column( | |||
children: <Widget>[ | |||
RichText( | |||
text: TextSpan(text: '¥', style: TextStyle(fontSize: 12, color: HexColor.fromHex('FFFFFF')), children: [ | |||
TextSpan(text: '3.10', style: TextStyle(fontSize: 15, color: HexColor.fromHex('#FFFFFF'))), | |||
]), | |||
), | |||
Text('分享赚', style: TextStyle(color: HexColor.fromHex('#FFFFFF'), fontSize: 15)) | |||
], | |||
), | |||
), | |||
); | |||
} | |||
/// 自购省 | |||
Widget _getZgsButton() { | |||
return GestureDetector( | |||
behavior: HitTestBehavior.opaque, | |||
onTap: () => _savemoneyOnClick(), | |||
child: Container( | |||
alignment: Alignment.center, | |||
padding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), | |||
decoration: BoxDecoration( | |||
gradient: LinearGradient(colors: [HexColor.fromHex('#FF6969'), HexColor.fromHex('#FF4646')], begin: Alignment.centerLeft, end: Alignment.centerRight), | |||
borderRadius: BorderRadius.only( | |||
bottomRight: Radius.circular(25), | |||
topRight: Radius.circular(25) | |||
) | |||
), | |||
child: Column( | |||
children: <Widget>[ | |||
RichText( | |||
text: TextSpan(text: '¥', style: TextStyle(fontSize: 12, color: HexColor.fromHex('FFFFFF')), children: [ | |||
TextSpan(text: '23.10', style: TextStyle(fontSize: 15, color: HexColor.fromHex('#FFFFFF'))), | |||
]), | |||
), | |||
Text('自购省', style: TextStyle(color: HexColor.fromHex('#FFFFFF'), fontSize: 15)) | |||
], | |||
), | |||
), | |||
); | |||
} | |||
Widget _getCustomWidget(String text, String textColor, String icon) { | |||
return Column( | |||
crossAxisAlignment: CrossAxisAlignment.center, | |||
mainAxisAlignment: MainAxisAlignment.end, | |||
children: <Widget>[ | |||
/// 图标 | |||
Container(height: 25, width: 25, color: Colors.red, margin: const EdgeInsets.only(bottom: 3)), | |||
/// 图片 | |||
Text(text, style: TextStyle(color: HexColor.fromHex(textColor), fontSize: 11)) | |||
], | |||
); | |||
} | |||
} |
@@ -0,0 +1,83 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// | |||
/// 商品详情价格widget | |||
/// | |||
class GoodsDetailsPriceWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsPriceWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container(margin: const EdgeInsets.symmetric(horizontal: 12.5), child: _getMainWidget()); | |||
} | |||
/// 主体视图 | |||
Widget _getMainWidget() { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
_getLeftWidget(), | |||
/// 右边widget | |||
_getBuyNumberWidget(), | |||
], | |||
); | |||
} | |||
/// 左边的wiget 包括价格等 | |||
Widget _getLeftWidget() { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.start, | |||
crossAxisAlignment: CrossAxisAlignment.center, | |||
children: <Widget>[ | |||
/// 价格 | |||
_getPriceWidget(), | |||
const SizedBox(width: 5), | |||
/// 券后 | |||
_getQhPriceWidget(), | |||
const SizedBox(width: 5), | |||
/// 积分 | |||
_getPointsWidget() | |||
], | |||
); | |||
} | |||
/// 价格 | |||
Widget _getPriceWidget() { | |||
return Row( | |||
children: <Widget>[ | |||
Text('¥', style: TextStyle(color: HexColor.fromHex('#FF4242'), fontSize: 15)), | |||
Text('99', style: TextStyle(color: HexColor.fromHex('#FF4242'), fontSize: 30)), | |||
], | |||
); | |||
} | |||
/// 积分 | |||
Widget _getPointsWidget() { | |||
return Container( | |||
decoration: BoxDecoration(color: HexColor.fromHex('#FFEFDA'), borderRadius: BorderRadius.circular(5)), | |||
padding: const EdgeInsets.only(left: 4, right: 7.5, top: 4, bottom: 4), | |||
child: Text('', style: TextStyle(color: HexColor.fromHex('#B78107'), fontSize: 9)), | |||
); | |||
} | |||
/// 券后价格 | |||
Widget _getQhPriceWidget() { | |||
return Column( | |||
children: <Widget>[ | |||
Text('券后', style: TextStyle(color: HexColor.fromHex('#FF4242'), fontSize: 11)), | |||
Text('¥ 199', style: TextStyle(color: HexColor.fromHex('#FF4242'), fontSize: 10)), | |||
], | |||
); | |||
} | |||
/// 购买人数 | |||
Widget _getBuyNumberWidget() { | |||
return Text('99999人已购买', style: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 12.5)); | |||
} | |||
} |
@@ -0,0 +1,46 @@ | |||
import 'dart:async'; | |||
import 'dart:math'; | |||
import 'package:bloc/bloc.dart'; | |||
import 'package:equatable/equatable.dart'; | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/bloc/goods_details_slide_banner_repository.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/model/goods_details_silde_banner_model.dart'; | |||
import 'package:zhiying_comm/util/empty_util.dart'; | |||
part 'goods_details_slide_banner_event.dart'; | |||
part 'goods_details_slide_banner_state.dart'; | |||
class GoodsDetailsSlideBannerBloc extends Bloc<GoodsDetailsSlideBannerEvent, GoodsDetailsSlideBannerState> { | |||
GoodsDetailsSlideBannerRepository repository; | |||
GoodsDetailsSlideBannerBloc({@required this.repository}); | |||
@override | |||
GoodsDetailsSlideBannerState get initialState => GoodsDetailsSlideBannerInitial(); | |||
@override | |||
Stream<GoodsDetailsSlideBannerState> mapEventToState( | |||
GoodsDetailsSlideBannerEvent event, | |||
) async* { | |||
/// 初始化 | |||
if (event is GoodsDetailsSlideBannerInitEvent) { | |||
yield* _mapInitEventToState(event); | |||
} | |||
} | |||
/// 初始化 | |||
Stream<GoodsDetailsSlideBannerState> _mapInitEventToState(GoodsDetailsSlideBannerInitEvent event) async* { | |||
var parentData = await repository.fetchParentData(event.model); | |||
if (!EmptyUtil.isEmpty(parentData)) { | |||
yield GoodsDetailsSlideBannerLoadedState(model: parentData); | |||
return; | |||
} | |||
var netData = await repository.fetchNetData(event.model); | |||
if (!EmptyUtil.isEmpty(netData)) | |||
yield GoodsDetailsSlideBannerLoadedState(model: parentData); | |||
else | |||
yield GoodsDetailsSlideBannerErrorState(); | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
part of 'goods_details_slide_banner_bloc.dart'; | |||
abstract class GoodsDetailsSlideBannerEvent extends Equatable { | |||
const GoodsDetailsSlideBannerEvent(); | |||
} | |||
/// 初始化事件 | |||
class GoodsDetailsSlideBannerInitEvent extends GoodsDetailsSlideBannerEvent { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsSlideBannerInitEvent({@required this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} |
@@ -0,0 +1,21 @@ | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/model/goods_details_silde_banner_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class GoodsDetailsSlideBannerRepository { | |||
/// 加载父页面数据 | |||
Future<GoodsDetailsSlideBannerModel> fetchParentData(final Map<String, dynamic> model) async { | |||
if (!EmptyUtil.isEmpty(model)) { | |||
try { | |||
return GoodsDetailsSlideBannerModel.fromJson(model['data']); | |||
} catch (e) { | |||
Logger.log(e); | |||
} | |||
} | |||
return null; | |||
} | |||
/// 加载网络数据 | |||
Future<GoodsDetailsSlideBannerModel> fetchNetData(final Map<String, dynamic> model) async { | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
part of 'goods_details_slide_banner_bloc.dart'; | |||
abstract class GoodsDetailsSlideBannerState extends Equatable { | |||
const GoodsDetailsSlideBannerState(); | |||
} | |||
class GoodsDetailsSlideBannerInitial extends GoodsDetailsSlideBannerState { | |||
@override | |||
List<Object> get props => []; | |||
} | |||
/// 数据加载成功 | |||
class GoodsDetailsSlideBannerLoadedState extends GoodsDetailsSlideBannerState { | |||
GoodsDetailsSlideBannerModel model; | |||
GoodsDetailsSlideBannerLoadedState({this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} | |||
/// 数据加载失败 | |||
class GoodsDetailsSlideBannerErrorState extends GoodsDetailsSlideBannerState { | |||
@override | |||
List<Object> get props => []; | |||
} |
@@ -0,0 +1,19 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_sk.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_widget.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// | |||
/// 可以滚动Banner | |||
/// | |||
class HomeSlideBannerCreater extends WidgetCreater { | |||
@override | |||
List<Widget> createSkeleton(Map<String, dynamic> model) { | |||
return [GoodsDetailsSlideBannerSkeleton()]; | |||
} | |||
@override | |||
List<Widget> createWidgets(Map<String, dynamic> model) { | |||
return [GoodsDetailsSlideBannerWidget(model)]; | |||
} | |||
} |
@@ -0,0 +1,21 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:shimmer/shimmer.dart'; | |||
class GoodsDetailsSlideBannerSkeleton extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return _shimmerWidget(width: double.infinity, height: 375); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} |
@@ -0,0 +1,172 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||
import 'package:flutter_swiper/flutter_swiper.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/bloc/goods_details_slide_banner_bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/bloc/goods_details_slide_banner_repository.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_sk.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/model/goods_details_silde_banner_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:cached_network_image/cached_network_image.dart'; | |||
/// | |||
/// 商品详情轮播图 | |||
/// | |||
class GoodsDetailsSlideBannerWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsSlideBannerWidget(this.model, {Key key}) : super(key: key); | |||
@override | |||
Widget build(BuildContext context) { | |||
return BlocProvider<GoodsDetailsSlideBannerBloc>( | |||
create: (_) => GoodsDetailsSlideBannerBloc(repository: GoodsDetailsSlideBannerRepository())..add(GoodsDetailsSlideBannerInitEvent(model: model)), | |||
child: GoodsDetailsSlideBannerContainer(model), | |||
); | |||
} | |||
} | |||
class GoodsDetailsSlideBannerContainer extends StatefulWidget { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsSlideBannerContainer(this.model, {Key key}) : super(key: key); | |||
@override | |||
_GoodsDetailsSlideBannerContainerState createState() => _GoodsDetailsSlideBannerContainerState(); | |||
} | |||
class _GoodsDetailsSlideBannerContainerState extends State<GoodsDetailsSlideBannerContainer> { | |||
/// 子元素点击事件 | |||
void _itemOnClick(IndexCarousel model) { | |||
print('点击了 $model'); | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
return BlocConsumer<GoodsDetailsSlideBannerBloc, GoodsDetailsSlideBannerState>( | |||
listener: (BuildContext context, GoodsDetailsSlideBannerState state) { | |||
if (state is GoodsDetailsSlideBannerErrorState) { | |||
print('数据加载出错'); | |||
} | |||
}, | |||
buildWhen: (previous, current) { | |||
/// 数据加载出错不进行build | |||
if (current is GoodsDetailsSlideBannerErrorState) { | |||
return false; | |||
} | |||
return true; | |||
}, | |||
builder: (context, state) { | |||
print('currente state = $state'); | |||
if (state is GoodsDetailsSlideBannerLoadedState) { | |||
if (!EmptyUtil.isEmpty(state.model) && !EmptyUtil.isEmpty(state.model.index_carousel_list)) { | |||
return _getMainWidget(state.model); | |||
} | |||
} | |||
// 骨架屏 | |||
return GoodsDetailsSlideBannerSkeleton(); | |||
}, | |||
); | |||
} | |||
/// 页面 | |||
Widget _getMainWidget(GoodsDetailsSlideBannerModel datas) { | |||
return Container( | |||
width: double.infinity, | |||
height: 375, | |||
child: Swiper( | |||
itemBuilder: (BuildContext context, int index) { | |||
IndexCarousel items = datas.index_carousel_list[index]; | |||
return Container( | |||
width: double.infinity, | |||
child: CachedNetworkImage(imageUrl: items?.img ?? '', fit: BoxFit.cover), | |||
); | |||
}, | |||
itemCount: datas?.index_carousel_list?.length ?? 0, | |||
loop: true, | |||
autoplay: true, | |||
onTap: (index) => _itemOnClick(datas.index_carousel_list[index]), | |||
pagination: _getSwiperStyleByType(datas, datas?.index_carousel_list?.length ?? 0), | |||
), | |||
); | |||
} | |||
/// 获取进度样式 | |||
SwiperPlugin _getSwiperStyleByType(GoodsDetailsSlideBannerModel model, int pageCount) { | |||
if ('1' != model.pagination_open) { | |||
return null; | |||
} | |||
if ('type_number' == model.pagination) { | |||
return _getNumswiperPlugin(pageCount, model.pagination_select_color, model.pagination_unselect_color); | |||
} | |||
if ('type_point' == model.pagination) { | |||
return _swiperCustomPaginationDito(pageCount, model.pagination_select_color, model.pagination_unselect_color); | |||
} | |||
if ('type_bar' == model.pagination) { | |||
return _swiperCustomPagination(pageCount, model.pagination_select_color, model.pagination_unselect_color); | |||
} | |||
return null; | |||
} | |||
/// 数字样式 | |||
SwiperPlugin _getNumswiperPlugin(int pageCount, String selectColor, String unselectColor) { | |||
return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) { | |||
return Align( | |||
alignment: Alignment(0.0, 0.9), | |||
child: Container( | |||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 18), | |||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(13), color: HexColor.fromHex('#4D000000')), | |||
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,61 @@ | |||
class GoodsDetailsSlideBannerModel { | |||
String pagination; | |||
String pagination_open; | |||
List<String> pagination_options; | |||
List<IndexCarousel> index_carousel_list; | |||
String pagination_select_color; | |||
String pagination_unselect_color; | |||
GoodsDetailsSlideBannerModel({this.pagination, this.pagination_open, this.pagination_options, this.pagination_select_color, this.pagination_unselect_color, this.index_carousel_list}); | |||
factory GoodsDetailsSlideBannerModel.fromJson(Map<String, dynamic> json) { | |||
return GoodsDetailsSlideBannerModel( | |||
pagination: json['pagination'], | |||
pagination_open: json['pagination_open'], | |||
pagination_options: json['pagination_options'] != null ? new List<String>.from(json['pagination_options']) : null, | |||
index_carousel_list: json['index_carousel_list'] != null ? (json['index_carousel_list'] as List).map((i) => IndexCarousel.fromJson(i)).toList() : null, | |||
pagination_select_color: json['pagination_select_color'], | |||
pagination_unselect_color: json['pagination_unselect_color'], | |||
); | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['pagination'] = this.pagination; | |||
data['pagination_open'] = this.pagination_open; | |||
data['pagination_select_color'] = this.pagination_select_color; | |||
data['pagination_unselect_color'] = this.pagination_unselect_color; | |||
if (this.pagination_options != null) { | |||
data['pagination_options'] = this.pagination_options; | |||
} | |||
if (this.index_carousel_list != null) { | |||
data['index_carousel_list'] = this.index_carousel_list.map((v) => v.toJson()).toList(); | |||
} | |||
return data; | |||
} | |||
} | |||
class IndexCarousel { | |||
String img; | |||
String skip_identifier; | |||
IndexCarousel({this.img, this.skip_identifier}); | |||
factory IndexCarousel.fromJson(Map<String, dynamic> json) { | |||
return IndexCarousel( | |||
img: json['img'], | |||
skip_identifier: json['skip_identifier'], | |||
); | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['img'] = this.img; | |||
data['skip_identifier'] = this.skip_identifier; | |||
return data; | |||
} | |||
} |
@@ -0,0 +1,4 @@ | |||
export 'store_bloc.dart'; | |||
export 'store_event.dart'; | |||
export 'store_state.dart'; |
@@ -0,0 +1,43 @@ | |||
import 'dart:async'; | |||
import 'package:bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/bloc/store_repository.dart'; | |||
import 'package:zhiying_comm/util/empty_util.dart' | |||
''; | |||
import 'bloc.dart'; | |||
class StoreBloc extends Bloc<StoreEvent, StoreState> { | |||
StoreRepository repository; | |||
StoreBloc({this.repository}); | |||
@override | |||
StoreState get initialState => StoreInitial(); | |||
@override | |||
Stream<StoreState> mapEventToState( | |||
StoreEvent event, | |||
) async* { | |||
/// 初始化 | |||
if(event is StoreInitEvent){ | |||
yield* _mapInitEventToState(event); | |||
} | |||
} | |||
/// 获取数据 | |||
Stream<StoreState> _mapInitEventToState(StoreInitEvent event) async*{ | |||
var result = await repository.fetchParentData(event); | |||
if(!EmptyUtil.isEmpty(result)){ | |||
yield StoreLoadedState(model: result); | |||
return; | |||
} | |||
var net = await repository.fetchNetData(event); | |||
if(!EmptyUtil.isEmpty(net)) | |||
yield StoreLoadedState(model: result); | |||
else | |||
yield StoreErrorState(); | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
import 'package:equatable/equatable.dart'; | |||
abstract class StoreEvent extends Equatable { | |||
const StoreEvent(); | |||
} | |||
/// 初始化事件 | |||
class StoreInitEvent extends StoreEvent { | |||
@override | |||
List<Object> get props => []; | |||
} |
@@ -0,0 +1,10 @@ | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/model/store_model.dart'; | |||
class StoreRepository { | |||
/// 获取上级数据 | |||
Future<StoreModel> fetchParentData(StoreInitEvent event) async {} | |||
/// 网络数据 | |||
Future<StoreModel> fetchNetData(StoreInitEvent event) async {} | |||
} |
@@ -0,0 +1,27 @@ | |||
import 'package:equatable/equatable.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/model/store_model.dart'; | |||
abstract class StoreState extends Equatable { | |||
const StoreState(); | |||
} | |||
class StoreInitial extends StoreState { | |||
@override | |||
List<Object> get props => []; | |||
} | |||
/// 数据加载完毕 | |||
class StoreLoadedState extends StoreState { | |||
final StoreModel model; | |||
const StoreLoadedState({this.model}); | |||
@override | |||
List<Object> get props => []; | |||
} | |||
/// 数据加载出错 | |||
class StoreErrorState extends StoreState { | |||
@override | |||
List<Object> get props => []; | |||
} |
@@ -0,0 +1,3 @@ | |||
class StoreModel{} |
@@ -0,0 +1,44 @@ | |||
import 'package:shimmer/shimmer.dart'; | |||
import 'package:flutter/material.dart'; | |||
class StoreSkeleton extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
height: 50, | |||
width: double.infinity, | |||
child: Row( | |||
mainAxisAlignment: MainAxisAlignment.start, | |||
children: <Widget>[ | |||
/// 图片 | |||
_shimmerWidget(width: 50, height: 50), | |||
/// | |||
Column( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
_shimmerWidget(width: 150, height: 20), | |||
_shimmerWidget(width: 50, height: 15) | |||
], | |||
), | |||
], | |||
), | |||
); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} |
@@ -0,0 +1,147 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/bloc/store_repository.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/store/model/store_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||
import 'store_sk.dart'; | |||
/// | |||
/// 商家widget | |||
/// | |||
class StoreWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const StoreWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return BlocProvider<StoreBloc>( | |||
create: (_) => StoreBloc(repository: StoreRepository())..add(StoreInitEvent()), | |||
child: StoreContainer(), | |||
); | |||
} | |||
} | |||
class StoreContainer extends StatefulWidget { | |||
@override | |||
_StoreContainerState createState() => _StoreContainerState(); | |||
} | |||
class _StoreContainerState extends State<StoreContainer> { | |||
/// 点击更多 | |||
void _onMoreClick(){ | |||
} | |||
/// 点击商家 | |||
void _onStoreClick(){ | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
return BlocConsumer<StoreBloc, StoreState>( | |||
listener: (context, state) {}, | |||
buildWhen: (prev, current) { | |||
if (current is StoreErrorState) { | |||
return false; | |||
} | |||
return true; | |||
}, | |||
builder: (context, state) { | |||
if (state is StoreLoadedState) { | |||
return _getMianWidget(state.model); | |||
} | |||
return StoreSkeleton(); | |||
}, | |||
); | |||
} | |||
/// 主视图 | |||
Widget _getMianWidget(StoreModel model) { | |||
return Container( | |||
margin: const EdgeInsets.only(left: 12.5, right: 12.5), | |||
child: Row( | |||
children: <Widget>[ | |||
/// 商家图片 | |||
_getStoreImgWidget(model), | |||
Expanded( | |||
child: Column( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
/// 商店名称与更多 | |||
_getStoreNameWidget(model), | |||
/// 评分描述 | |||
_getEvaluateWidget(model), | |||
], | |||
), | |||
), | |||
], | |||
), | |||
); | |||
} | |||
/// 商家图片 | |||
Widget _getStoreImgWidget(StoreModel model) { | |||
return Container( | |||
width: 50, | |||
height: 50, | |||
color: Colors.red, | |||
); | |||
} | |||
/// 商店名称 | |||
Widget _getStoreNameWidget(StoreModel model) { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
/// 商店名称 | |||
Text( | |||
'品胜京东自营旗舰店', | |||
style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 13), | |||
), | |||
/// 更多 | |||
Text( | |||
'更多店铺优惠 >', | |||
style: TextStyle(color: HexColor.fromHex('#FF4242'), fontSize: 11), | |||
), | |||
], | |||
); | |||
} | |||
/// 评分描述 | |||
Widget _getEvaluateWidget(StoreModel model) { | |||
return Row( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
/// 宝贝描述 5.0 | |||
_getCoustomWidet('宝贝描述 5.0', '#999999', ''), | |||
/// 物流服务 5.0 | |||
_getCoustomWidet('宝贝描述 5.0', '#999999', ''), | |||
/// 服务态度 1.0 | |||
_getCoustomWidet('宝贝描述 5.0', '#999999', ''), | |||
], | |||
); | |||
} | |||
Widget _getCoustomWidet(String text, String textColor, String icon) { | |||
return Row( | |||
children: <Widget>[ | |||
Text(text, style: TextStyle(fontSize: 11, color: HexColor.fromHex(textColor))), | |||
Container( | |||
width: 12, | |||
height: 12, | |||
color: Colors.red, | |||
), | |||
], | |||
); | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// | |||
/// 商品详情标题 | |||
/// | |||
class GoodsDetailsTitleWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const GoodsDetailsTitleWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
width: double.infinity, | |||
margin: const EdgeInsets.only(left: 12.5, right: 12.5), | |||
child: _getMaiWidget(), | |||
); | |||
} | |||
/// 主widget | |||
Widget _getMaiWidget() { | |||
return RichText( | |||
maxLines: 2, | |||
overflow: TextOverflow.ellipsis, | |||
text: TextSpan(children: [ | |||
WidgetSpan( | |||
child: _getGoodsTypeIcon(), | |||
), | |||
_getGoodsTitle(), | |||
]), | |||
); | |||
} | |||
/// 商品类型图标 | |||
Widget _getGoodsTypeIcon() { | |||
return Container( | |||
height: 15, | |||
width: 32, | |||
color: Colors.red, | |||
); | |||
} | |||
/// 商品标题 | |||
InlineSpan _getGoodsTitle() { | |||
return TextSpan(text: '品胜(PISEN)苹果数据线1.5米 适用于苹果手机所有机型 MFI认证安全稳定一年换新1.5米2米', style: TextStyle(fontSize: 14, color: HexColor.fromHex('#FF333333'))); | |||
} | |||
} |
@@ -0,0 +1,3 @@ | |||
class UpgradeTipModel{} | |||
@@ -0,0 +1,27 @@ | |||
import 'package:shimmer/shimmer.dart'; | |||
import 'package:flutter/material.dart'; | |||
class UpgradeTipSkeleton extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
margin: const EdgeInsets.symmetric(horizontal: 12.5), | |||
height: 35, | |||
child: _shimmerWidget(width: double.infinity, height: double.infinity, radius: 20), | |||
); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} | |||
@@ -0,0 +1,57 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/widgets/goods_details/upgrade_tip/model/upgrade_tip_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// | |||
/// 更新提示widget | |||
/// | |||
class UpgradeTipWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const UpgradeTipWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
decoration: BoxDecoration( | |||
color: HexColor.fromHex('#FFEFDA'), | |||
borderRadius: BorderRadius.circular(30), | |||
), | |||
padding: const EdgeInsets.only(left: 10, right: 13, top: 10, bottom: 10), | |||
margin: const EdgeInsets.symmetric(horizontal: 12.5), | |||
child: Row( | |||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
children: <Widget>[ | |||
_geLeftWidget(null), | |||
_getRightWidget(null), | |||
], | |||
), | |||
); | |||
} | |||
/// 左边的视图 | |||
Widget _geLeftWidget(UpgradeTipModel model) { | |||
return Row( | |||
children: <Widget>[ | |||
/// 图标 | |||
Container(width: 15, height: 15, color: Colors.red), | |||
const SizedBox(width: 7.5), | |||
/// 文字 | |||
Text('下载APP升级运营商,享受更多收益', style: TextStyle(color: HexColor.fromHex('#C09023'), fontSize: 11)) | |||
], | |||
); | |||
} | |||
/// 右边的视图 | |||
Widget _getRightWidget(UpgradeTipModel model) { | |||
return Row( | |||
children: <Widget>[ | |||
Text('前往下载', style: TextStyle(color: HexColor.fromHex('#C09023'), fontSize: 11)), | |||
const SizedBox(width: 4), | |||
Text('》', style: TextStyle(color: HexColor.fromHex('#C09023'), fontSize: 11)) | |||
], | |||
); | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
import 'package:flutter/material.dart'; | |||
class HomeAiDialog extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container(); | |||
} | |||
} |
@@ -45,6 +45,7 @@ class _HomeBannerContainerState extends State<HomeBannerContainer> { | |||
/// 点击事件 | |||
void _itemOnClick(HomeBannerListItemModel model){ | |||
print('${model?.skip_identifier}'); | |||
RouterUtil.route(model.toJson(), context); | |||
} | |||
@override | |||
@@ -0,0 +1,3 @@ | |||
export 'home_notice_bloc.dart'; | |||
export 'home_notice_event.dart'; | |||
export 'home_notice_state.dart'; |
@@ -0,0 +1,32 @@ | |||
import 'dart:async'; | |||
import 'package:bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/bloc/home_notice_repository.dart'; | |||
import 'package:zhiying_comm/util/empty_util.dart'; | |||
import 'bloc.dart'; | |||
class HomeNoticeBloc extends Bloc<HomeNoticeEvent, HomeNoticeState> { | |||
HomeNoticeRepository repository; | |||
HomeNoticeBloc({this.repository}); | |||
@override | |||
HomeNoticeState get initialState => HomeNoticeInitial(); | |||
@override | |||
Stream<HomeNoticeState> mapEventToState( | |||
HomeNoticeEvent event, | |||
) async* { | |||
if(event is HomeNoticeInitEvent){ | |||
yield* _mapInitEventToState(event); | |||
} | |||
} | |||
/// 初始化 | |||
Stream<HomeNoticeState> _mapInitEventToState(HomeNoticeInitEvent event) async* { | |||
var parentData = await repository.fetchParentData(event); | |||
if(!EmptyUtil.isEmpty(parentData)) | |||
yield HomeNoticeLoadedState(model: parentData); | |||
else | |||
yield HomeNoticeErrorState(); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
import 'package:equatable/equatable.dart'; | |||
import 'bloc.dart'; | |||
abstract class HomeNoticeEvent extends Equatable { | |||
const HomeNoticeEvent(); | |||
@override | |||
List<Object> get props => []; | |||
} | |||
/// 初始化事件 | |||
class HomeNoticeInitEvent extends HomeNoticeEvent{ | |||
final Map<String, dynamic> model; | |||
const HomeNoticeInitEvent({this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} |
@@ -0,0 +1,18 @@ | |||
import 'dart:convert'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/model/home_notice_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class HomeNoticeRepository { | |||
/// 获取父页面的数据 | |||
Future<HomeNoticeModel> fetchParentData(HomeNoticeInitEvent event) async { | |||
try { | |||
String jsonStr = event.model['data']; | |||
return HomeNoticeModel.fromJson(jsonDecode(jsonStr)); | |||
} catch (e) { | |||
Logger.log(e); | |||
} | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
import 'package:equatable/equatable.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/model/home_notice_model.dart'; | |||
import 'bloc.dart'; | |||
abstract class HomeNoticeState extends Equatable { | |||
const HomeNoticeState(); | |||
@override | |||
List<Object> get props => []; | |||
} | |||
/// 初始化事件 | |||
class HomeNoticeInitial extends HomeNoticeState { | |||
@override | |||
List<Object> get props => []; | |||
} | |||
/// 数据加载完毕 | |||
class HomeNoticeLoadedState extends HomeNoticeState { | |||
final HomeNoticeModel model; | |||
const HomeNoticeLoadedState({this.model}); | |||
@override | |||
List<Object> get props => [this.model]; | |||
} | |||
/// 数据加载出错 | |||
class HomeNoticeErrorState extends HomeNoticeState{ | |||
} |
@@ -0,0 +1,28 @@ | |||
import 'package:shimmer/shimmer.dart'; | |||
import 'package:flutter/material.dart'; | |||
/// | |||
/// 公告的骨架屏 | |||
/// | |||
class HomeNoticeSkeleton extends StatelessWidget { | |||
final Map<String, dynamic> map; | |||
const HomeNoticeSkeleton({this.map}); | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container(padding: const EdgeInsets.symmetric(horizontal: 12.5), child: _shimmerWidget(width: double.infinity, height: 30, radius: 8)); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} |
@@ -0,0 +1,203 @@ | |||
import 'dart:async'; | |||
import 'package:flutter/material.dart'; | |||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/bloc/home_notice_repository.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/home_notice_sk.dart'; | |||
import 'package:cached_network_image/cached_network_image.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_notice/model/home_notice_model.dart'; | |||
import 'bloc/bloc.dart'; | |||
/// | |||
/// 公告滚动widget | |||
/// | |||
class HomeNoticeWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const HomeNoticeWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return BlocProvider<HomeNoticeBloc>( | |||
create: (_) => HomeNoticeBloc(repository: HomeNoticeRepository())..add(HomeNoticeInitEvent(model: model)), | |||
child: HomeNoticeWidgetContianer(), | |||
); | |||
} | |||
} | |||
class HomeNoticeWidgetContianer extends StatefulWidget { | |||
@override | |||
_HomeNoticeWidgetContianerState createState() => _HomeNoticeWidgetContianerState(); | |||
} | |||
class _HomeNoticeWidgetContianerState extends State<HomeNoticeWidgetContianer> { | |||
/// 子item点击事件 | |||
void _itemOnClick(HomeNoticeModel model) { | |||
if(pageIndex == model.notices.length){ | |||
pageIndex = 0; | |||
} | |||
print('===== $pageIndex'); | |||
HomeNoticeNoticesModel item = model.notices[pageIndex]; | |||
_itemJump(item); | |||
} | |||
/// 子item跳转 | |||
void _itemJump(HomeNoticeNoticesModel model){ | |||
print('${model?.skip_identifier}'); | |||
RouterUtil.route(model.toJson(), context); | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
return BlocConsumer<HomeNoticeBloc, HomeNoticeState>( | |||
listener: (context, state) {}, | |||
buildWhen: (prev, current) { | |||
return true; | |||
}, | |||
builder: (context, state) { | |||
if (state is HomeNoticeLoadedState) { | |||
return _getMainWidget(state?.model); | |||
} | |||
return HomeNoticeSkeleton(); | |||
}, | |||
); | |||
} | |||
/// 主体页面 | |||
Widget _getMainWidget(HomeNoticeModel model) { | |||
return Container( | |||
width: double.infinity, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.only(bottomLeft: Radius.circular(7.5), bottomRight: Radius.circular(7.5))), | |||
padding: const EdgeInsets.only(bottom: 7.5), | |||
child: Container( | |||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(7.5), color: HexColor.fromHex(model?.bg_color)), | |||
// color: Colors.cyan), | |||
margin: const EdgeInsets.only(left: 12.5, right: 12.5), | |||
padding: const EdgeInsets.only(top: 8, bottom: 8, left: 12, right: 8), | |||
// height: 30, | |||
width: double.infinity, | |||
child: _getChildWidget(model), | |||
), | |||
); | |||
} | |||
var pageIndex = 0; | |||
Widget _getChildWidget(HomeNoticeModel model) { | |||
return GestureDetector( | |||
onTap: () => _itemOnClick(model), | |||
behavior: HitTestBehavior.opaque, | |||
child: Row( | |||
children: <Widget>[ | |||
/// 图片 | |||
// Container(width: 52, height: 13, color: Colors.red), | |||
CachedNetworkImage( | |||
imageUrl: model?.logo_img ?? '', | |||
width: 52, | |||
), | |||
const SizedBox(width: 14), | |||
/// 文字 | |||
Expanded( | |||
child: Container( | |||
width: double.infinity, | |||
height: 15, | |||
alignment: Alignment.centerLeft, | |||
// color: Colors.yellowAccent, | |||
child: MarqueeWidget( | |||
model?.notices?.length ?? 0, | |||
(BuildContext context, int index) { | |||
HomeNoticeNoticesModel item = model.notices[index]; | |||
return Align(alignment: Alignment.centerLeft, child: Text('${item?.notice_text}' , style: TextStyle(color: HexColor.fromHex(model?.text_color), fontSize: 12))); | |||
}, | |||
onPageChanged: (index) => pageIndex = index, | |||
), | |||
), | |||
), | |||
const SizedBox(width: 14), | |||
/// 图片 | |||
CachedNetworkImage(imageUrl: model?.jump_img ?? '', height: 18), | |||
// Container( | |||
// width: 18, | |||
// height: 18, | |||
// color: Colors.red, | |||
// ), | |||
], | |||
), | |||
); | |||
} | |||
} | |||
// 上下滚动的消息轮播 | |||
class MarqueeWidget extends StatefulWidget { | |||
int count; // 子视图数量 | |||
IndexedWidgetBuilder itemBuilder; // 子视图构造器 | |||
final ValueChanged<int> onPageChanged; | |||
MarqueeWidget(this.count, this.itemBuilder, {this.onPageChanged}); | |||
@override | |||
_MarqueeWidgetState createState() => _MarqueeWidgetState(); | |||
} | |||
class _MarqueeWidgetState extends State<MarqueeWidget> { | |||
PageController _controller; | |||
Timer _timer; | |||
@override | |||
void initState() { | |||
super.initState(); | |||
if (widget.count > 1) { | |||
_controller = PageController(); | |||
_timer = Timer.periodic(Duration(seconds: 5), (timer) { | |||
// 如果当前位于最后一页,则直接跳转到第一页,两者内容相同,跳转时视觉上无感知 | |||
if (_controller.page.round() >= widget.count) { | |||
_controller.jumpToPage(0); | |||
} | |||
_controller.nextPage(duration: Duration(seconds: 1), curve: Curves.linear); | |||
}); | |||
} | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
// return PageView.builder( | |||
// scrollDirection: Axis.vertical, | |||
// controller: _controller, | |||
// itemBuilder: (buildContext, index) { | |||
// if (index < widget.count) { | |||
// return widget.itemBuilder(buildContext, index); | |||
// } else { | |||
// return widget.itemBuilder(buildContext, 0); | |||
// } | |||
// }, | |||
// itemCount: widget.count + 1, // 在原数据末尾添加一笔数据(即第一笔数据),用于实现无限循环滚动效果 | |||
// ); | |||
// } | |||
return PageView.custom( | |||
physics: NeverScrollableScrollPhysics(), | |||
childrenDelegate: SliverChildBuilderDelegate((context, index) { | |||
if (index < widget.count) { | |||
return widget.itemBuilder(context, index); | |||
} else { | |||
return widget.itemBuilder(context, 0); | |||
} | |||
}, childCount: widget.count + 1), | |||
scrollDirection: Axis.vertical, | |||
controller: _controller, | |||
onPageChanged: widget?.onPageChanged, | |||
); | |||
} | |||
@override | |||
void dispose() { | |||
super.dispose(); | |||
_controller?.dispose(); | |||
_timer?.cancel(); | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
class HomeNoticeModel { | |||
String logo_img; | |||
String jump_img; | |||
String bg_color; | |||
String text_color; | |||
String duration_time; | |||
List<HomeNoticeNoticesModel> notices; | |||
HomeNoticeModel({this.notices, this.logo_img, this.jump_img, this.bg_color, this.text_color, this.duration_time}); | |||
factory HomeNoticeModel.fromJson(Map<String, dynamic> json) { | |||
return HomeNoticeModel( | |||
logo_img: json['logo_img']?.toString(), | |||
jump_img: json['jump_img']?.toString(), | |||
bg_color: json['bg_color']?.toString(), | |||
text_color: json['text_color']?.toString(), | |||
duration_time: json['duration_time']?.toString(), | |||
notices: json['notices'] != null ? (json['notices'] as List).map((i) => HomeNoticeNoticesModel.fromJson(i)).toList() : null, | |||
); | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['duration_time'] = this.duration_time; | |||
data['text_color'] = this.text_color; | |||
data['bg_color'] = this.bg_color; | |||
data['jump_img'] = this.jump_img; | |||
data['logo_img'] = this.logo_img; | |||
if (this.notices != null) { | |||
data['notices'] = this.notices.map((v) => v.toJson()).toList(); | |||
} | |||
return data; | |||
} | |||
} | |||
class HomeNoticeNoticesModel { | |||
String notice_text; | |||
String skip_identifier; | |||
HomeNoticeNoticesModel({this.notice_text, this.skip_identifier}); | |||
factory HomeNoticeNoticesModel.fromJson(Map<String, dynamic> json) { | |||
return HomeNoticeNoticesModel( | |||
notice_text: json['notice_text']?.toString(), | |||
skip_identifier: json['skip_identifier']?.toString(), | |||
); | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['img'] = this.notice_text; | |||
data['skip_identifier'] = this.skip_identifier; | |||
return data; | |||
} | |||
} |
@@ -32,8 +32,9 @@ class HomeQuickEntryContianer extends StatefulWidget { | |||
class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||
/// Icon点击事件 | |||
void _itemIconClick(TypeNormal item){ | |||
print("item type = ${item.skip_identifier}"); | |||
void _itemIconClick(TypeNormal model){ | |||
print("item type = ${model.skip_identifier}"); | |||
RouterUtil.route(model.toJson(), context); | |||
} | |||
@override | |||
@@ -250,6 +251,7 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||
SwiperPagination _swiperPaginationDot(HomeQuickEntryModel model){ | |||
return SwiperPagination(margin: const EdgeInsets.only(), builder: DotSwiperPaginationBuilder( color: HexColor.fromHex(model?.pagination_unselect_color), activeColor: HexColor.fromHex(model?.pagination_select_color), size: 8, activeSize: 8)); | |||
} | |||
// 自定义进度条 条形 | |||
SwiperPlugin _swiperCustomPagination(int pageCount) { | |||
List list = []; | |||
@@ -9,8 +9,7 @@ import 'package:zhiying_comm/util/empty_util.dart'; | |||
import './bloc.dart'; | |||
class HomeSlideBannerBloc | |||
extends Bloc<HomeSlideBannerEvent, HomeSlideBannerState> { | |||
class HomeSlideBannerBloc extends Bloc<HomeSlideBannerEvent, HomeSlideBannerState> { | |||
HomeSlideBannerRepository repository; | |||
HomeSlideBannerBloc({@required this.repository}); | |||
@@ -19,8 +18,7 @@ class HomeSlideBannerBloc | |||
HomeSlideBannerState get initialState => InitialHomeSlideBannerState(); | |||
@override | |||
Stream<HomeSlideBannerState> mapEventToState( | |||
HomeSlideBannerEvent event) async* { | |||
Stream<HomeSlideBannerState> mapEventToState(HomeSlideBannerEvent event) async* { | |||
final currentState = state; | |||
/// 初始化 | |||
@@ -31,11 +29,14 @@ class HomeSlideBannerBloc | |||
} | |||
/// 初始化 | |||
Stream<HomeSlideBannerState> _mapInitEventToState( | |||
HomeBannerInitEvent event) async* { | |||
Stream<HomeSlideBannerState> _mapInitEventToState(HomeBannerInitEvent 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 HomeSlideBannerCachedState(datas: cached); | |||
if (!EmptyUtil.isEmpty(cached)) yield HomeSlideBannerCachedState(datas: cached); | |||
var param = await repository.fetchData(id: event.model['mod_id']); | |||
if (!EmptyUtil.isEmpty(param)) | |||
yield HomeSlideBannerLoadedState(datas: param); | |||
@@ -1,3 +1,5 @@ | |||
import 'dart:convert'; | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_slide_banner/model/home_slide_banner_model.dart'; | |||
import 'package:zhiying_comm/util/empty_util.dart'; | |||
@@ -6,33 +8,42 @@ import 'package:zhiying_comm/util/net_util.dart'; | |||
class HomeSlideBannerRepository { | |||
/// 获取缓存数据 | |||
Future<List<HomeSlideBannerModelItems>> fetchCachedDate({@required int id}) async { | |||
Future<HomeSlideBannerModel> fetchCachedDate({@required int id}) async { | |||
var cached = await NetUtil.getRequestCachedData('/api/v1/mod', params: { | |||
'ids': [id] | |||
}); | |||
if (!EmptyUtil.isEmpty(cached)) { | |||
HomeSlideBannerModel model = HomeSlideBannerModel.fromJson(cached); | |||
if (null != model && !EmptyUtil.isEmpty(model.items)) { | |||
return model.items; | |||
try { | |||
return HomeSlideBannerModel.fromJson(cached); | |||
}catch(e){ | |||
} | |||
} | |||
return null; | |||
} | |||
/// 获取父页面传进来的数据 | |||
Future<HomeSlideBannerModel> fetchPreantData(@required Map<String, dynamic> model) async{ | |||
try{ | |||
if(!EmptyUtil.isEmpty(model)){ | |||
return HomeSlideBannerModel.fromJson(jsonDecode(model['data'])); | |||
} | |||
}catch(e){ | |||
} | |||
return null; | |||
} | |||
/// 获取数据 | |||
Future<List<HomeSlideBannerModelItems>> fetchData({@required int id}) async { | |||
Future<HomeSlideBannerModel> 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])) { | |||
HomeSlideBannerModel model = HomeSlideBannerModel.fromJson(params[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); | |||
if (null != model && !EmptyUtil.isEmpty(model.items)) { | |||
return model.items; | |||
try{ | |||
return HomeSlideBannerModel.fromJson(params[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); | |||
}catch(e){ | |||
} | |||
} | |||
return null; | |||
@@ -16,7 +16,7 @@ class InitialHomeSlideBannerState extends HomeSlideBannerState { | |||
/// 缓存数据 | |||
class HomeSlideBannerCachedState extends HomeSlideBannerState { | |||
List<HomeSlideBannerModelItems> datas; | |||
HomeSlideBannerModel datas; | |||
HomeSlideBannerCachedState({this.datas}); | |||
@@ -26,12 +26,11 @@ class HomeSlideBannerCachedState extends HomeSlideBannerState { | |||
/// 数据加载完毕状态 | |||
class HomeSlideBannerLoadedState extends HomeSlideBannerState { | |||
List<HomeSlideBannerModelItems> datas; | |||
HomeSlideBannerModel datas; | |||
HomeSlideBannerLoadedState({this.datas}); | |||
HomeSlideBannerLoadedState copyWith( | |||
{List<HomeSlideBannerModelItems> newData}) { | |||
HomeSlideBannerLoadedState copyWith({HomeSlideBannerModel newData}) { | |||
return HomeSlideBannerLoadedState( | |||
datas: newData ?? datas, | |||
); | |||
@@ -2,6 +2,7 @@ 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/goods_details_page/goods_details_page.dart'; | |||
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; | |||
import 'package:cached_network_image/cached_network_image.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
@@ -39,9 +40,14 @@ class HomeSlideBannerContainer extends StatefulWidget { | |||
} | |||
class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> { | |||
/// 子元素点击事件 | |||
void _itemOnClick(HomeSlideBannerModelItems items) { | |||
print('点击了 $items'); | |||
void _itemOnClick(IndexCarousel model) { | |||
print('点击了 $model'); | |||
// RouterUtil.route(model.toJson(), context); | |||
Navigator.push(context, MaterialPageRoute( | |||
builder: (_) => PageFactory.create('goods_details', null) | |||
)); | |||
} | |||
@override | |||
@@ -73,26 +79,26 @@ class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> { | |||
); | |||
} | |||
Widget _getMainWidget(List<HomeSlideBannerModelItems> datas) { | |||
Widget _getMainWidget(HomeSlideBannerModel datas) { | |||
return Container( | |||
width: double.infinity, | |||
height: 140, | |||
child: Swiper( | |||
itemBuilder: (BuildContext context, int index) { | |||
HomeSlideBannerModelItems items = datas[index]; | |||
IndexCarousel items = datas.index_carousel_list[index]; | |||
return Container( | |||
// color: Colors.primaries[index % Colors.primaries.length], | |||
width: double.infinity, | |||
child: CachedNetworkImage( | |||
imageUrl: items?.img?? '', | |||
imageUrl: items?.img ?? '', | |||
fit: BoxFit.cover, | |||
), | |||
); | |||
}, | |||
itemCount: datas?.length ?? 0, | |||
itemCount: datas?.index_carousel_list?.length ?? 0, | |||
loop: true, | |||
onTap: (index) => _itemOnClick(datas[index]), | |||
pagination: _SwiperCustomPagination(datas?.length ?? 0), | |||
autoplay: true, | |||
onTap: (index) => _itemOnClick(datas.index_carousel_list[index]), | |||
pagination: _getSwiperStyleByType(datas, datas?.index_carousel_list?.length ?? 0), | |||
onIndexChanged: (index) { | |||
print('切换下一页'); | |||
Provider.of<MainPageBgNotifier>(context, listen: false).switchBg(Container( | |||
@@ -105,8 +111,45 @@ class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> { | |||
); | |||
} | |||
/// 获取进度样式 | |||
SwiperPlugin _getSwiperStyleByType(HomeSlideBannerModel model, int pageCount) { | |||
if('1' != model.pagination_open){ | |||
return null; | |||
} | |||
if ('type_number' == model.pagination) { | |||
return _getNumswiperPlugin(pageCount, model.pagination_select_color, model.pagination_unselect_color); | |||
} | |||
if ('type_point' == model.pagination) { | |||
return _swiperCustomPaginationDito(pageCount, model.pagination_select_color, model.pagination_unselect_color); | |||
} | |||
if ('type_bar' == model.pagination) { | |||
return _swiperCustomPagination(pageCount, model.pagination_select_color, model.pagination_unselect_color); | |||
} | |||
return null; | |||
} | |||
/// 数字样式 | |||
SwiperPlugin _getNumswiperPlugin(int pageCount, String selectColor, String unselectColor) { | |||
return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) { | |||
return Align( | |||
alignment: Alignment(0.0, 0.9), | |||
child: Container( | |||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 18), | |||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(13), color: HexColor.fromHex('#4D000000')), | |||
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) { | |||
SwiperPlugin _swiperCustomPagination(int pageCount, String selectColor, String unselectColor) { | |||
List list = []; | |||
for (int i = 0; i < pageCount; i++) { | |||
list.add(i); | |||
@@ -134,11 +177,16 @@ class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> { | |||
return Container( | |||
height: 4, | |||
width: 25, | |||
decoration: BoxDecoration(borderRadius: borderRadius, color: index == config.activeIndex ? HexColor.fromHex('#FF4242') : HexColor.fromHex('#FFFFFF')), | |||
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)); | |||
} | |||
} |
@@ -1,115 +1,58 @@ | |||
class HomeSlideBannerModel { | |||
List<HomeSlideBannerModelItems> items; | |||
List<IndexCarousel> index_carousel_list; | |||
String pagination; | |||
String pagination_open; | |||
List<String> pagination_options; | |||
String pagination_select_color; | |||
String pagination_unselect_color; | |||
HomeSlideBannerModel({this.items}); | |||
HomeSlideBannerModel({this.index_carousel_list, this.pagination, this.pagination_open, this.pagination_options, this.pagination_select_color, this.pagination_unselect_color}); | |||
HomeSlideBannerModel.fromJson(Map<String, dynamic> json) { | |||
if (json['6'] != null) { | |||
items = new List<HomeSlideBannerModelItems>(); | |||
json['6'].forEach((v) { | |||
items.add(new HomeSlideBannerModelItems.fromJson(v)); | |||
}); | |||
factory HomeSlideBannerModel.fromJson(Map<String, dynamic> json) { | |||
return HomeSlideBannerModel( | |||
index_carousel_list: json['index_carousel_list'] != null ? (json['index_carousel_list'] as List).map((i) => IndexCarousel.fromJson(i)).toList() : null, | |||
pagination: json['pagination'], | |||
pagination_open: json['pagination_open'], | |||
pagination_options: json['pagination_options'] != null ? new List<String>.from(json['pagination_options']) : null, | |||
pagination_select_color: json['pagination_select_color'], | |||
pagination_unselect_color: json['pagination_unselect_color'], | |||
); | |||
} | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
if (this.items != null) { | |||
data['6'] = this.items.map((v) => v.toJson()).toList(); | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['pagination'] = this.pagination; | |||
data['pagination_open'] = this.pagination_open; | |||
data['pagination_select_color'] = this.pagination_select_color; | |||
data['pagination_unselect_color'] = this.pagination_unselect_color; | |||
if (this.index_carousel_list != null) { | |||
data['index_carousel_list'] = this.index_carousel_list.map((v) => v.toJson()).toList(); | |||
} | |||
if (this.pagination_options != null) { | |||
data['pagination_options'] = this.pagination_options; | |||
} | |||
return data; | |||
} | |||
return data; | |||
} | |||
} | |||
class HomeSlideBannerModelItems { | |||
String modId; | |||
String modPid; | |||
String modName; | |||
String position; | |||
String title; | |||
String subtitle; | |||
String url; | |||
String margin; | |||
String aspectRatio; | |||
String icon; | |||
String img; | |||
String fontColor; | |||
String bgImg; | |||
String bgColor; | |||
String bgColorT; | |||
String badge; | |||
String path; | |||
String data; | |||
String sort; | |||
String isGlobal; | |||
class IndexCarousel { | |||
String img; | |||
String skip_identifier; | |||
HomeSlideBannerModelItems( | |||
{this.modId, | |||
this.modPid, | |||
this.modName, | |||
this.position, | |||
this.title, | |||
this.subtitle, | |||
this.url, | |||
this.margin, | |||
this.aspectRatio, | |||
this.icon, | |||
this.img, | |||
this.fontColor, | |||
this.bgImg, | |||
this.bgColor, | |||
this.bgColorT, | |||
this.badge, | |||
this.path, | |||
this.data, | |||
this.sort, | |||
this.isGlobal}); | |||
IndexCarousel({this.img, this.skip_identifier}); | |||
HomeSlideBannerModelItems.fromJson(Map<String, dynamic> json) { | |||
modId = json['mod_id']?.toString(); | |||
modPid = json['mod_pid']?.toString(); | |||
modName = json['mod_name']?.toString(); | |||
position = json['position']?.toString(); | |||
title = json['title']?.toString(); | |||
subtitle = json['subtitle']?.toString(); | |||
url = json['url']?.toString(); | |||
margin = json['margin']?.toString(); | |||
aspectRatio = json['aspect_ratio']?.toString(); | |||
icon = json['icon']?.toString(); | |||
img = json['img']?.toString(); | |||
fontColor = json['font_color']?.toString(); | |||
bgImg = json['bg_img']?.toString(); | |||
bgColor = json['bg_color']?.toString(); | |||
bgColorT = json['bg_color_t']?.toString(); | |||
badge = json['badge']?.toString(); | |||
path = json['path']?.toString(); | |||
data = json['data']?.toString(); | |||
sort = json['sort']?.toString(); | |||
isGlobal = json['is_global']?.toString(); | |||
} | |||
factory IndexCarousel.fromJson(Map<String, dynamic> json) { | |||
return IndexCarousel( | |||
img: json['img'], | |||
skip_identifier: json['skip_identifier'], | |||
); | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['mod_id'] = this.modId; | |||
data['mod_pid'] = this.modPid; | |||
data['mod_name'] = this.modName; | |||
data['position'] = this.position; | |||
data['title'] = this.title; | |||
data['subtitle'] = this.subtitle; | |||
data['url'] = this.url; | |||
data['margin'] = this.margin; | |||
data['aspect_ratio'] = this.aspectRatio; | |||
data['icon'] = this.icon; | |||
data['img'] = this.img; | |||
data['font_color'] = this.fontColor; | |||
data['bg_img'] = this.bgImg; | |||
data['bg_color'] = this.bgColor; | |||
data['bg_color_t'] = this.bgColorT; | |||
data['badge'] = this.badge; | |||
data['path'] = this.path; | |||
data['data'] = this.data; | |||
data['sort'] = this.sort; | |||
data['is_global'] = this.isGlobal; | |||
return data; | |||
} | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['img'] = this.img; | |||
data['skip_identifier'] = this.skip_identifier; | |||
return data; | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/widgets/home/home_sreach/home_sreach_widget.dart'; | |||
import 'package:zhiying_base_widget/widgets/others/normal_nav/normal_nav.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class HomeSreachCreater extends WidgetCreater { | |||
@override | |||
List<Widget> createWidgets(Map<String, dynamic> model) { | |||
return [ | |||
SliverPersistentHeader( | |||
pinned: false, | |||
floating: false, | |||
delegate: HomeSreachDeleagater(), | |||
), | |||
]; | |||
} | |||
@override | |||
bool isSliverChild() { | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,21 @@ | |||
import 'package:shimmer/shimmer.dart'; | |||
import 'package:flutter/material.dart'; | |||
class HomeSreachSkeleton extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container(); | |||
} | |||
Widget _shimmerWidget({double width, double height, double radius = 0}) { | |||
return Shimmer.fromColors( | |||
baseColor: Colors.grey[300], | |||
highlightColor: Colors.grey[100], | |||
child: Container( | |||
width: width, | |||
height: height, | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(radius)), | |||
), | |||
); | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:flutter/material.dart'; | |||
import 'dart:ui'; | |||
class HomeSreachDeleagater extends SliverPersistentHeaderDelegate{ | |||
double _height; | |||
HomeSreachDeleagater() : super() { | |||
_height = MediaQueryData.fromWindow(window).padding.top + 44; | |||
} | |||
@override | |||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { | |||
print('${shrinkOffset.toString()}'); | |||
double percent = shrinkOffset / _height; | |||
print('${percent.toString()}'); | |||
return HomeSreachWidget(null); | |||
} | |||
@override | |||
double get maxExtent => _height; | |||
@override | |||
double get minExtent => _height; | |||
@override | |||
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) { | |||
return false; | |||
} | |||
} | |||
/// | |||
/// 首页搜索框 | |||
/// | |||
class HomeSreachWidget extends StatelessWidget { | |||
final Map<String, dynamic> model; | |||
const HomeSreachWidget(this.model); | |||
@override | |||
Widget build(BuildContext context) { | |||
return HomeSreachContainer(); | |||
} | |||
} | |||
class HomeSreachContainer extends StatefulWidget { | |||
@override | |||
_HomeSreachContainerState createState() => _HomeSreachContainerState(); | |||
} | |||
class _HomeSreachContainerState extends State<HomeSreachContainer> { | |||
@override | |||
Widget build(BuildContext context) { | |||
return _getMainWidget(); | |||
} | |||
/// 主视图 | |||
Widget _getMainWidget() { | |||
return Container( | |||
color: Colors.transparent, | |||
height: 30, | |||
width: double.infinity, | |||
margin: EdgeInsets.only(left: 12.5, right: 12.5, bottom: 10, top: MediaQueryData.fromWindow(window).padding.top + 10), | |||
child: Row( | |||
children: <Widget>[ | |||
/// 搜索框 | |||
Expanded( | |||
child: _getSreachWidget(), | |||
), | |||
const SizedBox(width: 10), | |||
/// 消息 | |||
_getMessageWidget(), | |||
], | |||
), | |||
); | |||
} | |||
/// 搜索栏 | |||
Widget _getSreachWidget() { | |||
return Container( | |||
height: 30, | |||
width: double.infinity, | |||
child: TextField( | |||
autofocus: false, | |||
style: TextStyle(color: HexColor.fromHex('#FFFFFF'), fontSize: 14), | |||
readOnly: true, | |||
decoration: InputDecoration( | |||
hintText: '输入搜索内容,领券省钱', | |||
hintStyle: TextStyle( | |||
color: Colors.white, | |||
fontSize: 14, | |||
), | |||
contentPadding: EdgeInsets.zero, | |||
prefixIcon: Icon( | |||
Icons.search, | |||
color: Colors.white, | |||
), | |||
filled: true, | |||
fillColor: Color(0x50cccccc), | |||
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Color(0x00000000)), borderRadius: BorderRadius.all(Radius.circular(30))), | |||
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Color(0x00000000)), borderRadius: BorderRadius.all(Radius.circular(30))), | |||
), | |||
), | |||
); | |||
} | |||
/// 消息widget | |||
Widget _getMessageWidget() { | |||
return Container( | |||
width: 30, | |||
height: 30, | |||
color: Colors.red, | |||
); | |||
} | |||
} |