import 'package:cs_resources/generated/assets.dart'; import 'package:cs_resources/theme/app_colors_theme.dart'; import 'package:flutter/material.dart'; import 'package:cs_resources/constants/color_constants.dart'; import 'my_load_image.dart'; import 'my_text_view.dart'; ///四种视图状态 enum LoadState { State_Success, State_Error, State_Loading, State_Empty } ///根据不同状态来展示不同的视图 class LoadStateLayout extends StatefulWidget { final LoadState state; //页面状态 final Widget? successWidget; //成功视图 final List? successSliverWidget; //成功的滚动视图(Sliver的布局) final VoidCallback? errorRetry; //错误事件处理 final Color? themeColor; String? errorMessage; LoadStateLayout({ Key? key, this.state = LoadState.State_Loading, //默认为加载状态 this.successWidget, //成功的布局 (二选一) this.successSliverWidget, //成功的滚动布局(二选一) this.errorMessage, //错误的信息展示 this.errorRetry, //错误重试的事件 this.themeColor, //主题颜色,Loading,文本颜色 }) : super(key: key); @override _LoadStateLayoutState createState() => _LoadStateLayoutState(); } class _LoadStateLayoutState extends State { @override Widget build(BuildContext context) { if (widget.successSliverWidget != null) { //如果有 successSliverWidget 就使用 Slivers 的方式布局 return CustomScrollView( slivers: _buildSlivers(), ); } else { //如果没有有 successSliverWidget 就使用默认布局的方式布局 return SizedBox( width: double.infinity, height: double.infinity, child: _buildWidget(context), ); } } //Slivers的布局 List _buildSlivers() { return _buildListWidget(context); } ///根据不同状态来显示不同的视图 (默认布局) Widget _buildWidget(BuildContext context) { switch (widget.state) { case LoadState.State_Success: return widget.successWidget ?? const SizedBox(); case LoadState.State_Error: return _errorView(context); case LoadState.State_Loading: return _loadingView(context); case LoadState.State_Empty: return _emptyView(context); default: return _loadingView(context); } } ///根据不同状态来显示不同的视图 (CustomScrollView) List _buildListWidget(BuildContext context) { switch (widget.state) { case LoadState.State_Success: return widget.successSliverWidget != null ? widget.successSliverWidget! : widget.successWidget != null ? [widget.successWidget!] : [const SizedBox()]; case LoadState.State_Error: return [widget.successSliverWidget != null ? _warpStateLayout(_errorView(context)) : _errorView(context)]; case LoadState.State_Loading: return [widget.successSliverWidget != null ? _warpStateLayout(_loadingView(context)) : _loadingView(context)]; case LoadState.State_Empty: return [widget.successSliverWidget != null ? _warpStateLayout(_emptyView(context)) : _emptyView(context)]; default: return [widget.successSliverWidget != null ? _warpStateLayout(_loadingView(context)) : _loadingView(context)]; } } //如果父布局是 CustomScrollView 则使用 SliverFillViewport 包裹状态布局 Widget _warpStateLayout(Widget widget) { return SliverFillViewport( delegate: SliverChildBuilderDelegate( (context, index) { return widget; }, childCount: 1, ), ); } // ===================================== 真正的状态布局 ↓ ===================================== ///加载中视图 Widget _loadingView(BuildContext context) { return Container( width: double.infinity, height: double.infinity, alignment: Alignment.center, child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ CircularProgressIndicator( strokeWidth: 3, valueColor: AlwaysStoppedAnimation(widget.themeColor ?? context.appColors.textDarkGray), ), MyTextView( 'Loading...', marginTop: 15, fontSize: 14, textColor: widget.themeColor ?? context.appColors.textDarkGray, ) ], ), ); } ///错误视图 Widget _errorView(BuildContext context) { return Container( width: double.infinity, height: double.infinity, alignment: Alignment.center, padding: const EdgeInsets.only(bottom: 10), child: GestureDetector( onTap: widget.errorRetry, child: Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ const MyAssetImage(Assets.baseServicePageLoadError, width: 141, height: 117.5, fit: BoxFit.contain), MyTextView( widget.errorMessage ?? 'Data loading failed! Please refresh and try again', marginTop: 18, fontSize: 14, textColor: widget.themeColor ?? context.appColors.textDarkGray, ), ], ))); } ///数据为空的视图 Widget _emptyView(BuildContext context) { return Container( width: double.infinity, height: double.infinity, alignment: Alignment.center, padding: const EdgeInsets.only(bottom: 10), child: Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ const MyAssetImage(Assets.baseServicePageNoData, width: 123.5, height: 115.5, fit: BoxFit.contain), MyTextView( 'There is currently no content available', marginTop: 18, fontSize: 14, textColor: widget.themeColor ?? context.appColors.textDarkGray, ), ], ), ); } }