目录总结前沿页面通用Loading组件是一个App必不可少的基础功能,之前只开发过Android原生的页面Loading,这次就按原生的逻辑再开发一个Flutter的Widget,对其进行封装复用我们...
目录
总结前沿
页面通用Loading组件是一个App必不可少的基础功能,之前只开发过android原生的页面Loading,这次就按原生的逻辑再开发一个Flutter的Widget,对其进行封装复用
我们先看下效果:
原理
状态
一个通用的页面加载Loading组件应该具备以下几种状态:
IDLE%20初始化
Idle状态,此时的组件还只是初始化
LOADING%20加载中
Loading状态,一般在网络请求或者耗时加载数据时调用,通用显示的是一个progress或者自定义的帧动画
LOADING_SUCCESS
LoadingSuccess加载成功,一般在网络请求成功后调用,并将需要展示的页面展示出来
LOADING_SUCCESS_BUT_EMPTY
页面加载成功但是没有数据,这种情况一般是发起列表数据请求但是没有数据,通常我们会展示一个空数据的页面来提醒用户
NETWORK_blockED
网络错误,一般是由于网络异常、网络请求连接超时导致。此时我们需要展示一个网络错误的页面,并且带有重试按钮,让用户重新发起请求
ERROR
通常是接口错误,这种情况下我们会根据接口返回的错误码或者错误文本提示用户,并且也有重试按钮
///%20状态枚举
enum%20LoadingStatus%20{
%20%20idle,%20//%20初始化
%20%20loading,%20//%20加载中
%20%20loading_suc,%20//%20加载成功
%20%20loading_suc_but_empty,%20//%20加载成功但是数据为空
%20%20network_blocked,%20//%20网络加载错误
%20%20error,%20//%20加载错误
}
复制代码
点击事件回调
当网络异常或者接口报错时,会显示错误页面,并且提供重试按钮,让用户点击重新请求。基于这个需求,我们还需要提供点击重试后的事件回调让业务可以处理重新请求。
%20///%20定义点击事件 %20typedef%20OnTapCallback%20=%20Function(LoadingView%20widget); 复制代码
提示文案
提供提示文案的自定义,方便业务根据自己的需求展示特定的提示文案
代码实现
根据上面的原理来实现对应的代码
构造方法%20///%20构造方法
%20LoadingView({
%20%20%20%20Key%20key,
%20%20%20%20@required%20this.child,%20//%20需要加载的Widget
%20%20%20%20@required%20this.todoAfterError,%20//%20错误点击重试
%20%20%20%20@required%20this.todoAfterNetworkBlocked,%20//%20网络错误点击重试
%20%20%20%20this.networkBlockedDesc%20=%20"网络连接超时,请检查你的网络环境",
%20%20%20%20this.errorDesc%20=%20"加载失败",
%20%20%20%20this.loadingStatus%20=%20LoadingStatus.idle,
%20})%20:%20super(key:%20key);
复制代码
根据不同的Loading状态展示对应的Widget其中idle、success状态直接展示需要加载的Widget(这里也可以使用渐变动画进行切换过度)
%20///根据不同状态展示不同Widget
%20%20Widget%20_buildBody()%20{
%20%20%20%20switch%20(widget.loadingStatus)%20{
%20%20%20%20%20%20case%20LoadingStatus.idle:
%20%20%20%20%20%20%20%20return%20widget.child;
%20%20%20%20%20%20case%20LoadingStatus.loading:
%20%20%20%20%20%20%20%20return%20_buildLoadingView();
%20%20%20%20%20%20case%20LoadingStatus.loading_suc:
%20%20%20%20%20%20%20%20return%20widget.child;
%20%20%20%20%20%20case%20LoadingStatus.loading_suc_but_empty:
%20%20%20%20%20%20%20%20return%20_buildLoadingSucButEmptyView();
%20%20%20%20%20%20case%20LoadingStatus.error:
%20%20%20%20%20%20%20%20return%20_buildErrorView();
%20%20%20%20%20%20case%20LoadingStatus.network_blocked:
%20%20%20%20%20%20%20%20return%20_buildNetworkBlockedView();
%20%20%20%20}
%20%20%20%20return%20widget.child;
%20%20}
复制代码
buildLoadingView,这里简单用了系统的CircularProgressIndicator,也可以自己显示帧动画%20%20///%20加载中%20View
%20%20Widget%20_buildLoadingView()%20{
%20%20%20%20return%20Container(
%20%20%20%20%20%20width:%20double.maxFinite,
%20%20%20%20%20%20height:%20double.maxFinite,
%20%20%20%20%20%20child:%20Center(
%20%20%20%20%20%20%20%20child:%20SizedBox(
%20%20%20%20%20%20%20%20%20%20height:%2022.w,
%20%20%20%20%20%20%20%20%20%20width:%2022.w,
%20%20%20%20%20%20%20%20%20%20child:%20CircularProgressIndicator(
%20%20%20%20%20%20%20%20%20%20%20%20strokeWidth:%202,
%20%20%20%20%20%20%20%20%20%20%20%20valueColor:%20AlwaysStoppedAnimation<Color>(AppColors.primaryBgBlue),
%20%20%20%20%20%20%20%20%20%20),
%20%20%20%20%20%20%20%20),
%20%20%20%20%20%20),
%20%20%20%20);
%20%20}
复制代码
其他提示页面,这里做了一个统一的封装
%20///%20编译通用页面
%20%20Container%20_buildGeneralTapView({
%20%20%20%20String%20url%20=%20"images/icon_network_blocked.png",
String desc,
@required Function onTap,
}) {
return Container(
color: AppColors.primaryBgWhite,
width: double.maxFinite,
height: double.maxFinite,
child: Center(
child: SizedBox(
height: 250.h,
child: Column(
children: [
Image.asset(url,
width: 140.w, height: 99.h),
SizedBox(
height: 40.h,
),
Text(
desc,
style: AppText.gray50Text12,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(
height: 30.h,
),
if (onTap != null)
BorderRedBtnWidget(
content: "重新加载",
onClick: onTap,
padding: 40.w,
),
],
),
),
),
);
}
/// 加载成功但数据为空 View
Widget _buildLoadingSucButEmptyView() {
return _buildGeneralTapView(
url: "images/icon_empty.png",
desc: "暂无数据",
onTap: null,
);
}
/// 网络加载错误页面
Widget _buildNetworkBlockedView() {
return _buildGeneralTapView(
url: "images/icon_network_blocked.png",
desc: widget.networkBlockedDesc,
onTap: () {
widget.todoAfterNetworkBlocked(widget);
});
}
/// 加载错误页面
Widget _buildErrorView() {
return _buildGeneralTapView(
url: "images/icon_error.png",
desc: widget.errorDesc,
onTap: () {
widget.todoAfterError(widget);
});
}
复制代码
使用
Widget _buildBody() {
var loadingView = LoadingView(
loadingStatus: LoadingStatus.loading,
child: _buildContent(),
todoAfterNetworkBlocked: (LoadingView widget) {
// 网络错误,点击重试
widget.updateStatus(LoadingStatus.loading);
Future.delayed(Duration(milliseconds: 1000), () {
widget.updateStatus(LoadingStatus.error);
});
},
todoAfterError: (LoadingView widget) {
// 接口错误,点击重试
widget.updateStatus(LoadingStatus.loading);
Future.delayed(Duration(milliseconds: 1000), () {
// widget.updateStatus(LoadingStatus.loading_suc);
widget.updateStatus(LoadingStatus.loading_suc_but_empty);
});
},
);
Future.delayed(Duration(milliseconds: 1000), (){
loadingView.updateStatus(LoadingStatus.network_blocked);
});
return loadingView;
}
复制代码
总结
至此已经完成了对整个Loading组件的封装,代码已上传github
以上就是Flutter开发通用页面Loading组件示例详解的详细内容,更多关于Flutter通用页面Loading组件的资料请关注我们其它相关文章!










