日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Flutter開發通用頁面Loading組件示例詳解_Android

作者:Fitem ? 更新時間: 2022-12-25 編程語言

前沿

頁面通用Loading組件是一個App必不可少的基礎功能,之前只開發過Android原生的頁面Loading,這次就按原生的邏輯再開發一個Flutter的Widget,對其進行封裝復用

我們先看下效果:

原理

狀態

一個通用的頁面加載Loading組件應該具備以下幾種狀態:

IDLE 初始化

Idle狀態,此時的組件還只是初始化

LOADING 加載中

Loading狀態,一般在網絡請求或者耗時加載數據時調用,通用顯示的是一個progress或者自定義的幀動畫

LOADING_SUCCESS

LoadingSuccess加載成功,一般在網絡請求成功后調用,并將需要展示的頁面展示出來

LOADING_SUCCESS_BUT_EMPTY

頁面加載成功但是沒有數據,這種情況一般是發起列表數據請求但是沒有數據,通常我們會展示一個空數據的頁面來提醒用戶

NETWORK_BLOCKED

網絡錯誤,一般是由于網絡異常、網絡請求連接超時導致。此時我們需要展示一個網絡錯誤的頁面,并且帶有重試按鈕,讓用戶重新發起請求

ERROR

通常是接口錯誤,這種情況下我們會根據接口返回的錯誤碼或者錯誤文本提示用戶,并且也有重試按鈕

/// 狀態枚舉
enum LoadingStatus {
  idle, // 初始化
  loading, // 加載中
  loading_suc, // 加載成功
  loading_suc_but_empty, // 加載成功但是數據為空
  network_blocked, // 網絡加載錯誤
  error, // 加載錯誤
}

點擊事件回調

當網絡異常或者接口報錯時,會顯示錯誤頁面,并且提供重試按鈕,讓用戶點擊重新請求。基于這個需求,我們還需要提供點擊重試后的事件回調讓業務可以處理重新請求。

 /// 定義點擊事件
 typedef OnTapCallback = Function(LoadingView widget);

提示文案

提供提示文案的自定義,方便業務根據自己的需求展示特定的提示文案

代碼實現

根據上面的原理來實現對應的代碼

  • 構造方法
 /// 構造方法
 LoadingView({
    Key key,
    @required this.child, // 需要加載的Widget
    @required this.todoAfterError, // 錯誤點擊重試
    @required this.todoAfterNetworkBlocked, // 網絡錯誤點擊重試
    this.networkBlockedDesc = "網絡連接超時,請檢查你的網絡環境",
    this.errorDesc = "加載失敗",
    this.loadingStatus = LoadingStatus.idle,
 }) : super(key: key);
  • 根據不同的Loading狀態展示對應的Widget
  • 其中idle、success狀態直接展示需要加載的Widget(這里也可以使用漸變動畫進行切換過度)
 ///根據不同狀態展示不同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,這里簡單用了系統的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),
          ),
        ),
      ),
    );
  }
  • 其他提示頁面,這里做了一個統一的封裝
/// 編譯通用頁面
  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,
                ),
            ],
          ),
        ),
      ),
    );
  }
    /// 加載成功但數據為空 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

原文鏈接:https://juejin.cn/post/7063025458761170981

欄目分類
最近更新