摘要:體驗熱更新帶來的開發(fā)周期加速。學(xué)會使用有狀態(tài)控件,增強了應(yīng)用的交互。使用和創(chuàng)建了一個支持懶加載的無限滾動列表。了解如何使用主題更改應(yīng)用的外觀。
接著上一篇,我們做一個這樣的APP:
開始之前,我發(fā)現(xiàn)了一個好玩的東西,每次我們在終端中輸入命令:
flutter run
終端里會有這個東西:
按照上圖所示,我們的進(jìn)入這個網(wǎng)頁看看是個啥:
好高大上的感覺,具體是干嘛的,我也不知道,有興趣的同學(xué)可以點進(jìn)去把玩把玩,以后搞明白了再更吧。
第一步先創(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{ @override final _suggestions = []; //用于保存隨機字符串詞組,注意這是一個數(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),免去了先聲明再使用的麻煩,并且可以直接對對象的屬性進(jìn)行配置,通過build()一層層回調(diào),代碼簡潔不少,而代碼中使用到的material內(nèi)置控件,我就不一一介紹了,有興趣的同學(xué)請參考material官方API,注意material控件索引在頁面右邊的列表,別找到左邊去了。
注意,遇到這種聲明類屬性的格式:_[變量名]。按官方的意思是,如果變量名的前綴有_下劃線,表示強制轉(zhuǎn)換為私有變量,相當(dāng)于聲明變量為private,但使用這個變量的時候,還是要將下劃線進(jìn)行完整的書寫。
保存代碼后運行一下,可以看到APP變成了這個樣子:
向下滾動試試,發(fā)現(xiàn)可以一直滾下去~
第二步向列表里加個_收藏_標(biāo)簽按鈕,使每行可以標(biāo)記收藏或取消收藏。這個_收藏_標(biāo)簽就是狀態(tài),既然要修改狀態(tài),肯定要到state中進(jìn)行啦。
到對象RandomWordsState中定義一個對象,用于存儲標(biāo)記。為什么要多帶帶存儲標(biāo)記呢?因為這樣就不需要往行對象(ListTile)中添加標(biāo)記,降低了對象的復(fù)雜度。如下:
class RandomWordsState extends State{ final _suggestions = []; final _saved = new Set (); //新加這一句 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ù)戳這個行,還自動配有動畫效果:
加入一個導(dǎo)航欄樣式的堆棧。
先往主頁面控件(AppBar)中添加一個可以進(jìn)入收藏列表的入口:
class RandomWordsState extends State{ ... @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("Startup Name Generator"), //為AppBar對象的actions屬性添加一個IconButton對象,actions屬性值可以是Widget類型的數(shù)組 actions: [ 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{ ... void _pushSaved() { } }
這時候可以看到右上角多了3個圖標(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ù),否則進(jìn)入收藏夾直接崩潰 return new Scaffold( appBar: new AppBar( title: new Text("收藏的列表項目"), ), body: new ListView(children: divided), //直接將準(zhǔn)備好的ListTile塞入其中,完成內(nèi)容填充 ); }, ), ); }
保存代碼后,刷新APP,如圖:
如上圖所示,紅色的箭頭表示點擊按鈕后頁面的切換,綠色箭頭表示收藏夾的值的對照,有沒有發(fā)現(xiàn)我們并沒有寫返回主頁按鈕的代碼,這個返回按鈕從哪來的呢?是由Navigator對象自動生成的,并且自動指向到主頁面的路由,不過遺憾的是,沒有加入返回手勢的支持,如有需要,還得自己寫,具體怎么寫,跟著我的筆記走吧,我現(xiàn)在也不知道。
大家注意看主頁列表和收藏夾列表的區(qū)別,兩者都是列表,都是使用的ListView和ListTile對象,但實現(xiàn)的方式完全不同,插入行對象和分割線的差異很有意思,有興趣的同學(xué)可以自行修改下代碼,看看能不能將兩種列表的構(gòu)建方法對調(diào)一下,參考官方資料ListView和ListTile
第四步變更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)格:
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ā)上面大搞特搞一番。
當(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)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93363.html
摘要:是啥是谷歌推出的一套視覺設(shè)計語言。比如有的可以換皮膚,而每一套皮膚就是一種設(shè)計語言,有古典風(fēng)呀炫酷風(fēng)呀極簡風(fēng)呀神馬的,而就是谷歌風(fēng),有興趣的同學(xué)可以學(xué)習(xí)了解一下官方原版和中文翻譯版,這是每一個產(chǎn)品經(jīng)理的必修教材。 flutter環(huán)境和運行環(huán)境搭建好之后,可以開始擼碼了,然而當(dāng)你打開VScode,在打開項目文件夾后,擺在你面前的是main.dart被打開的樣子,里面七七八八的已經(jīng)寫好了一...
摘要:當(dāng)發(fā)送按鈕觸發(fā)事件后調(diào)用函數(shù),在中執(zhí)行了方法,此時根據(jù)中的變量變更重新渲染對象,然后大家就可以看到消息記錄框中底部新增了一行消息。 熟悉了flutter的各種控件和相互嵌套的代碼結(jié)構(gòu)后,可以再加深一點難度:加入動畫特效。 雖然flutter的內(nèi)置Metarial控件已經(jīng)封裝好了符合其設(shè)計語言的動畫特效,使開發(fā)者節(jié)約了不少視覺處理上的精力,比如點擊或長按listTile控件時自帶水波紋動...
摘要:側(cè)邊欄我們先圖解一下側(cè)邊欄的結(jié)構(gòu)整個側(cè)邊欄主從上到下按區(qū)塊分別放置了賬號和若干功能項分割線的列表,很容易想到使用布局控件。賬號信息區(qū)域中有賬號頭像粉絲頭像賬號文字信息和背景圖,這塊我們可以使用控件庫的控件實現(xiàn)。 經(jīng)過2周的學(xué)習(xí),看過筆記1-8的小伙伴們已經(jīng)有不少開始自己寫APP了,我也按耐不住這股熱情,想要自己開發(fā)個APP玩玩,so,從本篇起,仿造一個APP,項目從0開始,每篇增加一些...
摘要:布局控件不會直接呈現(xiàn)內(nèi)容,可看作承載可視控件的容器。布局控件也是可以模擬顯示的,通常用于調(diào)試布局樣式時用到的網(wǎng)格線標(biāo)尺動畫幀等。但是當(dāng)頁面內(nèi)容需要超出屏幕尺寸時,就用和代替。 不知不覺已經(jīng)到了第7篇,然而很多萌新玩家可能還是不知道如何堆砌控件,像用CSS一樣搭出漂亮的APP界面,我也一樣,紅紅火火恍恍惚惚,直到今天含淚讀完Flutter布局基礎(chǔ),仿佛打開了一個全新的世界。 基本概念 在...
摘要:注釋處的方法是程序的入口,使用了符號,這是中單行函數(shù)或方法的簡寫,等價于如下代碼方法是框架的入口,如果不返回方法,那么執(zhí)行的是一個控制臺應(yīng)用。 本文首發(fā)于微信公眾號「劉望舒」 前言 最近的Google I/O大會上,F(xiàn)lutter1.5 開始支持移動、Web、桌面和嵌入式設(shè)備,從不溫不火的sky一直進(jìn)化到如今熱門的Flutter,F(xiàn)lutter的發(fā)展已經(jīng)超出很多人的想象。我對跨平臺技術(shù)一...
閱讀 3947·2021-10-19 13:23
閱讀 2326·2021-09-09 11:37
閱讀 2507·2019-08-29 15:20
閱讀 3407·2019-08-29 11:08
閱讀 1661·2019-08-26 18:27
閱讀 1764·2019-08-23 12:20
閱讀 3028·2019-08-23 11:54
閱讀 2544·2019-08-22 15:19