国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【開發(fā)經(jīng)驗(yàn)】Flutter避免代碼嵌套,寫好build方法

Worktile / 905人閱讀

摘要:意味著屬性必須在構(gòu)造函數(shù)中就被初始化完成,不接受提前定義,也不接受更改。所以,在生命周期中動態(tài)的改變對象的屬性是不可能的,必須使用框架的方法來為構(gòu)造函數(shù)動態(tài)指定參數(shù),從而達(dá)到改變組件屬性的功能。

本文適合使用Flutter開發(fā)過一段時間的開發(fā)者閱讀,旨在分享一種避免Flutter的UI代碼嵌套太深問題的方法。如果對本文內(nèi)容或觀點(diǎn)有相關(guān)疑問,歡迎在評論中指出。

優(yōu)化效果(縮略圖):

距離我接觸Flutter已經(jīng)過去了九個月,在Flutter代碼編寫的過程中,很多開發(fā)者都遇到了“回調(diào)地獄”的問題。在Flutter中,稱之為回調(diào)并不準(zhǔn)確,準(zhǔn)確的說,是因?yàn)楸姸?b>Widget互相嵌套在一起,導(dǎo)致反括號部分堆積嚴(yán)重,極度影響代碼可讀性。

本文將介紹一種代碼編寫風(fēng)格,最大限度減少嵌套對代碼閱讀的影響。

初步介紹

我們先來簡單看一下,Flutter的UI代碼:

使用build方法

FlutterWidget使用build方法來創(chuàng)建UI組件,然后通過注入child屬性的方式為組件添加子組件,子組件可以繼續(xù)包含child,通過調(diào)用每一個childbuild方法,就形成了類似DOM結(jié)構(gòu)的組件樹,然后由渲染引擎渲染圖形。

一個常見的定義組件的例子如下:

class DeleteText extends StatelessWidget {
  // 我們在build方法中渲染自定義Widget
  @override
  Widget build(BuildContext context) {
    return Text("Delete");
  }
}
組件屬性必須為final

要在Flutter中定義(繼承)一個Widget,則它的屬性必須都是final的。final意味著屬性必須在構(gòu)造函數(shù)中就被初始化完成,不接受提前定義,也不接受更改。所以,在生命周期中動態(tài)的改變Widget對象的屬性是不可能的,必須使用框架的build方法來為構(gòu)造函數(shù)動態(tài)指定參數(shù),從而達(dá)到改變組件屬性的功能。

class Avatar extends StatelessWidget {
  // 如果url屬性不是final的,編譯器會報出警告
  final String url;
  // 這個構(gòu)造方法很長,但是主要你寫了final屬性,VSCode就會幫我們自動生成
  const Avatar({Key key, this.url}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8),
      ),
      child: Image.network(url),
    );
  }
}
Tips:自動創(chuàng)建構(gòu)造方法,只要是構(gòu)造方法沒有的final屬性,點(diǎn)擊“快速修復(fù)”,就可以自動生成構(gòu)造方法。

Flutter語法與HTML/CSS

嵌套正是DOM樹的特點(diǎn),正如HTML其實(shí)也會無限嵌套一樣(大多數(shù)前端可能看HTML看習(xí)慣了,都忘了HTML其實(shí)也經(jīng)常會寫成嵌套很深的形式),Flutter的UI代碼嵌套本質(zhì)是不可避免的,這正是Flutter UI代碼的編寫特點(diǎn)——一次成型,而不是通過addView之類的方法來手動管理每一個視圖的生命周期。在此基礎(chǔ)上,Flutter可以高效的反復(fù)重建Widget,在渲染效率上展現(xiàn)出了非常大的優(yōu)勢。


  • 嵌套代碼難以閱讀

    當(dāng)我們評判一串代碼的時候,一個顯而易見的點(diǎn),就是代碼距離左邊的距離,如果一行代碼距離左邊達(dá)到了十多個tab,可想而知它被嵌套在了多么深的位置。

    來看看這個Widget,這個Widget很簡單,左邊有一個正文和一個附屬文本,附屬文本在正文下方,右邊有一組按鈕,代表這一行的操作,我們再給他嵌套一個動畫的漸現(xiàn)效果,處理好字體。那么他的代碼應(yīng)該如下所示:

    // 一個簡單的嵌套的情況
    class ActionRow extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return AnimatedOpacity(
          opacity: 1,
          duration: Duration(milliseconds: 800),
          child: Container(
            color: Colors.white,
            margin: EdgeInsets.symmetric(vertical: 1),
            padding: EdgeInsets.symmetric(horizontal: 20),
            child: Row(
              children: [
                Expanded(
                  child: Container(
                    padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
    /*  超級長的左邊距  */Text(
                          "Title",
                          style: TextStyle(fontSize: 16),
                        ),
                        Container(
                          padding: EdgeInsets.only(top: 4),
                          child: Text(
                            "Desc",
                            style: TextStyle(fontSize: 12),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
                Row(
                  children: [
                    Container(
                      padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
                      child: MaterialButton(
                        color: Colors.orange,
                        child: Text("Edit"),
    /*  超級長的左邊距   */onPressed: () {
                          print("Handle Edit");
                        },
                      ),
                    ),
                    Container(
                      padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
                      child: MaterialButton(
                        color: Colors.red,
                        child: Text("Delete"),
                        onPressed: () {
                          print("Handle Delete");
                        },// 往下數(shù),足足11個反括號
                      ),
                    ),
                  ],
                )
              ],
            ),
          ),
        );
      }
    }

    此種代碼,只要是開發(fā)過Flutter的開發(fā)者一定不會陌生,它可以完美運(yùn)行,但是十分難以閱讀。反括號的數(shù)量經(jīng)常會達(dá)到一個更夸張的級別,導(dǎo)致部分內(nèi)容被頂?shù)竭^于右邊,在閱讀時造成了非常大的困難。

    就讓我們以這串代碼為例子,來優(yōu)化他的嵌套,使其可以輕松的從上到下閱讀。

    解決方法 不寫new

    Dart2已經(jīng)可以完全不寫new了,但有的開發(fā)者還在寫new。去掉new之后,代碼會變得更加干凈。

    定義變量以減少反括號

    在這里,我們可以抽取部分嵌套很深的Widget,將其定義成變量,從而減少它與左邊的距離。
    讀一下代碼,我們很容易就能發(fā)現(xiàn),左邊的Expanded部分中,兩個文字的相關(guān)代碼距離左邊太遠(yuǎn)了,我們將他們抽出來作為一個獨(dú)立的Widget變量,右邊的兩個按鈕也是同理:

    class ActionRow extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // 將左邊的抽出來作為變量
        Widget left = Container(
          padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
    /* 短多了啊*/"Title",
                style: TextStyle(fontSize: 16),
              ),
              Container(
                padding: EdgeInsets.only(top: 4),
                child: Text(
                  "Desc",
                  style: TextStyle(fontSize: 12),
                ),
              ),
            ],
          ),
        );
        // 右邊同理
        Widget right = Row(
          children: [
            Container(
              padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
              child: MaterialButton(
                color: Colors.orange,
    /* 短多了啊*/child: Text("Edit"),
                onPressed: () {
                  print("Do something here");
                },
              ),
            ),
            Container(
              padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
              child: MaterialButton(
                color: Colors.red,
                child: Text("Delete"),
                onPressed: () {
                  print("Do something here");
                },
              ),
            ),
          ],
        );
        return AnimatedOpacity(
          opacity: 1,
          duration: Duration(milliseconds: 800),
          child: Container(
            color: Colors.white,
            margin: EdgeInsets.symmetric(vertical: 1),
            padding: EdgeInsets.symmetric(horizontal: 20),
            child: Row(
              children: [
                Expanded(
    /*這里還是太長*/child: left,
                ),
                right,
              ],// 現(xiàn)在有六個反括號
            ),
          ),
        );
      }
    }

    現(xiàn)在,我們的程序似乎有了一個均勻的左邊距,看起來不會那么可怕了。

    反復(fù)利用變量,處理復(fù)雜嵌套

    在嵌套很復(fù)雜時,也可以使用這種處理方法,把修飾用的UI與主體功能分離。很多時候?yàn)榱藢?shí)現(xiàn)設(shè)計(jì)圖我們會嵌套很多的Center和Padding,將他們與真正起作用的UI分離開,有利于我們第一時間找到目標(biāo)Widget:

    class ActionRow extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // 這里看起來非常清晰,我們就不需要繼續(xù)抽離變量了
        Widget left = Container(
          padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                "Title",
                style: TextStyle(fontSize: 16),
              ),
              Container(
                padding: EdgeInsets.only(top: 4),
                child: Text(
                  "Desc",
                  style: TextStyle(fontSize: 12),
                ),
              ),
            ],
          ),
        );
        Widget right = Row(
          children: [
            Container(
              padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
              child: MaterialButton(
                color: Colors.orange,
                child: Text("Edit"),
                onPressed: () {
                  print("Do something here");
                },
              ),
            ),
            Container(
              padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
              child: MaterialButton(
                color: Colors.red,
                child: Text("Delete"),
                onPressed: () {
                  print("Do something here");
                },
              ),
            ),
          ],
        );
        // 定義變量
        Widget row = Row(
          children: [
            Expanded(
              child: left,
            ),
            right,
          ],
        );
        // 然后在外面嵌套修飾的Container,注意,這里把row嵌套給了自己
        row = Container(
          color: Colors.white,
          margin: EdgeInsets.symmetric(vertical: 1),
          padding: EdgeInsets.symmetric(horizontal: 20),
          child: row,
        );
        // 我突然覺得這一層Widget暫時不需要,使用注釋就可以將其去掉
        // 如果這里是嵌套的寫法,是不能快速注釋一個Widget的
        // row = AnimatedOpacity(
        //   opacity: 1,
        //   duration: Duration(milliseconds: 800),
        //   child: row,
        // );
        return row;
      }
    }
    反復(fù)利用變量完成條件渲染

    有時候,在數(shù)據(jù)不同時,我們希望組件按不同的方式嵌套。將組件寫成一整坨當(dāng)然做不到如此靈活,從google的AppBar的源碼中,我學(xué)習(xí)了一套寫法,通過反復(fù)利用同一個Widget,優(yōu)雅的處理了條件渲染的問題。

    在這個例子里,我們希望做到一個效果,如果沒有傳入onEdit與onDelete方法,就不渲染右邊的部分,應(yīng)該如何寫呢?這個時候,嵌套任何組件都顯得復(fù)雜,我們只需要一個if就搞定了。

    // 現(xiàn)在看起來就好多啦
    class ActionRow extends StatelessWidget {
      final String title;
      final String desc;
      final VoidCallback onEdit;
      final VoidCallback onDelete;
      // 如上文所述,這里是自動生成的,然后添加一下默認(rèn)值
      const ActionRow({
        Key key,
        this.title: "title",
        this.desc: "desc",
        this.onEdit,
        this.onDelete,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        Widget left = Container(
          padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: TextStyle(fontSize: 16),
              ),
              Container(
                padding: EdgeInsets.only(top: 4),
                child: Text(
                  desc,
                  style: TextStyle(fontSize: 12),
                ),
              ),
            ],
          ),
        );
        
        Widget right = Container(
          alignment: Alignment.center,
          child: Text("No Function Here"),
        );
        // 只有傳入方法,右邊才會出現(xiàn)按鈕
        if (onEdit != null || onDelete != null) {
          right = Row(
            children: [
              Container(
                padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
                child: MaterialButton(
                  color: Colors.orange,
                  child: Text("Edit"),
                  onPressed: onEdit ?? () {},
                ),
              ),
              Container(
                padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
                child: MaterialButton(
                  color: Colors.red,
                  child: Text("Delete"),
                  onPressed: onDelete ?? () {},
                ),
              ),
            ],
          );
        }
        Widget row = Row(
          children: [
            Expanded(
              child: left,
            ),
            right,
          ],
        );
        row = Container(
          color: Colors.white,
          margin: EdgeInsets.symmetric(vertical: 1),
          padding: EdgeInsets.symmetric(horizontal: 20),
          child: row,
        );
        return row;
      }
    }
    提取組件——Stateful與Stateless

    很顯然上面的代碼屬于比較簡單的UI代碼,我們通常會把代碼寫的更大更復(fù)雜,這時候抽取組件就十分有必要,在上面的代碼中,我們覺得left還是有點(diǎn)復(fù)雜的,試著把它抽出來,作為一個StatelessWidget:

    想想:為什么不是StatefulWidget

    這一步也有快捷操作哦:

    抽離后的代碼:

    class ActionRow extends StatelessWidget {
      final String title;
      final String desc;
      final VoidCallback onEdit;
      final VoidCallback onDelete;
    
      const ActionRow({
        Key key,
        this.title: "title",
        this.desc: "desc",
        this.onEdit,
        this.onDelete,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // 這個就很少了
        Widget left = TextGroup(title: title, desc: desc);
        Widget right = Container(
          alignment: Alignment.center,
          child: Text("No Function Here"),
        );
        if (onEdit != null || onDelete != null) {
          right = Row(
            children: [
              Container(
                padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
                child: MaterialButton(
                  color: Colors.orange,
                  child: Text("Edit"),
                  onPressed: onEdit ?? () {},
                ),
              ),
              Container(
                padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
                child: MaterialButton(
                  color: Colors.red,
                  child: Text("Delete"),
                  onPressed: onDelete ?? () {},
                ),
              ),
            ],
          );
        }
    
        Widget row = Row(
          children: [
            Expanded(
              child: left,
            ),
            right,
          ],
        );
        row = Container(
          color: Colors.white,
          margin: EdgeInsets.symmetric(vertical: 1),
          padding: EdgeInsets.symmetric(horizontal: 20),
          child: row,
        );
        // row = AnimatedOpacity(
        //   opacity: 1,
        //   duration: Duration(milliseconds: 800),
        //   child: row,
        // );
        return row;
      }
    }
    
    // 沒必要優(yōu)化抽離后的小Widget,畢竟只需要知道他負(fù)責(zé)顯示兩行字就好了
    // 看上去代碼很多,但是都是自動生成的
    class TextGroup extends StatelessWidget {
      const TextGroup({
        Key key,
        @required this.title,
        @required this.desc,
      }) : super(key: key);
    
      final String title;
      final String desc;
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: TextStyle(fontSize: 16),
              ),
              Container(
                padding: EdgeInsets.only(top: 4),
                child: Text(
                  desc,
                  style: TextStyle(fontSize: 12),
                ),
              ),
            ],
          ),
        );
      }
    }

    如此一來我們的優(yōu)化就完成了,對比一下代碼,是不是看起來更好了呢?

    優(yōu)化完成,看看縮略圖:

    優(yōu)化前:

    優(yōu)化后:

    誤區(qū)

    很多開發(fā)者會有如下誤區(qū)。實(shí)際上,Google的部分UI源碼也存在如下這些問題,導(dǎo)致閱讀困難,但是有部分官方Widget的代碼質(zhì)量明顯更好,我們當(dāng)然可以學(xué)習(xí)更好的寫法。

    在編寫UI代碼時,請避免如下行為:

    使用function來創(chuàng)建Widget

    不必使用function來創(chuàng)建Widget,你應(yīng)當(dāng)把組件提取成StatelessWidget,然后將屬性或事件傳遞給這個Widget

    使用function的問題是,你可以在function中向Widget傳遞閉包,該閉包包含了當(dāng)前的作用域,卻又不在build方法中,同時你也可以在function中做其他無關(guān)的事情。

    所以當(dāng)我們過一段時間回頭閱讀代碼的時候,build中夾雜的function顯得非常的混亂不堪,沒有條理,UI應(yīng)當(dāng)是聚合在一起的,而數(shù)據(jù)與事件,應(yīng)當(dāng)與UI分離開來。如此才可以閱讀一次build方法,就基本理解當(dāng)前Widget的功能與目的。

    // function創(chuàng)建Widget可能會破壞Widget樹的可讀性
    class ActionRow extends StatelessWidget {
      final String title;
      final String desc;
      final VoidCallback onEdit;
      final VoidCallback onDelete;
    
      const ActionRow({
        Key key,
        this.title: "title",
        this.desc: "desc",
        this.onEdit,
        this.onDelete,
      }) : super(key: key);
    
      Widget buildEditButton() {
        return Container(
          padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
          child: MaterialButton(
            color: Colors.orange,
            child: Text("Edit"),
            onPressed: onEdit ?? () {},
          ),
        );
      }
    
      Widget buildDeleteButton() {
        return Container(
          padding: EdgeInsets.fromLTRB(6, 8, 8, 8),
          child: MaterialButton(
            color: Colors.red,
            child: Text("Delete"),
            onPressed: onDelete ?? () {},
          ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        // Widget left = TextGroup(title: title, desc: desc);
        Widget right = Container(
          alignment: Alignment.center,
          child: Text("No Function Here"),
        );
        if (onEdit != null || onDelete != null) {
          // 本來這里要傳入onDelete和onEdit的,
          // 但是現(xiàn)在這兩個屬性根本就不在build方法里出現(xiàn)(他們?nèi)ツ膬毫耍浚?      // 所以使用function來build組件可能會丟失一些關(guān)鍵信息,打斷代碼閱讀的順序。
          Widget editButton = buildEditButton();
          Widget deleteButton = buildDeleteButton();
    
          right = Row(
            children: [
              editButton,
              deleteButton,
            ],
          );
        }
        Widget row = Row(
          children: [
            // Expanded(
              // child: left,
            // ),
            right,
          ],
        );
        row = Container(
          color: Colors.white,
          margin: EdgeInsets.symmetric(vertical: 1),
          padding: EdgeInsets.symmetric(horizontal: 20),
          child: row,
        );
        return row;
      }
    }

    這個當(dāng)然不是強(qiáng)制的,甚至不少Google的例子也采用這種寫法,但是通過閱讀大量的源碼來進(jìn)行對比,這種寫法是很難通順閱讀的,總是需要在不同的function中切來切去,屬性引用沒有任何章法可言。

    StatelessWidget會強(qiáng)制所有屬性都是final的,這意味著,你必須把可變的屬性寫在build方法里(而不是其他地方),大多數(shù)時候,這非常有利于代碼閱讀。

    因?yàn)?b>final的特性,你也沒機(jī)會把變量寫到其他地方了,這樣看起來更整潔,畢竟整個頁面的數(shù)據(jù)通常也只有那么幾個。
    寫太多StatefulWidget

    這里其實(shí)說的是,不要嵌套很多StatefulWidget,事實(shí)上大部分Widget都可以是Stateless的:例如官方的Switch組件,居然也是Stateless的。通常按照我們的經(jīng)驗(yàn),Switch似乎需要維護(hù)自己的開關(guān)狀態(tài),在Flutter實(shí)際應(yīng)用中,并不需要如此,任何狀態(tài)都可以交給父組件管理,從而減少一個StatefulWidget,也就減少了一個State,大大減少了UI代碼的復(fù)雜程度。

    從我目前的經(jīng)驗(yàn)來看,只有很少部分Widget需要寫成Stateful的:

    頁面,推薦每一個返回ScaffoldWidget都寫成Stateful

    需要在initState中觸發(fā)方法,例如從網(wǎng)絡(luò)請求數(shù)據(jù),開啟藍(lán)牙搜索等異步操作。

    需要維護(hù)自己的動畫狀態(tài)的。

    同時StatefulWidget不應(yīng)緊密嵌套在一起,只需要把數(shù)據(jù)都放在上一級的state里就好,維護(hù)state實(shí)際上會多出非常多的無用代碼,過多嵌套會直接導(dǎo)致代碼混亂不堪。

    總結(jié)

    作者:馬嘉倫
    日期:2019/07/14
    平臺:Segmentfault獨(dú)家,勿轉(zhuǎn)載

    我的其他文章:
    【開發(fā)經(jīng)驗(yàn)】淺談flutter的優(yōu)點(diǎn)與缺點(diǎn)
    【Flutter工具】fmaker:自動生成倍率切圖/自動更換App圖標(biāo)
    【開發(fā)經(jīng)驗(yàn)】在Flutter中使用dart的單例模式

    本文是對Flutter的一種編碼風(fēng)格的概括,主要的意義在于減少代碼嵌套層數(shù),增強(qiáng)代碼可讀性。本文大部分經(jīng)驗(yàn)其實(shí)來自Google自己的組件源碼,是通過對比大量源碼得出的一個較優(yōu)寫法,如果你對上述觀點(diǎn),建議,代碼,風(fēng)格有疑問或者發(fā)現(xiàn)了文章中的問題,請直接留下你的評論,我會直接在評論中進(jìn)行回復(fù)。

    本文禁止任何轉(zhuǎn)載,需轉(zhuǎn)載授權(quán)可直接聯(lián)系我

    文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/105633.html

    相關(guān)文章

    • flutter筆記3:基礎(chǔ)語法、框架、控件

      摘要:是啥是谷歌推出的一套視覺設(shè)計(jì)語言。比如有的可以換皮膚,而每一套皮膚就是一種設(shè)計(jì)語言,有古典風(fēng)呀炫酷風(fēng)呀極簡風(fēng)呀神馬的,而就是谷歌風(fēng),有興趣的同學(xué)可以學(xué)習(xí)了解一下官方原版和中文翻譯版,這是每一個產(chǎn)品經(jīng)理的必修教材。 flutter環(huán)境和運(yùn)行環(huán)境搭建好之后,可以開始擼碼了,然而當(dāng)你打開VScode,在打開項(xiàng)目文件夾后,擺在你面前的是main.dart被打開的樣子,里面七七八八的已經(jīng)寫好了一...

      draveness 評論0 收藏0
    • flutter筆記4:使用material原生控件開發(fā)一個APP

      摘要:體驗(yàn)熱更新帶來的開發(fā)周期加速。學(xué)會使用有狀態(tài)控件,增強(qiáng)了應(yīng)用的交互。使用和創(chuàng)建了一個支持懶加載的無限滾動列表。了解如何使用主題更改應(yīng)用的外觀。 接著上一篇,我們做一個這樣的APP:showImg(https://segmentfault.com/img/remote/1460000013672700); 開始之前,我發(fā)現(xiàn)了一個好玩的東西,每次我們在終端中輸入命令: flutter ru...

      lifefriend_007 評論0 收藏0
    • flutter的入門實(shí)踐到可開發(fā)

      摘要:繼上一篇關(guān)于的介紹,是仿照微信界面,因?yàn)樽鳛榍岸碎_發(fā),有一定的基礎(chǔ),所有寫起來,也不是很吃力。班門弄斧之作,若有大神見到,敬請指教,有不對不合理之處,敬請指出我是邇伶貳環(huán)境準(zhǔn)備以系統(tǒng)為例。 flutter的入門記錄 0.前言: flutter 的入門demo 已經(jīng)寫好一個星期了,只不過一直都沒有整理出博客來。收拾好心情,來整理一下。繼上一篇關(guān)于react-native-wx的介紹,是仿...

      _DangJin 評論0 收藏0
    • 用前端 最舒服的躺姿 "搞定" Flutter (組件篇)

      摘要:是谷歌的移動框架,可以快速在和上構(gòu)建高質(zhì)量的原生用戶界面。在全世界好了這些,大家早就知道了,來點(diǎn)實(shí)在的話說隔壁師兄,閑魚是最早一批與谷歌展開合作,并在重要的商品詳情頁中使用技術(shù)上線的。一切皆來自的組件皆來自。是狀態(tài)不可變的稱為無狀態(tài)。 前言 要說2018年最火的跨端技術(shù),當(dāng)屬于 Flutter 莫屬,應(yīng)該沒人質(zhì)疑吧。一個新的技術(shù)的趨勢,最明顯的特征,就是它一定想把前浪拍死在沙灘上。這個...

      LMou 評論0 收藏0

    發(fā)表評論

    0條評論

    最新活動
    閱讀需要支付1元查看
    <