Flutter之BaseWidget高度封装,如BaseActivity/BaseViewController般丝滑

3,227 阅读6分钟
原文链接: blog.csdn.net

Flutter—分久必合,结束百家争鸣的使者

Flutter致命优势

当今大前端开发天下,百家争鸣,玲琅满目的框架 、插件害苦了开发人员。
如果你是一名移动端或者前端开发人员,,你还不知道或者还在观望Flutter,这是件多么可怕的事情。
之前对于Flutter我也是持观望态度,随着1.0、1.2版本的发布,果断入坑,理由很简单:

  1. Flutter是自己渲染界面(区别于React Native以及Weex),这一点势必打破手机碎片化问题,不管是哪个厂商的安卓手机,也不管是ios还是安卓,画完UI,长相一个样,几乎不用适配。
  2. 第二点就厉害了,Flutter支持web开发、桌面(windows、macOS)开发、移动端(ios、安卓),以及谷歌将来要出的新系统Fuchsia,统统支持。

当然人无完人,flutter 现在还是幼婴阶段,插件、控件之类的还不是很多,以及热修复暂时还不支持,不过这些都是迟早解决的事。

入坑以来,发现Flutter 的页面不像安卓那样明确,安卓中就是Activity,IOS中就是UIViewController,H5中就是一个route,我们项目开发基本都会有一个BaseActivity/BaseViewController,今天就为各位带来和其功能以及使用方式差不多的BaseWidget。

BaseWidget

BaseWidget 生命周期

话不多说,先上视频。

  • 左图是 一个页面里面嵌套着三个Tab页切换的效果
  • 右图是一个三级路由跳转和回退的效果,以及公用的错误页面、无数据页面和loading页面(loadiing页面可以用dialog替换)。
  • 下面两幅图分别是这两个效果中 跳转和切换时 每个页面的生命周期情况

就问 熟不熟悉!熟不熟悉 ! 相信每一个安卓开发人员都很熟悉这种log日志,也是安卓入门必备的技能。

BaseWidget 实现功能

看完效果,我来描述一下BaseWidget所能轻松实现的功能。

  1. 开发的时候,写一个类继承BaseWidget,就会让我们实现必要的抽象方法,俗称模板模式,当然,内嵌页面需要继承BaseInnerWidget,要做的事一目了然
  2. 从一个页面A跳转到B的时候,A会调用onPause方法,B会调用onCreate和onResume方法,从B回到A的时候,A会调用onResume方法,B会调用onPause和onDestory方法 ,onCreate中放一些数据初始化,onResume中就放一下网络请求,每次回到页面都会发起请求,onPause和onDestory分别是离开页面和销毁页面,可以自己根据需求来完善方法。
  3. 状态栏TopBar可以轻松隐藏和设置颜色以及以图片作为背景
  4. 导航栏AppBar同样可以轻松隐藏和设置背景颜色(图片),其中导航栏中的左边返回键、中间的大标题、右面的小标题,可以随意设置隐藏和现实,当然可以重写他们的方法,随意设置自己的Widget,实现高度定制。
  5. 内置了一个 错误加载页面 ,网络加载出错的时候 ,可以调个方法就显示,不用每个页面都写错误页面,避免需求变更时束手无策。
  6. 内置一个无数据页面,和错误页面 使用方法和功能差不多
  7. 内置了loading加载 页面 ,功能同上,觉得这个没必要的,可以自己用dialog替代~
  8. 监听app退到后台和从后台返回到前台,要做什么功能在BaseWidget的方法里面直接写就好了
  9. 重中之重,有了一个基类,拓展性就很高很高了~

新写一个类 ,创建好是这个样子的,简约而大气的模板模式,可以随心所欲的写代码了。

class FirstPage extends BaseWidget {
  @override
  BaseWidgetState<BaseWidget> getState() {
    // TODO: implement getState
    return _FirstPageState();
  }

}

class _FirstPageState extends BaseWidgetState<FirstPage> {
  @override
  Widget buildWidget(BuildContext context) {
    // TODO: implement buildWidget
    return null;
  }

  @override
  void onCreate() {
    // TODO: implement onCreate
  }

  @override
  void onPause() {
    // TODO: implement onPause
  }

  @override
  void onResume() {
    // TODO: implement onResume
  }

}

BaseWidget 实现思路

入坑Flutter的时候发觉Flutter的生命周期不是那么明确。

Flutter中所谓的生命周期是在State中,如下简单几个

  • initState 创建之初调用一次 类似于onCreate
  • didChangeDependencies 在initState之后调用,可以在这个方法中跨组件拿到数据。
  • didUpdateWidget 当组件的状态改变的时候就会调用,比如调用了setState.
  • build 创建Widget的地方,在离开和回到页面的时候都会调用。
  • deactivate 在离开和回到页面的时候都会调用。
  • dispose 销毁的时候调用

打日志的时候发现很乱,尤其的build和deactivate两个方法,跳转和回到页面都会调用到,有点像onPause和onResume的集合体,所以就借用了数据结构中的Stack栈 在页面创建的时候存在Stack中,离开的时候移除Stack,然后根据页面存在栈中的位置,结合build和deactivate 调用时机,写出了真正意义上的onPaue和onResume方法

@override
  void initState() {
    NavigatorManger().addWidget(this);//入栈
}

  @override
  void dispose() {
    NavigatorManger().removeWidget(this);//出栈
    super.dispose();
  }

不过这里出现了个情况,就是当BaseWidget作为内部页面嵌入的时候,自己的生命周期不明确,而且也影响外部页面的生命周期,索性就单独整了一个BaseInnerWisget作为内嵌页面的基类,有点类似BaseFragment,不过他的生命周期需要在外部页面中完善些方法才能正确,强迫症的同学可以自己在封装一下~具体使用方法已上传代码,可自行发挥。

生命周期整完以后,就是一些基础布局搭建了,

布局搭建,就是在基类里面的Build方法中先内置了几个基本控件,然后预留一个抽象方法给子类搭建自己的布局。


  Widget _getBaseView(BuildContext context) {
    return Column(
      children: <Widget>[
        _getBaseTopBar(),//状态栏布局
        _getBaseAppBar(),//导航栏布局
        Container(
          width: getScreenWidth(),
          height: getMainWidgetHeight(),//子类布局可用的高度
          color: Colors.white, //背景颜色,可自己变更
          child: Stack(
            children: <Widget>[
              buildWidget(context),//子类的布局
              _getBaseErrorWidget(),//错误页面布局
              _getBaseEmptyWidget(),//空页面布局
              _getBassLoadingWidget(),//加载中布局
            ],
          ),
        ),
      ],
    );
  }

剩下的事情就是往各个方法里面填写对应的界面,以及暴露出方法让子类修改属性,无非就是设置下 文案,图片,隐藏和显示,都是很基础的啦,具体实现可以自己看代码哈,一定难不倒聪明的你!

作为开发人员,我希望把功能掌握在自己手里,而不是sdk手里,愉快的发车吧!
源码和具体说明已经上传至github欢迎star、fork。
Flutter/安卓开发交流群:661614986,期待您的加入!