flutter筆記4:使用material原生控件開發(fā)一個APP

接著上一篇撩满,我們做一個這樣的APP:


flutter官方案例

開始之前葵第,我發(fā)現(xiàn)了一個好玩的東西圣拄,每次我們在終端中輸入命令:

flutter run

終端里會有這個東西:


APP調(diào)試器

按照上圖所示嘴秸,我們的進入這個網(wǎng)頁看看是個啥:


調(diào)試器主頁

好高大上的感覺,具體是干嘛的庇谆,我也不知道岳掐,有興趣的同學(xué)可以點進去把玩把玩,以后搞明白了再更吧饭耳。

由于Flutter官方的更新串述,使用外部包需要到文件管理的配置文件中添加依賴的項目,所以需要到項目根目錄下的pubspec.yaml文件中添加如下代碼:

dependencies:
  flutter:
  sdk: flutter

  cupertino_icons: ^0.1.0
  english_words: ^3.1.0    //將本行代碼添加到示例中的位置

第一步

先創(chuàng)建一個列表寞肖。

回到main.dart中纲酗,把原來的代碼全部清空衰腌,復(fù)制以下代碼:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  //構(gòu)建一個容器
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      home: new RandomWords(),//定義子組件為有狀態(tài)控件RandomWords類的實例
    );
  }
}

//定義有狀態(tài)控件RandomWords類
class RandomWords extends StatefulWidget {
  @override
  createState() => new RandomWordsState();//創(chuàng)建有狀態(tài)控件RandomWords的狀態(tài)類實例:RandomWordsState
}

//定義狀態(tài)類RandomWordsState
class RandomWordsState extends State<RandomWords> {
  @override
  final _suggestions = <WordPair>[];  //用于保存隨機字符串詞組,注意這是一個數(shù)組變量
  final _biggerFont = const TextStyle(fontSize: 18.0);   //用于標(biāo)識字符串的樣式

  //構(gòu)建一個腳手架觅赊,里面塞入前面定義好的_buildSuggestions類
  Widget build(BuildContext context) {
    return new Scaffold (
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
      ),
      body: _buildSuggestions(), 
    );
  }

  //定義一個子控件右蕊,這個控件就是放置隨機字符串詞組的列表
  Widget _buildSuggestions() {
    return new ListView.builder(  //ListView(列表視圖)是material.dart中的基礎(chǔ)控件
      padding: const EdgeInsets.all(16.0),  //padding(內(nèi)邊距)是ListView的屬性,配置其屬性值
      //通過ListView自帶的函數(shù)itemBuilder茉兰,向ListView中塞入行尤泽,變量 i 是從0開始計數(shù)的行號
      //此函數(shù)會自動循環(huán)并計數(shù),咋結(jié)束的我也不知道规脸,走著瞧咯
      itemBuilder: (context, i) {
        if (i.isOdd) return new Divider();//奇數(shù)行塞入分割線對象
        final index = i ~/ 2;  //當(dāng)前行號除以2取整坯约,得到的值就是_suggestions數(shù)組項索引號
        // 如果計算得到的數(shù)組項索引號超出了_suggestions數(shù)組的長度,那_suggestions就再生10個隨機組合的字符串詞組
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);//把這個數(shù)據(jù)項塞入ListView中
      }
    );
  }

  //定義的_suggestions數(shù)組項屬性
  Widget _buildRow(WordPair pair) {
    //ListTile和Text都是material.dart中的基礎(chǔ)控件
    return new ListTile(
      title: new Text(
        pair.asPascalCase,  //使用駝峰樣式
        style: _biggerFont,
      ),
    );
  }
    
}

看到這里莫鸭,是不是有點暈闹丐,各種聲明、各種引用被因,還有回調(diào)卿拴,把上面的代碼,用下面的圖解析下結(jié)構(gòu)梨与,看看到底怎么個情況:


代碼圖解

可以發(fā)現(xiàn)在StatelessWidget和State類中都有一個Widget類型的函數(shù)build()堕花,感覺有點像類的初始化方法construct(),而RandomWords對象為什么只使用了createState()卻沒有build()粥鞋,我也不知道缘挽,走著瞧吧。當(dāng)對象實例化的時候呻粹,首先執(zhí)行Widget build(BuildContext context){}函數(shù)壕曼,函數(shù)中BuildContext類型的參數(shù)context,到目前為止還不知道干嘛用的等浊,暫且忽略其意義吧腮郊。

material類型的子控件都通過回調(diào)函數(shù)的方式創(chuàng)建,我讀起來有些不習(xí)慣筹燕,但通過回調(diào)轧飞,免去了先聲明再使用的麻煩,并且可以直接對對象的屬性進行配置撒踪,通過build()一層層回調(diào)踪少,代碼簡潔不少,而代碼中使用到的material內(nèi)置控件糠涛,我就不一一介紹了援奢,有興趣的同學(xué)請參考material官方API,注意material控件索引在頁面右邊的列表忍捡,別找到左邊去了集漾。

注意切黔,遇到這種聲明類屬性的格式:_[變量名]。按官方的意思是具篇,如果變量名的前綴有_下劃線纬霞,表示強制轉(zhuǎn)換為私有變量,相當(dāng)于聲明變量為private驱显,但使用這個變量的時候诗芜,還是要將下劃線進行完整的書寫。

保存代碼后運行一下埃疫,可以看到APP變成了這個樣子:


無限滾動的列表

向下滾動試試伏恐,發(fā)現(xiàn)可以一直滾下去~

第二步

向列表里加個收藏標(biāo)簽按鈕,使每行可以標(biāo)記收藏或取消收藏栓霜。這個收藏標(biāo)簽就是狀態(tài)翠桦,既然要修改狀態(tài),肯定要到state中進行啦胳蛮。

到對象RandomWordsState中定義一個對象销凑,用于存儲標(biāo)記。為什么要單獨存儲標(biāo)記呢仅炊?因為這樣就不需要往行對象(ListTile)中添加標(biāo)記斗幼,降低了對象的復(fù)雜度。如下:

class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];

  final _saved = new Set<WordPair>();  //新加這一句

  final _biggerFont = const TextStyle(fontSize: 18.0);
  ...
}

為什么存儲標(biāo)記的是對象而不是一個數(shù)組呢抚垄?大概是想順便教我們使用一下Set對象吧孟岛,據(jù)說Set對象不允許有重復(fù)的項目,方便后面模擬堆棧的效果督勺,非常適合這種場景。然后我們到每個行添加一個標(biāo)記收藏的控件:

Widget _buildRow(WordPair pair) {
    //定義一個布爾變量斤贰,用于判斷行控件ListTile是否被標(biāo)記為收藏
    final alreadySaved = _saved.contains(pair);
    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
      //安放圖標(biāo)控件
      trailing: new Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      //定義點擊事件智哀,控制圖標(biāo)的樣式的切換
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
    },
    );
  }

注意,在onTap事件中荧恍,使用到了setState()方法(用過vue或react的玩家是不是很熟悉呀)瓷叫,在這個方法里修改變量值,即可觸發(fā)state對象執(zhí)行build()方法重繪對象送巡。這里每次變更對象_saved后摹菠,都會重繪ListTile對象,而靜態(tài)變量alreadySaved也被重新定義骗爆,因此不用擔(dān)心alreadySaved值不被更新的問題次氨,如果去除final關(guān)鍵字,Dart語法會報錯摘投,還請路過大神點撥一下原因煮寡。

保存代碼后虹蓄,可以看到APP刷新了,每一行都添加了一個心型圖標(biāo)幸撕,反復(fù)戳這個行薇组,還自動配有動畫效果:


實現(xiàn)標(biāo)記按鈕

第三步

加入一個導(dǎo)航欄樣式的堆棧。

先往主頁面控件(AppBar)中添加一個可以進入收藏列表的入口:

class RandomWordsState extends State<RandomWords> {
  ...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
        //為AppBar對象的actions屬性添加一個IconButton對象坐儿,actions屬性值可以是Widget類型的數(shù)組
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved), 
          //可以試試添加這兩行后APP上有什么效果
          new IconButton(icon: new Icon(Icons.add), onPressed: _pushSaved), 
          new IconButton(icon: new Icon(Icons.create), onPressed: _pushSaved), 
        ],
      ),
      body: _buildSuggestions(),
    );
  }
  ...
}

由于沒有定義_pushSaved函數(shù)律胀,直接復(fù)制上面注釋說明的代碼會報錯,因此貌矿,定義一個void類型的函數(shù)_pushSaved:

class RandomWordsState extends State<RandomWords> {
  ...
  void _pushSaved() {
  }
}

這時候可以看到右上角多了3個圖標(biāo)炭菌,如圖:

創(chuàng)建收藏夾入口圖標(biāo)

然后我們往_pushSaved()函數(shù)中添加代碼,讓收藏夾玩起來:

void _pushSaved() {
    //創(chuàng)建導(dǎo)航欄控件Navigator站叼,然后往里面塞入MaterialPageRoute控件
    Navigator.of(context).push(
      new MaterialPageRoute(
        builder: (context) {
          //通過遍歷_saved對象娃兽,獲取已收藏的行對象
          final tiles = _saved.map(
                (pair) {
              return new ListTile(
                title: new Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );
          //函數(shù)的的鏈?zhǔn)秸{(diào)用,獲取到添加好分割線的ListTile控件
          final divided = ListTile
              .divideTiles(            //divideTiles()函數(shù)尽楔,向每個tile間隔插入一個1像素寬的邊框
                context: context, 
                tiles: tiles,
              )
              .toList();  //不要漏掉這個函數(shù)投储,否則進入收藏夾直接崩潰
          return new Scaffold(
            appBar: new AppBar(
              title: new Text('收藏的列表項目'),
            ),
            body: new ListView(children: divided),  //直接將準(zhǔn)備好的ListTile塞入其中,完成內(nèi)容填充
          );
        },
      ),
    );
  }

保存代碼后阔馋,刷新APP玛荞,如圖:


兩個頁面相互跳轉(zhuǎn)

如上圖所示,紅色的箭頭表示點擊按鈕后頁面的切換呕寝,綠色箭頭表示收藏夾的值的對照勋眯,有沒有發(fā)現(xiàn)我們并沒有寫返回主頁按鈕的代碼,這個返回按鈕從哪來的呢下梢?是由Navigator對象自動生成的客蹋,并且自動指向到主頁面的路由,不過遺憾的是孽江,沒有加入返回手勢的支持讶坯,如有需要,還得自己寫岗屏,具體怎么寫辆琅,跟著我的筆記走吧,我現(xiàn)在也不知道这刷。

大家注意看主頁列表和收藏夾列表的區(qū)別婉烟,兩者都是列表,都是使用的ListView和ListTile對象暇屋,但實現(xiàn)的方式完全不同似袁,插入行對象和分割線的差異很有意思,有興趣的同學(xué)可以自行修改下代碼,看看能不能將兩種列表的構(gòu)建方法對調(diào)一下叔营,參考官方資料ListViewListTile

第四步

變更UI主題風(fēng)格屋彪。

這一步超級簡單,往MaterialApp對象里添加theme屬性值即可:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      //添加theme屬性值绒尊,塞入ThemeData對象
      theme: new ThemeData(
        primaryColor: Colors.white,
      ),
      home: new RandomWords(),
    );
  }
}

再保存畜挥,刷新APP試試,主題變成了白色風(fēng)格:

變更風(fēng)格

ThemeData()方法本身提供了很多配色方案婴谱,玩家可以參考ThemeData官方說明蟹但,掌握其強大功能。沒想到變更主題如此輕松谭羔,在當(dāng)前APP界越來越追求視覺體驗升級的趨勢下华糖,使用flutter開發(fā)APP的玩家應(yīng)該欣慰不少吧~

好勒,這次官方萌新課程的搬運就到這里瘟裸,我是真的超喜歡這個萌新課程客叉,連課程總結(jié)都幫我寫好了:

  • 從頭開始創(chuàng)建一個Flutter應(yīng)用程序。
  • 書寫了Dart語言的代碼话告。
  • 學(xué)會了調(diào)用外部的第三方庫兼搏。
  • 體驗熱更新帶來的開發(fā)周期加速。
  • 學(xué)會使用有狀態(tài)控件沙郭,增強了應(yīng)用的交互佛呻。
  • 使用ListView和ListTiles創(chuàng)建了一個支持懶加載的無限滾動列表。
  • 創(chuàng)建了一組路由并實現(xiàn)了主路由和新路由之間的跳轉(zhuǎn)邏輯病线。
  • 了解如何使用主題更改應(yīng)用UI的外觀吓著。

自我總結(jié)一下,flutter是一個控件高度集成化的開發(fā)平臺送挑,控件的完整度極高灰羽,控件之間的交互實現(xiàn)也傾向于傻瓜化慰丛,比如自動生成返回按鈕捕虽、主題風(fēng)格全局可控黑滴。只要把握好狀態(tài)值和控件之間的嵌套關(guān)系,開發(fā)者幾乎不需要單獨敲代碼實現(xiàn)跳轉(zhuǎn)邏輯赡突,代碼簡直不要太簡潔,不知不覺間就寫好了一個APP区赵。而VScode中的Dart Code插件也實在太好用惭缰,代碼提示、函數(shù)用法和參數(shù)都有詳盡的說明笼才,看得出谷歌拿出了十足的誠意要在跨平臺開發(fā)上面大搞特搞一番漱受。

Dart Code插件提示

當(dāng)然了,滿屏幕的回調(diào)函數(shù)讓我這種編程思維還停留在C語言時代的菜鳥來說,扶墻~ 頭有點暈昂羡,還需要點時間慢慢適應(yīng)一下下絮记,也由于我沒有那么深厚的技術(shù)功底,對這個教程的理解還比較有限虐先,可能有寫的不對或不好的地方怨愤,也歡迎大家指正,尤其我花了一天一夜寫了這篇稿也是蠻不容易了蛹批,有路過的高手不說兩句也是哪啥了是吧撰洗。當(dāng)然,我有空的時候抓緊讀一讀Dart 語法基礎(chǔ)官方原版腐芍,有了新的發(fā)現(xiàn)也會寫稿分享出來差导。

好啦就寫到這里,廣告時間猪勇,對flutter感興趣的小伙伴可以關(guān)注我设褐,歡迎大家到Flutter圈子中投稿,也可以聯(lián)系管理員加入我們的flutter微信群嗨聊泣刹,謝謝捧場~助析!
flutter 中文社區(qū)(官方QQ群:338252156)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市项玛,隨后出現(xiàn)的幾起案子貌笨,更是在濱河造成了極大的恐慌,老刑警劉巖襟沮,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锥惋,死亡現(xiàn)場離奇詭異,居然都是意外死亡开伏,警方通過查閱死者的電腦和手機膀跌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來固灵,“玉大人捅伤,你說我怎么就攤上這事∥撞#” “怎么了丛忆?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長仍秤。 經(jīng)常有香客問我熄诡,道長,這世上最難降的妖魔是什么诗力? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任凰浮,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘袜茧。我一直安慰自己菜拓,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布笛厦。 她就那樣靜靜地躺著纳鼎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪递递。 梳的紋絲不亂的頭發(fā)上喷橙,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音登舞,去河邊找鬼贰逾。 笑死,一個胖子當(dāng)著我的面吹牛菠秒,可吹牛的內(nèi)容都是我干的疙剑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼践叠,長吁一口氣:“原來是場噩夢啊……” “哼言缤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起禁灼,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤管挟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后弄捕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體僻孝,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年守谓,在試婚紗的時候發(fā)現(xiàn)自己被綠了穿铆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡斋荞,死狀恐怖荞雏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情平酿,我是刑警寧澤凤优,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蜈彼,受9級特大地震影響筑辨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柳刮,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一挖垛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秉颗,春花似錦痢毒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至菇怀,卻和暖如春凭舶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背爱沟。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工帅霜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呼伸。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓身冀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親括享。 傳聞我的和親對象是個殘疾皇子搂根,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容