• 谈谈我对 Flutter 未来发展 和 “嵌套地狱” 的浅显看法


    Flutter 未来发展

    提到 Flutter 就不得不提到 Fuchsia 系统,这是一个尚未正式发布的操作的系统,引用 Android 和 Chrome 的高级副总裁 Hiroshi Lockheimer 在一档播客节目中对 Fuchsia 的介绍是:

    不仅仅是手机和个人电脑,在物联网的世界里,越来越多的设备需要操作系统、新的软件运行环境等支持。我认为,在具有不同优势和专业化的诸多操作系统中还存在很大的发展空间。Fuchsia 就是其中之一,所以,请继续保持关注。

    是的,Fuchsia 系统是为物联网研发的操作系统,物联网简称 IoT,现在全世界都在押注 IoT,包括华为、小米等国内公司。

    那 Flutter 和 Fuchsia 又有什么关系呢?

    Flutter 是 Fuchsia 官方指定的唯一UI开发框架。

    现在有很多物联网操作系统 ,Fuchsia 就一定可以脱颖而出吗?

    不一定,未来的事情谁说的准呢,但在我看来 Fuchsia 是最有可能发展起来的物联网操作系统,因为一个操作系统的发展除了本身优秀以外,最大的阻碍其实是生态,而 Fuchsia 在生态方面具有天然的优势, 国外的一篇报道曾说:

    Google 希望将 Android App 无缝移植到 Fuchsia 上,而且一直在做相关工作。

    试想一下,一旦 Google 将 Android App 无缝移植到 Fuchsia 上,其他物联网操作系统如何与之抗衡。

    这里引用 Google 公众号底部的一句话送给大家:

    预测未来不如创造未来

    在跨平台技术上 Flutter 还有很多竞争对手,比如 HTML5、React Native、Weex、快应用、小程序等,我曾在跨平台技术发展简介 中详细说明了各个跨平台技术的发展历史及优缺点。

    Flutter 的出现会终结其他跨平台技术?我想不会的, React Native 发展了这么多年也没有完全干掉 HTML5,应为 HTML5 有其独特的应用场景,比如 营销活动场景、新闻或者博客详情页面等,这些场景非常适合 HTML5。因此 Flutter 也不可能终结其他跨平台技术,总结一句话就是:

    未来很长一段时间,将会是跨平台技术共存的时代,但 Flutter 适用场景更为广阔。

    Flutter 嵌套地狱

    现在网络上对 Flutter 吐槽最多大概就是 Flutter “嵌套地狱”写法了,为什么会出现这种现象?个人认为最大的原因就是目前大部分开源的 Flutter 项目都是这种嵌套写法(包括我自己以前也是如此),导致后来的初学者认为这么写没有问题,当项目越来越复杂时,这种嵌套写法给项目的维护带来了巨大的挑战。下面说说如何避免这种嵌套写法?

    比如实现如下效果:

    嵌套地狱 的写法:

    @override
    Widget build(BuildContext context) {
      return Column(
        children: <Widget>[
          Container(
            height: 45,
            child: Row(
              children: <Widget>[
                SizedBox(
                   30,
                ),
                Icon(
                  Icons.notifications,
                  color: Colors.blue,
                ),
                SizedBox(
                   30,
                ),
                Expanded(
                  child: Text('消息中心'),
                ),
                Container(
                  padding: EdgeInsets.symmetric(horizontal: 10),
                  decoration: BoxDecoration(
                      shape: BoxShape.rectangle,
                      borderRadius: BorderRadius.all(Radius.circular(50)),
                      color: Colors.red),
                  child: Text(
                    '2',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
                SizedBox(
                   15,
                ),
              ],
            ),
          ),
          Divider(),
          //类似上面的布局写6个
        ],
      );
    }
    

    上面还仅仅是第一项的布局,下面还有7个,一个30多行代码,7个就是200多行的布局代码,这还仅仅是布局代码,如果加上逻辑,都不敢想象啊。

    或许有一点封装思想开发者会将每一个 Item封装为一个方法,写法如下:

    _buildItem(IconData iconData, Color iconColor, String title, Widget widget) {
      return Container(
        height: 45,
        child: Row(
          children: <Widget>[
            SizedBox(
               30,
            ),
            Icon(
              iconData,
              color: iconColor,
            ),
            SizedBox(
               30,
            ),
            Expanded(
              child: Text('$title'),
            ),
            widget,
            SizedBox(
               15,
            ),
          ],
        ),
      );
    }
    
    @override
    Widget build(BuildContext context) {
      return Column(
        children: <Widget>[
          _buildItem(...),
          Divider(),
          _buildItem(...),
          Divider(),
          _buildItem(...),
          Divider(),
          _buildItem(...),
          Divider(),
          _buildItem(...),
          Divider(),
          _buildItem(...),
          Divider(),
        ],
      );
    }
    

    这样看起来好多了,基本解决了嵌套地狱问题,但这样写还存在一个非常大的问题-性能问题,一旦其中一个数字发生变化,整个页面都要重建,Flutter 开发中非常重要的一个原则就是 尽可能少的重建组件,因此将上面封装到方法中组件变为一个 Widget。

    class SettingDemo extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            _SettingItem(
              iconData: Icons.notifications,
              iconColor: Colors.blue,
              title: '消息中心',
              suffix: _NotificationsText(
                text: '2',
              ),
            ),
            Divider(),
            _SettingItem(
              iconData: Icons.thumb_up,
              iconColor: Colors.green,
              title: '我赞过的',
              suffix: _Suffix(
                text: '121篇',
              ),
            ),
            Divider(),
            _SettingItem(
              iconData: Icons.grade,
              iconColor: Colors.yellow,
              title: '收藏集',
              suffix: _Suffix(
                text: '2个',
              ),
            ),
            Divider(),
            _SettingItem(
              iconData: Icons.shopping_basket,
              iconColor: Colors.yellow,
              title: '已购小册',
              suffix: _Suffix(
                text: '100个',
              ),
            ),
            Divider(),
            _SettingItem(
              iconData: Icons.account_balance_wallet,
              iconColor: Colors.blue,
              title: '我的钱包',
              suffix: _Suffix(
                text: '10万',
              ),
            ),
            Divider(),
            _SettingItem(
              iconData: Icons.location_on,
              iconColor: Colors.grey,
              title: '阅读过的文章',
              suffix: _Suffix(
                text: '1034篇',
              ),
            ),
            Divider(),
            _SettingItem(
              iconData: Icons.local_offer,
              iconColor: Colors.grey,
              title: '标签管理',
              suffix: _Suffix(
                text: '27个',
              ),
            ),
          ],
        );
      }
    }
    
    class _SettingItem extends StatelessWidget {
      const _SettingItem(
          {Key key, this.iconData, this.iconColor, this.title, this.suffix})
          : super(key: key);
    
      final IconData iconData;
      final Color iconColor;
      final String title;
      final Widget suffix;
    
      @override
      Widget build(BuildContext context) {
        return Container(
          height: 45,
          child: Row(
            children: <Widget>[
              SizedBox(
                 30,
              ),
              Icon(iconData,color: iconColor,),
              SizedBox(
                 30,
              ),
              Expanded(
                child: Text('$title'),
              ),
              suffix,
              SizedBox(
                 15,
              ),
            ],
          ),
        );
      }
    }
    
    class _NotificationsText extends StatelessWidget {
      final String text;
    
      const _NotificationsText({Key key, this.text}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.symmetric(horizontal: 10),
          decoration: BoxDecoration(
              shape: BoxShape.rectangle,
              borderRadius: BorderRadius.all(Radius.circular(50)),
              color: Colors.red),
          child: Text(
            '$text',
            style: TextStyle(color: Colors.white),
          ),
        );
      }
    }
    
    class _Suffix extends StatelessWidget {
      final String text;
    
      const _Suffix({Key key, this.text}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Text(
          '$text',
          style: TextStyle(color: Colors.grey.withOpacity(.5)),
        );
      }
    }
    

    封装为一个个单独的小组件,将有变化的组件尽量单独封装,这样就不会重建整个控件树,增强了可读性和可维护性,而且对性能有很大的提升。

    最后总结一句:

    虽然 Flutter 一切皆是组件,但并不代表一切都要写在组件中。

    当然这仅仅是我个人的看法,如果您有更好的方法欢迎一起讨论,从我做起,规范写法,为 Flutter 发展贡献做出一点微不足道的贡献。

    交流

    老孟Flutter博客地址(330个控件用法):http://laomengit.com

    欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

  • 相关阅读:
    maven 3.2.5 的安装,部署和实例
    Java8 stream操作toMap的key重复问题
    Jenkins配置定时任务注意点
    npm install提示node-sass错误
    centos 使用docker 安装 teamcity
    centos 不能连接外网,使用本地yum源安装软件
    git添加本地代码到远程仓库
    mysql 新建外网用户 和只读用户
    mysql 删除重复数据保留最新一条
    批量删除redis缓存
  • 原文地址:https://www.cnblogs.com/mengqd/p/13184318.html
Copyright © 2020-2023  润新知