談談我對 Flutter 將來發展 和 「嵌套地獄」 的淺顯見解

Flutter 將來發展

提到 Flutter 就不得不提到 Fuchsia 系統,這是一個還沒有正式發佈的操做的系統,引用 Android 和 Chrome 的高級副總裁 Hiroshi Lockheimer 在一檔播客節目中對 Fuchsia 的介紹是:git

不只僅是手機和我的電腦,在物聯網的世界裏,愈來愈多的設備須要操做系統、新的軟件運行環境等支持。我認爲,在具備不一樣優點和專業化的諸多操做系統中還存在很大的發展空間。Fuchsia 就是其中之一,因此,請繼續保持關注。

是的,Fuchsia 系統是爲物聯網研發的操做系統,物聯網簡稱 IoT,如今全世界都在押注 IoT,包括華爲、小米等國內公司。小程序

那 Flutter 和 Fuchsia 又有什麼關係呢?微信

Flutter 是 Fuchsia 官方指定的惟一UI開發框架。網絡

如今有不少物聯網操做系統 ,Fuchsia 就必定能夠脫穎而出嗎?框架

不必定,將來的事情誰說的準呢,但在我看來 Fuchsia 是最有可能發展起來的物聯網操做系統,由於一個操做系統的發展除了自己優秀之外,最大的阻礙實際上是生態,而 Fuchsia 在生態方面具備自然的優點, 國外的一篇報道曾說:less

Google 但願將 Android App 無縫移植到 Fuchsia 上,並且一直在作相關工做。

試想一下,一旦 Google 將 Android App 無縫移植到 Fuchsia 上,其餘物聯網操做系統如何與之抗衡。ide

這裏引用 Google 公衆號底部的一句話送給你們:佈局

預測將來不如創造將來性能

在跨平臺技術上 Flutter 還有不少競爭對手,好比 HTML五、React Native、Weex、快應用、小程序等,我曾在[跨平臺技術發展簡介]() 中詳細說明了各個跨平臺技術的發展歷史及優缺點。ui

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(
              width: 30,
            ),
            Icon(
              Icons.notifications,
              color: Colors.blue,
            ),
            SizedBox(
              width: 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(
              width: 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(
          width: 30,
        ),
        Icon(
          iconData,
          color: iconColor,
        ),
        SizedBox(
          width: 30,
        ),
        Expanded(
          child: Text('$title'),
        ),
        widget,
        SizedBox(
          width: 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(
            width: 30,
          ),
          Icon(iconData,color: iconColor,),
          SizedBox(
            width: 30,
          ),
          Expanded(
            child: Text('$title'),
          ),
          suffix,
          SizedBox(
            width: 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】:

相關文章
相關標籤/搜索