flutter 2.1 Widget

1 Widget只是UI元素的一個(gè)配置數(shù)據(jù),并且一個(gè)Widget可以對(duì)應(yīng)多個(gè)Element
Widget實(shí)際上就是Element的配置數(shù)據(jù)复斥,Widget樹實(shí)際上是一個(gè)配置樹霉旗,而真正的UI渲染樹是由Element構(gòu)成召川;不過南缓,由于Element是通過Widget生成的,所以它們之間有對(duì)應(yīng)關(guān)系荧呐,在大多數(shù)場(chǎng)景汉形,我們可以寬泛地認(rèn)為Widget樹就是指UI控件樹或UI渲染樹。
一個(gè)Widget對(duì)象可以對(duì)應(yīng)多個(gè)Element對(duì)象坛增。這很好理解,根據(jù)同一份配置(Widget)薄腻,可以創(chuàng)建多個(gè)實(shí)例(Element)

2.1 StatelessWidget
StatelessElement 間接繼承自Element類收捣,與StatelessWidget相對(duì)應(yīng)(作為其配置數(shù)據(jù))。
StatelessWidget用于不需要維護(hù)狀態(tài)的場(chǎng)景庵楷,它通常在build方法中通過嵌套其它Widget來(lái)構(gòu)建UI罢艾,在構(gòu)建過程中會(huì)遞歸的構(gòu)建其嵌套的Widget楣颠。

2.2 Context
build方法有一個(gè)context參數(shù),它是BuildContext類的一個(gè)實(shí)例咐蚯,表示當(dāng)前widget在widget樹中的上下文童漩,每一個(gè)widget都會(huì)對(duì)應(yīng)一個(gè)context對(duì)象(因?yàn)槊恳粋€(gè)widget都是widget樹上的一個(gè)節(jié)點(diǎn))。實(shí)際上春锋,context是當(dāng)前widget在widget樹中位置中執(zhí)行”相關(guān)操作“的一個(gè)句柄矫膨,比如它提供了從當(dāng)前widget開始向上遍歷widget樹以及按照widget類型查找父級(jí)widget的方法

3 StatefulWidget
StatefulElement 間接繼承自Element類,與StatefulWidget相對(duì)應(yīng)(作為其配置數(shù)據(jù))期奔。StatefulElement中可能會(huì)多次調(diào)用createState()來(lái)創(chuàng)建狀態(tài)(State)對(duì)象侧馅。
createState() 用于創(chuàng)建和Stateful widget相關(guān)的狀態(tài),它在Stateful widget的生命周期中可能會(huì)被多次調(diào)用呐萌。例如馁痴,當(dāng)一個(gè)Stateful widget同時(shí)插入到widget樹的多個(gè)位置時(shí),F(xiàn)lutter framework就會(huì)調(diào)用該方法為每一個(gè)位置生成一個(gè)獨(dú)立的State實(shí)例肺孤,其實(shí)罗晕,本質(zhì)上就是一個(gè)StatefulElement對(duì)應(yīng)一個(gè)State實(shí)例

4.1 State
一個(gè)StatefulWidget類會(huì)對(duì)應(yīng)一個(gè)State類,State表示與其對(duì)應(yīng)的StatefulWidget要維護(hù)的狀態(tài)赠堵,State中的保存的狀態(tài)信息可以:
1.在widget 構(gòu)建時(shí)可以被同步讀取小渊。
2.在widget生命周期中可以被改變,當(dāng)State被改變時(shí)顾腊,可以手動(dòng)調(diào)用其setState()方法通知Flutter framework狀態(tài)發(fā)生改變粤铭,F(xiàn)lutter framework在收到消息后,會(huì)重新調(diào)用其build方法重新構(gòu)建widget樹杂靶,從而達(dá)到更新UI的目的梆惯。
State中有兩個(gè)常用屬性:
1.widget,它表示與該State實(shí)例關(guān)聯(lián)的widget實(shí)例吗垮,由Flutter framework動(dòng)態(tài)設(shè)置垛吗。注意,這種關(guān)聯(lián)并非永久的烁登,因?yàn)樵趹?yīng)用聲明周期中怯屉,UI樹上的某一個(gè)節(jié)點(diǎn)的widget實(shí)例在重新構(gòu)建時(shí)可能會(huì)變化,但State實(shí)例只會(huì)在第一次插入到樹中時(shí)被創(chuàng)建饵沧,當(dāng)在重新構(gòu)建時(shí)锨络,如果widget被修改了,F(xiàn)lutter framework會(huì)動(dòng)態(tài)設(shè)置State.widget為新的widget實(shí)例狼牺。
2.context羡儿。StatefulWidget對(duì)應(yīng)的BuildContext,作用同StatelessWidget的BuildContext是钥。

initState:當(dāng)Widget第一次插入到Widget樹時(shí)會(huì)被調(diào)用掠归,對(duì)于每一個(gè)State對(duì)象缅叠,F(xiàn)lutter framework只會(huì)調(diào)用一次該回調(diào),所以虏冻,通常在該回調(diào)中做一些一次性的操作肤粱,如狀態(tài)初始化、訂閱子樹的事件通知等厨相。不能在該回調(diào)中調(diào)用BuildContext.inheritFromWidgetOfExactType(該方法用于在Widget樹上獲取離當(dāng)前widget最近的一個(gè)父級(jí)InheritFromWidget领曼,關(guān)于InheritedWidget我們將在后面章節(jié)介紹),原因是在初始化完成后领铐,Widget樹中的InheritFromWidget也可能會(huì)發(fā)生變化悯森,所以正確的做法應(yīng)該在在build()方法或didChangeDependencies()中調(diào)用它。
didChangeDependencies():當(dāng)State對(duì)象的依賴發(fā)生變化時(shí)會(huì)被調(diào)用绪撵;例如:在之前build() 中包含了一個(gè)InheritedWidget瓢姻,然后在之后的build() 中InheritedWidget發(fā)生了變化,那么此時(shí)InheritedWidget的子widget的didChangeDependencies()回調(diào)都會(huì)被調(diào)用音诈。典型的場(chǎng)景是當(dāng)系統(tǒng)語(yǔ)言Locale或應(yīng)用主題改變時(shí)幻碱,F(xiàn)lutter framework會(huì)通知widget調(diào)用此回調(diào)。
build():此回調(diào)讀者現(xiàn)在應(yīng)該已經(jīng)相當(dāng)熟悉了细溅,它主要是用于構(gòu)建Widget子樹的褥傍,會(huì)在如下場(chǎng)景被調(diào)用:

在調(diào)用initState()之后。
在調(diào)用didUpdateWidget()之后喇聊。
在調(diào)用setState()之后恍风。
在調(diào)用didChangeDependencies()之后。
在State對(duì)象從樹中一個(gè)位置移除后(會(huì)調(diào)用deactivate)又重新插入到樹的其它位置之后誓篱。
reassemble():此回調(diào)是專門為了開發(fā)調(diào)試而提供的朋贬,在熱重載(hot reload)時(shí)會(huì)被調(diào)用,此回調(diào)在Release模式下永遠(yuǎn)不會(huì)被調(diào)用窜骄。
didUpdateWidget():在widget重新構(gòu)建時(shí)锦募,F(xiàn)lutter framework會(huì)調(diào)用Widget.canUpdate來(lái)檢測(cè)Widget樹中同一位置的新舊節(jié)點(diǎn),然后決定是否需要更新邻遏,如果Widget.canUpdate返回true則會(huì)調(diào)用此回調(diào)糠亩。正如之前所述,Widget.canUpdate會(huì)在新舊widget的key和runtimeType同時(shí)相等時(shí)會(huì)返回true准验,也就是說(shuō)在在新舊widget的key和runtimeType同時(shí)相等時(shí)didUpdateWidget()就會(huì)被調(diào)用赎线。
deactivate():當(dāng)State對(duì)象從樹中被移除時(shí),會(huì)調(diào)用此回調(diào)糊饱。在一些場(chǎng)景下垂寥,F(xiàn)lutter framework會(huì)將State對(duì)象重新插到樹中,如包含此State對(duì)象的子樹在樹的一個(gè)位置移動(dòng)到另一個(gè)位置時(shí)(可以通過GlobalKey來(lái)實(shí)現(xiàn))。如果移除后沒有重新插入到樹中則緊接著會(huì)調(diào)用dispose()方法矫废。
dispose():當(dāng)State對(duì)象從樹中被永久移除時(shí)調(diào)用;通常在此回調(diào)中釋放資源砰蠢。


image.png

為什么要將build方法放在State中蓖扑,而不是放在StatefulWidget中?
1.狀態(tài)訪問不便台舱。
試想一下律杠,如果我們的StatefulWidget有很多狀態(tài),而每次狀態(tài)改變都要調(diào)用build方法竞惋,由于狀態(tài)是保存在State中的柜去,如果build方法在StatefulWidget中,那么build方法和狀態(tài)分別在兩個(gè)類中拆宛,那么構(gòu)建時(shí)讀取狀態(tài)將會(huì)很不方便嗓奢!試想一下,如果真的將build方法放在StatefulWidget中的話浑厚,由于構(gòu)建用戶界面過程需要依賴State股耽,所以build方法將必須加一個(gè)State參數(shù),
這樣的話就只能將State的所有狀態(tài)聲明為公開的狀態(tài)钳幅,這樣才能在State類外部訪問狀態(tài)物蝙!但是,將狀態(tài)設(shè)置為公開后敢艰,狀態(tài)將不再具有私密性诬乞,這就會(huì)導(dǎo)致對(duì)狀態(tài)的修改將會(huì)變的不可控。但如果將build()方法放在State中的話钠导,構(gòu)建過程不僅可以直接訪問狀態(tài)震嫉,而且也無(wú)需公開私有狀態(tài),這會(huì)非常方便辈双。
2.繼承StatefulWidget不便
例如责掏,F(xiàn)lutter中有一個(gè)動(dòng)畫widget的基類AnimatedWidget,它繼承自StatefulWidget類湃望。AnimatedWidget中引入了一個(gè)抽象方法build(BuildContext context)换衬,繼承自AnimatedWidget的動(dòng)畫widget都要實(shí)現(xiàn)這個(gè)build方法。現(xiàn)在設(shè)想一下证芭,如果StatefulWidget 類中已經(jīng)有了一個(gè)build方法瞳浦,正如上面所述,此時(shí)build方法需要接收一個(gè)state對(duì)象废士,這就意味著AnimatedWidget必須將自己的State對(duì)象(記為_animatedWidgetState)提供給其子類叫潦,因?yàn)樽宇愋枰谄鋌uild方法中調(diào)用父類的build方法
這樣很顯然是不合理的,因?yàn)?br> a.AnimatedWidget的狀態(tài)對(duì)象是AnimatedWidget內(nèi)部實(shí)現(xiàn)細(xì)節(jié)官硝,不應(yīng)該暴露給外部矗蕊。
b.如果要將父類狀態(tài)暴露給子類短蜕,那么必須得有一種傳遞機(jī)制,而做這一套傳遞機(jī)制是無(wú)意義的傻咖,因?yàn)楦缸宇愔g狀態(tài)的傳遞和子類本身邏輯是無(wú)關(guān)的朋魔。

5獲取State
5.1 在Widget樹中獲取State對(duì)象
由于StatefulWidget的的具體邏輯都在其State中,所以很多時(shí)候卿操,我們需要獲取StatefulWidget對(duì)應(yīng)的State對(duì)象來(lái)調(diào)用一些方法警检,比如Scaffold組件對(duì)應(yīng)的狀態(tài)類ScaffoldState中就定義了打開SnackBar(路由頁(yè)底部提示條)的方法。我們有兩種方法在子widget樹中獲取父級(jí)StatefulWidget的State對(duì)象害淤。

5.2 通過Context獲取
context對(duì)象有一個(gè)ancestorStateOfType(TypeMatcher)方法扇雕,該方法可以從當(dāng)前節(jié)點(diǎn)沿著widget樹向上查找指定類型的StatefulWidget對(duì)應(yīng)的State對(duì)象。下面是實(shí)現(xiàn)打開SnackBar的示例:

5.3 通過GlobalKey獲取
_globalKey.currentState.openDrawer()
GlobalKey是Flutter提供的一種在整個(gè)APP中引用element的機(jī)制窥摄。如果一個(gè)widget設(shè)置了GlobalKey镶奉,那么我們便可以通過globalKey.currentWidget獲得該widget對(duì)象、globalKey.currentElement來(lái)獲得widget對(duì)應(yīng)的element對(duì)象崭放,如果當(dāng)前widget是StatefulWidget腮鞍,則可以通過globalKey.currentState來(lái)獲得該widget對(duì)應(yīng)的state對(duì)象。
注意:使用GlobalKey開銷較大莹菱,如果有其他可選方案移国,應(yīng)盡量避免使用它。另外同一個(gè)GlobalKey在整個(gè)widget樹中必須是唯一的道伟,不能重復(fù)迹缀。

6 Flutter SDK內(nèi)置組件庫(kù)介紹
Flutter提供了一套豐富、強(qiáng)大的基礎(chǔ)組件蜜徽,在基礎(chǔ)組件庫(kù)之上Flutter又提供了一套Material風(fēng)格(Android默認(rèn)的視覺風(fēng)格)和一套Cupertino風(fēng)格(iOS視覺風(fēng)格)的組件庫(kù)祝懂。

6.1 基礎(chǔ)組件 import 'package:flutter/widgets.dart';

  • Text:該組件可讓您創(chuàng)建一個(gè)帶格式的文本。
  • Row拘鞋、 Column: 這些具有彈性空間的布局類Widget可讓您在水平(Row)和垂直(Column)方向上創(chuàng)建靈活的布局砚蓬。其設(shè)計(jì)是基于Web開發(fā)中的Flexbox布局模型。
  • Stack: 取代線性布局 (譯者語(yǔ):和Android中的FrameLayout相似)盆色,Stack允許子 widget 堆疊灰蛙, 你可以使用 Positioned 來(lái)定位他們相對(duì)于Stack的上下左右四條邊的位置。Stacks是基于Web開發(fā)中的絕對(duì)定位(absolute positioning )布局模型設(shè)計(jì)的隔躲。
  • ContainerContainer 可讓您創(chuàng)建矩形視覺元素摩梧。container 可以裝飾一個(gè)BoxDecoration, 如 background、一個(gè)邊框宣旱、或者一個(gè)陰影仅父。 Container 也可以具有邊距(margins)、填充(padding)和應(yīng)用于其大小的約束(constraints)。另外笙纤, Container可以使用矩陣在三維空間中對(duì)其進(jìn)行變換耗溜。

6.2 Material組件 import 'package:flutter/material.dart';
Flutter提供了一套豐富的Material組件,它可以幫助我們構(gòu)建遵循Material Design設(shè)計(jì)規(guī)范的應(yīng)用程序省容。Material應(yīng)用程序以MaterialApp 組件開始强霎, 該組件在應(yīng)用程序的根部創(chuàng)建了一些必要的組件,比如Theme組件蓉冈,它用于配置應(yīng)用的主題。 是否使用MaterialApp完全是可選的轩触,但是使用它是一個(gè)很好的做法寞酿。在之前的示例中,我們已經(jīng)使用過多個(gè)Material 組件了脱柱,如:Scaffold伐弹、AppBarFlatButton等榨为。要使用Material 組件惨好,需要先引入它:

6.3 Cupertino組件 import 'package:flutter/cupertino.dart';
Flutter也提供了一套豐富的Cupertino風(fēng)格的組件,盡管目前還沒有Material 組件那么豐富随闺,但是它仍在不斷的完善中日川。值得一提的是在Material 組件庫(kù)中有一些組件可以根據(jù)實(shí)際運(yùn)行平臺(tái)來(lái)切換表現(xiàn)風(fēng)格,比如MaterialPageRoute矩乐,在路由切換時(shí)龄句,如果是Android系統(tǒng),它將會(huì)使用Android系統(tǒng)默認(rèn)的頁(yè)面切換動(dòng)畫(從底向上)散罕;如果是iOS系統(tǒng)分歇,它會(huì)使用iOS系統(tǒng)默認(rèn)的頁(yè)面切換動(dòng)畫(從右向左)。由于在前面的示例中還沒有Cupertino組件的示例欧漱,下面我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Cupertino組件風(fēng)格的頁(yè)面:

總結(jié)

Flutter提供了豐富的組件职抡,在實(shí)際的開發(fā)中你可以根據(jù)需要隨意使用它們,而不必?fù)?dān)心引入過多組件庫(kù)會(huì)讓你的應(yīng)用安裝包變大误甚,這不是web開發(fā)缚甩,dart在編譯時(shí)只會(huì)編譯你使用了的代碼。由于Material和Cupertino都是在基礎(chǔ)組件庫(kù)之上的窑邦,所以如果我們的應(yīng)用中引入了這兩者之一蹄胰,則不需要再引入flutter/widgets.dart了,因?yàn)樗鼈儍?nèi)部已經(jīng)引入過了奕翔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末裕寨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宾袜,老刑警劉巖捻艳,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異庆猫,居然都是意外死亡认轨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門月培,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)嘁字,“玉大人,你說(shuō)我怎么就攤上這事杉畜〖脱眩” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵此叠,是天一觀的道長(zhǎng)纯续。 經(jīng)常有香客問我,道長(zhǎng)灭袁,這世上最難降的妖魔是什么猬错? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮茸歧,結(jié)果婚禮上倦炒,老公的妹妹穿的比我還像新娘。我一直安慰自己软瞎,他們只是感情好析校,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铜涉,像睡著了一般智玻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芙代,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天吊奢,我揣著相機(jī)與錄音,去河邊找鬼纹烹。 笑死页滚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铺呵。 我是一名探鬼主播裹驰,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼片挂!你這毒婦竟也來(lái)了幻林?” 一聲冷哼從身側(cè)響起贞盯,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沪饺,沒想到半個(gè)月后躏敢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡整葡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年件余,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遭居。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啼器,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俱萍,到底是詐尸還是另有隱情端壳,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布鼠次,位于F島的核電站,受9級(jí)特大地震影響芋齿,放射性物質(zhì)發(fā)生泄漏腥寇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一觅捆、第九天 我趴在偏房一處隱蔽的房頂上張望赦役。 院中可真熱鬧,春花似錦栅炒、人聲如沸掂摔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乙漓。三九已至,卻和暖如春释移,著一層夾襖步出監(jiān)牢的瞬間叭披,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工玩讳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涩蜘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓熏纯,卻偏偏與公主長(zhǎng)得像同诫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子樟澜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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