美文网首页
Flutter加载(loading)页面 2023-01-20

Flutter加载(loading)页面 2023-01-20

作者: 勇往直前888 | 来源:发表于2023-01-19 15:07 被阅读0次

    需求简介

    一般的页面,大多数可以分为三种状态:

    1. 数据加载完成,正常显示;

    2. 数据加载完成,但是没有数据,一般会有一个空数据视图;
      加载后网络错误一般给个toast提示就好,给个错误视图并没有什么价值。

    3. 加载过程,一般是loading视图,这个就是当前的话题;

    简单实现

    一般的toast插件,都会提供一个loading视图。比如我们现在用的bot_toast插件,大多数时候用的是toast提示。网络访问时的loading视图用的也是他,而且直接做在底层的request接口。只要有网络访问,就自动显示。

    企业微信截图_62fa2228-9bcf-473d-81e1-47bfbb65f5d3.png

    自定义视图

    如果简单的loading不喜欢,可以考虑自定义写一个。
    这里有一个非常好用的插件lottie

    他的特点是,先用AE工具做一个动画,然后借助工具Bodymovin转化为json文件。把这个json文件以资源的形式加入工程,然后就可以用这个lottie工具进行展示。

    企业微信截图_efb3cd09-06a4-4605-a379-710af219e2fc.png

    这样出来的loading动画比直接使用gif文件,质量上要好很多。所以这个插件还是很受欢迎的。

    企业微信截图_41311865-2609-4049-9cee-5ef53829f304.png

    使用

    • 把动画json文件以资源的形式加入工程。

    • 类似图片,用lottie工具加载。

    企业微信截图_26bf171c-189f-49a3-866b-c7e8f51e9d87.png

    封装

    • lottie工具实现的是动画以json资源文件的形式加载,并且画面质量很高。

    • 就像上面的视图,4个跳动的绿点是动画,但是灰色框,以及外面看不见的蒙层,那是需要自己写的。

    loading视图

      Widget get _loadingView {
        // return Center(
        //   child: Lottie.network('https://assets3.lottiefiles.com/private_files/lf30_gvdwzaoj.json'),
        // );
        // return Center(child: Lottie.asset("assets/loading.json"));
        return Center(
          child: Container(
            color: Colors.transparent,
            height: ScreenUtil().screenHeight,
            width: ScreenUtil().screenWidth,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                  decoration: BoxDecoration(
                    color: const Color(0x99000000),
                    borderRadius: BorderRadius.all(Radius.circular(5.w)),
                  ),
                  width: 100.w,
                  height: 100.w,
                  child: Center(
                    child: SizedBox(
                      width: 60.w,
                      height: 60.w,
                      child: Lottie.asset("assets/lottie/loading.json"),
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    
    • Lottie加载的动画是60x60的跳动的绿点;

    • 绿点包在一个100x100的透明度60%黑色,带圆角的矩形中

    • 最外层是一个全屏尺寸的无色矩形,防止点击。

    布局实现

    这个loading视图做成了一个公共组件,主要的布局代码如下:

      @override
      Widget build(BuildContext context) {
        if (cover) {
          return Stack(
            children: [child, isLoading ? _loadingView : Container()],
          );
        } else {
          return isLoading ? _loadingView : child;
        }
      }
    
    • cover参数默认为true,就是loading视图以浮层的形式覆盖在原视图上(Stack组件实现)。为false的时候,就是只显示loading视图,不显示原视图。

    • 做成了公共组件,原视图以child的方式加入,然后使用者自己控制isLoading参数来达到loading视图的显示和隐藏。这个有点“套娃”的味道,和传统的继承感觉不大一样。

    使用

    • 如果要全屏控制,可以把整个Scaffold都当做child传入;

    • 大多数时候,只要把body作为child的就可以了。(loading过程,可以点导航栏的返回按钮)

            body: LottieUtils(
              isLoading: logic.isShowLoading,
              cover: logic.hasData,
              child: buildBody(),
            ),
    
    • 使用两三个逻辑变量来控制loading视图的显示和隐藏
      /// 加载过程标记
      /// 是否有数据; 根据接口返回的total来判断
      /// 无数据,只显示loading,cover参数为false;
      /// 有数据,loading展示在原有视图之上,cover参数为true;
      bool get hasData {
        return total > 0;
      }
    
      bool isDataReady = false;
      bool get isShowLoading {
        return !isDataReady;
      }
    
    • 一般可以直接用在网络接口数据的访问中
      /// 获取预演包裹列表; 上拉,下拉,接口封装
      /// 加载过程标记做在这个接口上
      Future getRehearList({bool isRefresh = false}) async {
        /// 接口开始,显示loading
        isDataReady = false;
        update();
    
        StorageApi.previewItem(
          parameters: queryParams,
          success: (response) {
            /// 成功,隐藏loading
            isDataReady = true;
            update();
           
            /// 其他业务处理代码
              
          },
          fail: (e) {
            /// 失败,隐藏loading
            isDataReady = true;
            update();
          },
        );
      }
    

    全局loading

    在大多数情况下,上面的loading方案已经够用。但是,某些特殊情况,就力不从心。
    上面的Loading和具体的页面深度绑定,有具体的上下文环境,可以工作很好。
    对于那些离开具体上下文全局场景,需要那种浮层式的全局loading。

    借用插件

    全局浮层写起来麻烦,那么可以考虑借用插件来实现。工程中的toast用的是bot_toast,那么就可以借用这个来实现。

    • 既然是全局的loading,那么就直接做成静态函数。
      static showToastLoading() {
        BotToast.showCustomLoading(
          toastBuilder: (cancelFunc) {
            return _loadingView;
          },
        );
      }
    
      static hideToastLoading() {
        BotToast.closeAllLoading();
      }
    
    • 具体的 _loadingView,就是上面用到的
      static Widget get _loadingView {
        return Center(
          child: Container(
            color: Colors.transparent,
            height: ScreenUtil().screenHeight,
            width: ScreenUtil().screenWidth,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                  decoration: BoxDecoration(
                    color: const Color(0x99000000),
                    borderRadius: BorderRadius.all(Radius.circular(5.w)),
                  ),
                  width: 100.w,
                  height: 100.w,
                  child: Center(
                    child: SizedBox(
                      width: 60.w,
                      height: 60.w,
                      child: Lottie.asset("assets/lottie/loading.json"),
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    
    • 使用起来和BotToast一样简单,只要保证LottieUtils.showToastLoading()和LottieUtils.hideToastLoading()成对出现就可以了,不需要考虑具体的布局。反正一律是全屏的浮层。

    相关文章

      网友评论

          本文标题:Flutter加载(loading)页面 2023-01-20

          本文链接:https://www.haomeiwen.com/subject/njkqhdtx.html