flutter避免嵌套地獄的5種方法

想入坑flutter的同學(xué),都很擔(dān)心嵌套地獄,但我實際使用flutter差不多1個月,發(fā)現(xiàn)如果用的好,是可以避免嵌套地獄的,我總結(jié)為5種方法。

方法一:適當(dāng)使用“高階組件”

flutter官方文檔沒有“高階組件”的概念,我這里說的“高階組件”指的是由基礎(chǔ)組件搭建的內(nèi)置組件,如果純粹用基礎(chǔ)組件搭建UI,那嵌套層次必然很多,我們應(yīng)該了解內(nèi)置的各類“高階組件”,而且不要害怕“高階組件”不夠靈活,要知道,組件的child屬性、title屬性、leading屬性等都可以賦值任何其他組件,“高階組件”一樣可以擴(kuò)展。

舉例1: 使用ListTile代替Row+Container

ListTile其實是一個三欄布局組件,如果你有三欄或者兩欄的布局需求,而且是兩頭寬度固定,中間一欄寬度自適應(yīng),都可以直接用它實現(xiàn),而不必要自己用Row+Flex+Container實現(xiàn)。

return ListTile(
    leading: CircleAvatar(
      //頭像半徑
      radius: 25,
      //頭像圖片 -> NetworkImage網(wǎng)絡(luò)圖片,AssetImage項目資源包圖片, FileImage本地存儲圖片
      backgroundImage: NetworkImage('${mModel.headurl}'),
    ),
    title: Text(
      '${mModel.nick}',
      style: TextStyle(letterSpacing: 0, color: Colors.black, fontSize: 14),
    ),
    subtitle: Text(
      '${mModel.decs}',
      style: TextStyle(
          letterSpacing: 0, color: Color(0xff666666), fontSize: 10),
    ),
    trailing: mFollowBtnWidget(mModel, i - 1),
  );

舉例2: 使用RichText代替Text

import '../constant.dart';
RichText(
    text: TextSpan(
      text: '這是標(biāo)題',
      style: Constant.SUB_TITLE
      children: <TextSpan>[
        TextSpan(
            text: '這是鏈接',
            style: Constant.LINK,
        TextSpan(
            text: '這里淡化',
            style: Constant.MUTE_TEXT,
      ],
    ),
  )

舉例3: 使用SliverAppBar代替AppBar

SliverAppBar是一個頂部帶banner圖并且banner圖可以滑動收起的AppBar,如果自己實現(xiàn)類似功能,就要寫很多嵌套和滾動事件。它的使用方法可以去官方文檔查看。

總之,對應(yīng)官方提供的組件,我們要了解透徹,不要寫了半天代碼,原來寫的是官方都實現(xiàn)了的組件,浪費了時間不說,還增加了嵌套層次。

方法二:封裝自定義組件

封裝的方法在大多數(shù)語言和框架里都有,相信大家都知道,在這里提幾個注意的點:

適合封裝的組件:

  • 頂部的AppBar
  • 點贊按鈕
  • 分享按鈕和分享按鈕組(比如微信分享、qq分享)
  • 個人頭像
  • 常用的主按鈕、默認(rèn)按鈕(類似vue的vant組件庫的按鈕)
  • Loading加載動畫
  • Dialog對話窗
  • 常用的帶顏色和大小屬性的文本

恰當(dāng)使用全局常量:

// file: constant.dart
class Constant {
  static const COLOR_TITLE = Color(0xFF202020);
  static const COLOR_SUBTITLE = Color(0xFF88888A);
  static const COLOR_MUTE = Color(0xccccccff);
  static const COLOR_WARN = Color(0xFFF59A23);
  static const COLOR_ERROR = Color(0xFFFA3651);
  static const COLOR_PRIMARY = Color(0xFFA33028);
  static const COLOR_LINK = Color(0xCC61ADF3);
  
  static sonst MAIN_TITLE = TextStyle(fontSize: 16, color: COLOR_TITLE);
  static sonst SUB_TITLE = TextStyle(fontSize: 12, color: COLOR_SUBTITLE);
  static sonst LINK = TextStyle(fontSize: 13, color: COLOR_LINK);
}

使用:

import '../constant.dart';
.....
Container(
    margin: EdgeInsets.only(top: 3),
    child: Text(
        mCneterItem[0].hotdiscuss,
        style: Constant.LINK,
  )

方法三:使用SizedBox代替Container的margin,Spacer代替Flex

如果我們使用Container僅僅是為了使用的它的margin屬性,可以適當(dāng)?shù)氖褂肧izedBox和Spacer代替。
例如:

Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        SizedBox(height: 5),
        Input(
          ...
        ),
        SizedBox(height: 5),
        Input(
          ...
        ),
        ),
      ],
    )

Spacer其實就是包裝了一個 Expanded 的 SizedBox. 我們可以通過它靈活控制 Row/Column

body: Center(
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: <Widget>[
      Container(
        color: Colors.blue,
        margin: EdgeInsets.symmetric(horizontal: 5),
        height: 50,
        width: 50,
      ),
      Spacer(flex: 2), // 彈性系數(shù)為2
      Container(
        color: Colors.blue,
        height: 50,
        margin: EdgeInsets.symmetric(horizontal: 5),
        width: 50,
      ),
      Spacer(), // 彈性系數(shù)默認(rèn)為1
      Container(
        color: Colors.blue,
        margin: EdgeInsets.symmetric(horizontal: 5),
        height: 50,
        width: 50,
      ),
    ],
  ),
)

方法四:使用Map代替if else

有時我們有通過if else來返回不同的組件嵌套,而里面僅有一部分不同,可以用Map或者三元語法返回一個變量,在組件嵌套里面直接使用變量就可以了。
實例:

// 優(yōu)化前的代碼:
if(level == 'level1') {
   return Container(
      width: (MediaQuery.of(context).size.width - 75) / 4,
      height: (MediaQuery.of(context).size.width - 75) / 4,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5),
          image: DecorationImage(
            image: NetworkImage('https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic1.jpg'),
            fit: BoxFit.cover,
          )),
    )
 } else {
   return Container(
      width: (MediaQuery.of(context).size.width - 75) / 4,
      height: (MediaQuery.of(context).size.width - 75) / 4,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5),
          image: DecorationImage(
            image: NetworkImage('https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic2.jpg'),
            fit: BoxFit.cover,
          )),
    )
 }
// 優(yōu)化后的代碼
urls = {
'level1': 'https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic1.jpg',
'level2': 'https://hrlweibo-1259131655.cos.ap-beijing.myqcloud.com/pic1.jpg'
}
return Container(
      width: (MediaQuery.of(context).size.width - 75) / 4,
      height: (MediaQuery.of(context).size.width - 75) / 4,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5),
          image: DecorationImage(
            image: NetworkImage(urls[level]),
            fit: BoxFit.cover,
          )),
    ),

大家可能覺得自己不會寫優(yōu)化前這么垃圾的代碼,但我在github上就經(jīng)??吹竭@樣的代碼,可能是有點懶,也可能是沒注意。說到這里,提醒大家要多review一下代碼,看是否可以優(yōu)化。

方法五:使用擴(kuò)展函數(shù)

關(guān)于擴(kuò)展函數(shù), 這篇文章寫的很好:《Flutter嵌套地獄!看完此文你就掌握了解決方案》,這個方法是解決嵌套地獄的終極方法,不過要適當(dāng)?shù)挠?,不要濫用,否則也會影響代碼閱讀,建議主要使用樣式組件的擴(kuò)展函數(shù),比如顏色、大小、paddig、是否可見,居中、居右,ClipOval,borderRadius等。文章的作者還寫了一個擴(kuò)展函數(shù)庫給我們使用,里面涵蓋了通常使用的擴(kuò)展函數(shù),我們可以在他的基礎(chǔ)上加自己喜歡的擴(kuò)展函數(shù)。

總結(jié):

有了以上5種方法,我感覺flutter好香!媽媽再也不用擔(dān)心我的嵌套地獄問題了!當(dāng)然,以上每個方法都有它自己的適用場景,要結(jié)合使用。還有,我們在開發(fā)過程中要學(xué)會重構(gòu)和去除重復(fù)代碼,方法二和方法四實際上是去除重復(fù)代碼,從而避免了嵌套。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容