網(wǎng)站首頁 編程語言 正文
前沿
頁面通用Loading組件是一個App必不可少的基礎功能,之前只開發(fā)過Android原生的頁面Loading,這次就按原生的邏輯再開發(fā)一個Flutter的Widget,對其進行封裝復用
我們先看下效果:
原理
狀態(tài)
一個通用的頁面加載Loading組件應該具備以下幾種狀態(tài):
IDLE 初始化
Idle狀態(tài),此時的組件還只是初始化
LOADING 加載中
Loading狀態(tài),一般在網(wǎng)絡請求或者耗時加載數(shù)據(jù)時調用,通用顯示的是一個progress或者自定義的幀動畫
LOADING_SUCCESS
LoadingSuccess加載成功,一般在網(wǎng)絡請求成功后調用,并將需要展示的頁面展示出來
LOADING_SUCCESS_BUT_EMPTY
頁面加載成功但是沒有數(shù)據(jù),這種情況一般是發(fā)起列表數(shù)據(jù)請求但是沒有數(shù)據(jù),通常我們會展示一個空數(shù)據(jù)的頁面來提醒用戶
NETWORK_BLOCKED
網(wǎng)絡錯誤,一般是由于網(wǎng)絡異常、網(wǎng)絡請求連接超時導致。此時我們需要展示一個網(wǎng)絡錯誤的頁面,并且?guī)в兄卦嚢粹o,讓用戶重新發(fā)起請求
ERROR
通常是接口錯誤,這種情況下我們會根據(jù)接口返回的錯誤碼或者錯誤文本提示用戶,并且也有重試按鈕
/// 狀態(tài)枚舉
enum LoadingStatus {
idle, // 初始化
loading, // 加載中
loading_suc, // 加載成功
loading_suc_but_empty, // 加載成功但是數(shù)據(jù)為空
network_blocked, // 網(wǎng)絡加載錯誤
error, // 加載錯誤
}
點擊事件回調
當網(wǎng)絡異常或者接口報錯時,會顯示錯誤頁面,并且提供重試按鈕,讓用戶點擊重新請求。基于這個需求,我們還需要提供點擊重試后的事件回調讓業(yè)務可以處理重新請求。
/// 定義點擊事件
typedef OnTapCallback = Function(LoadingView widget);
提示文案
提供提示文案的自定義,方便業(yè)務根據(jù)自己的需求展示特定的提示文案
代碼實現(xiàn)
根據(jù)上面的原理來實現(xiàn)對應的代碼
- 構造方法
/// 構造方法
LoadingView({
Key key,
@required this.child, // 需要加載的Widget
@required this.todoAfterError, // 錯誤點擊重試
@required this.todoAfterNetworkBlocked, // 網(wǎng)絡錯誤點擊重試
this.networkBlockedDesc = "網(wǎng)絡連接超時,請檢查你的網(wǎng)絡環(huán)境",
this.errorDesc = "加載失敗",
this.loadingStatus = LoadingStatus.idle,
}) : super(key: key);
- 根據(jù)不同的Loading狀態(tài)展示對應的Widget
- 其中idle、success狀態(tài)直接展示需要加載的Widget(這里也可以使用漸變動畫進行切換過度)
///根據(jù)不同狀態(tài)展示不同Widget
Widget _buildBody() {
switch (widget.loadingStatus) {
case LoadingStatus.idle:
return widget.child;
case LoadingStatus.loading:
return _buildLoadingView();
case LoadingStatus.loading_suc:
return widget.child;
case LoadingStatus.loading_suc_but_empty:
return _buildLoadingSucButEmptyView();
case LoadingStatus.error:
return _buildErrorView();
case LoadingStatus.network_blocked:
return _buildNetworkBlockedView();
}
return widget.child;
}
- buildLoadingView,這里簡單用了系統(tǒng)的CircularProgressIndicator,也可以自己顯示幀動畫
/// 加載中 View
Widget _buildLoadingView() {
return Container(
width: double.maxFinite,
height: double.maxFinite,
child: Center(
child: SizedBox(
height: 22.w,
width: 22.w,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(AppColors.primaryBgBlue),
),
),
),
);
}
- 其他提示頁面,這里做了一個統(tǒng)一的封裝
/// 編譯通用頁面
Container _buildGeneralTapView({
String url = "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,
),
],
),
),
),
);
}
/// 加載成功但數(shù)據(jù)為空 View
Widget _buildLoadingSucButEmptyView() {
return _buildGeneralTapView(
url: "images/icon_empty.png",
desc: "暫無數(shù)據(jù)",
onTap: null,
);
}
/// 網(wǎng)絡加載錯誤頁面
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) {
// 網(wǎng)絡錯誤,點擊重試
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;
}
總結
至此已經(jīng)完成了對整個Loading組件的封裝,代碼已上傳Github
原文鏈接:https://juejin.cn/post/7063025458761170981
相關推薦
- 2023-07-05 parcel運行終端報錯Uncaught ReferenceError: parcelRequire
- 2022-02-18 spring常見錯誤:Error creating bean with name ‘xxx‘
- 2023-05-08 Python實現(xiàn)統(tǒng)計文章閱讀量的方法詳解_python
- 2022-09-04 Go語言指針用法詳解_Golang
- 2022-07-13 Docker的資源控制管理
- 2022-09-23 WPF仿微信實現(xiàn)截圖功能的方法詳解_C#教程
- 2023-03-22 WinPC搭建nginx服務器的實現(xiàn)步驟_nginx
- 2022-06-09 Python+OpenCV實現(xiàn)圖片中的圓形檢測_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支