官术网_书友最值得收藏!

1.1.3 Container

在Flutter框架中,若需對(duì)一個(gè)組件進(jìn)行包裝或修飾,則最直接的辦法就是將它嵌套在一個(gè)容器組件內(nèi)。Container組件就是這樣一個(gè)結(jié)合了定義尺寸、形狀、背景顏色、間距、留白、裝飾等多功能于一身的組件。雖然這些功能都有對(duì)應(yīng)的組件,例如調(diào)節(jié)尺寸可以用SizedBox組件,設(shè)置間距可以用Padding組件,更改背景顏色可以用DecoratedBox組件,這些本書都會(huì)介紹到,但對(duì)于初學(xué)者而言,直接套用Container組件無疑是最簡便且最容易記住的方式。對(duì)于有經(jīng)驗(yàn)的開發(fā)者,適時(shí)使用Container組件也有助于在縮短代碼量的同時(shí)增加代碼的可讀性。

除了包裝和修飾其他組件之外,Container組件也可以直接用來繪制圖形或色塊,代碼如下:

Container(
    width: 200,
    height: 100,
    color: Colors.grey,
)

圖1-4 用Container組件繪制一個(gè)矩形色塊

以上代碼利用width(寬度)、height(高度)和color(顏色)3個(gè)常用屬性,定義了一個(gè)寬度為200邏輯像素、高度為100邏輯像素的灰色矩形,如圖1-4所示。

1.嵌套子組件

除了繪制圖形外,Container組件更常用于包裝和修飾其他組件。開發(fā)者可借助其child參數(shù)傳入另一個(gè)組件,以達(dá)成嵌套的效果。這里需要注意的是,如果嵌套的子組件的尺寸小于這個(gè)Container組件,則還需要通過傳入alignment(對(duì)齊)屬性設(shè)置內(nèi)部的小組件應(yīng)該怎樣擺放,如居中、左上、右下等。如果沒有傳入alignment參數(shù),則Container組件不會(huì)自動(dòng)把child居中,而是會(huì)將child設(shè)置為自身尺寸。

例如上例中的灰色的Container組件可以使用child屬性再嵌套一個(gè)黑色的Container組件,并在其中再次嵌套第3個(gè)白色的Container組件,并為它們分別設(shè)置對(duì)齊屬性,代碼如下:

運(yùn)行效果如圖1-5所示。

實(shí)戰(zhàn)中,Container組件也常用于為其他組件設(shè)置背景顏色。例如,可將之前介紹的FlutterLogo組件尺寸設(shè)置為100單位(高度和寬度均為100邏輯像素),并嵌套在Container組件內(nèi),再用color屬性把Container組件設(shè)置為黑色,代碼如下:

Container(
    color: Colors.black,
    child: FlutterLogo(size: 100),
)

運(yùn)行效果如圖1-6所示。

圖1-5 用Container組件嵌套的形式修飾其他組件

圖1-6 用Container組件使FlutterLogo的背景變成黑色

這里可以觀察到FlutterLogo的背景變成了黑色(實(shí)際上是它的父級(jí)組件Container組件的填充色),并且由于FlutterLogo的尺寸是100單位,從視覺效果上,可以推測此時(shí)Container組件的尺寸似乎也應(yīng)該是100單位。

實(shí)際上,這個(gè)Container組件的尺寸確實(shí)是100單位。在沒有設(shè)置alignment屬性的情況下,也沒有刻意設(shè)置Container組件的高度和寬度時(shí),它會(huì)盡量把自己的尺寸調(diào)節(jié)到child的尺寸,但若設(shè)置了alignment屬性,它就不會(huì)這么做了。Container組件自身尺寸的算法相對(duì)復(fù)雜,有興趣的讀者可參考本節(jié)末尾的“Flutter框架小知識(shí):Container組件的尺寸究竟是怎么確定的?”。

由此可見,如果直接將一個(gè)組件嵌套在Container組件中,而不設(shè)置Container組件的任何屬性,視覺上就不會(huì)有效果,因?yàn)檫@個(gè)Container組件的尺寸會(huì)匹配child,且默認(rèn)填充色為透明。

另外,F(xiàn)lutter框架中還有大量其他組件也有child屬性,一般用于嵌套另一個(gè)組件,與上述用法一致,本書之后的章節(jié)將不再詳細(xì)介紹其他組件的child屬性。

2.常用屬性

1)width和height

寬度和高度,類型為double小數(shù),默認(rèn)值為null。用于設(shè)置Container組件的尺寸,單位是邏輯像素。

Dart Tips語法小貼士

Dart空安全(null-safety)及遺留代碼

上文提到Container組件尺寸屬性的類型為double,默認(rèn)值是null。考慮空安全,實(shí)際上Container組件的尺寸屬性應(yīng)是“double?”而不是double類,前者為“可空的小數(shù)”類型而后者為“不可空的小數(shù)”類型。在2021年3月3日發(fā)布的Flutter 2.0中,F(xiàn)lutter開始默認(rèn)采用支持空安全的Dart 2.12版,因此組件的可選參數(shù)都必須是可空類型,即可選的color參數(shù)需寫為“Color?”,可選的子組件應(yīng)是“Widget?”類等。本書為了提高閱讀流暢度,在提及Dart類型時(shí)盡量不添加問號(hào),以免在閱讀時(shí)引起不必要的斷句障礙。

在2021年3月之前啟動(dòng)的Flutter項(xiàng)目可能還沒有遷移至Flutter 2.0空安全,因此在那些項(xiàng)目代碼中,任何類型都是可空的,如int、bool、double等,初始值都是null,而不是很多編程語言里常見的0、false或者0.0等。在啟用空安全之前,只有賦值定義如inti=0時(shí),其初始值才是0,否則直接定義inti就相當(dāng)于inti=null,因此在舊代碼中,若看到其他開發(fā)者寫了if(checked==true)的時(shí)候,不要輕易地把它“簡化”成if(checked),因?yàn)榭瞻踩暗腷ool有3種狀態(tài),因此上段代碼的原作者可能是指if(checked!=false&& checked!=null),所以一定要仔細(xì)檢查確認(rèn)后再?zèng)Q定。

如果一個(gè)Container組件只被設(shè)置了尺寸,而沒有用到其他的功能,如填充色或修飾屬性等,也可以考慮直接使用SizedBox組件,在本章后面小節(jié)會(huì)介紹。

2)color

填充色,類型為Color(可空顏色類,準(zhǔn)確而言是“Color?”),當(dāng)其值為null時(shí)則為透明,沒有填充效果。通常在開發(fā)的過程中,為了看清Container組件的尺寸和位置,可以臨時(shí)為它設(shè)置一些不透明或半透明的顏色,如Colors. blue藍(lán)色或Colors. red. withOpacity(0.5)半透明的紅色等,以便直觀地觀察和調(diào)整布局。

這里的填充色必須是單一的顏色,如需使用顏色漸變(有時(shí)也譯作色彩梯度或顏色帶),可以使用decoration(修飾)屬性。需要注意的是,顏色和修飾屬性有沖突,如果使用decoration屬性,則這里的color屬性必須為空(傳入null或刪掉不傳)。

3)child

子組件,類型為Widget。如果不傳入,且沒有定義Container組件的尺寸,則Container組件會(huì)盡量占滿父級(jí)組件的全部空間。例如,當(dāng)父級(jí)組件也沒有定義或約束尺寸時(shí),它會(huì)占滿整個(gè)屏幕。

Container組件只支持嵌套一個(gè)子組件,如果需要傳入多個(gè)組件,則可考慮使用Column、Row或Stack組件。這些布局組件在實(shí)戰(zhàn)中都比較常見,在本章后面小節(jié)也會(huì)依次介紹。

4)alignment

當(dāng)子組件的尺寸小于Container組件時(shí),開發(fā)者可利用alignment屬性設(shè)置對(duì)齊方式。類型為Alignment類,構(gòu)造函數(shù)為Alignment(double x,doubley),其中xy分別對(duì)應(yīng)橫軸和縱軸方向的位置,取值范圍為[-1.0,1.0]。橫軸(x)方向-1.0表示最左邊,1.0表示最右邊,0.0則坐落于正中間。縱軸(y)方向-1.0表示最頂部,1.0表示最底部,例如從上到下1/8的位置就可以用-0.25表示。

Alignment類型對(duì)常見的對(duì)齊場景已內(nèi)置命名構(gòu)造函數(shù),方便開發(fā)者直接使用,以增加代碼可讀性。例如,左上對(duì)齊既可以用Alignment(-1.0,-1.0)表示,也可以直接用Alignment. topLeft表示。

如果child屬性為空,即沒有子組件需要對(duì)齊,則alignment屬性會(huì)被直接忽略。

5)margin和padding

間距留白和填充留白,分別指Container組件的“外部”和“內(nèi)部”的空白部分。類型為EdgeInsets類,基本的構(gòu)造函數(shù)有EdgeInsets. fromLTRB(doubleleft,doubletop,double right,doublebottom),即依次單獨(dú)設(shè)置左、上、右、下這4個(gè)方向分別留白多少邏輯像素。如果4個(gè)數(shù)值相同,則可以使用EdgeInsets. all(doublevalue)同時(shí)設(shè)置4個(gè)方向的值。如果只需設(shè)置其中幾個(gè)值,則可以使用EdgeInsets. only()方法,傳入需要設(shè)置的方向,省略的方向則自動(dòng)為0。

例如,可通過margin和padding屬性修改一個(gè)Container組件的留白情況,代碼如下:運(yùn)行效果如圖1-7所示。

圖1-7 Container的間距留白和填充

3.不常用屬性

1)constraints

布局約束,可以傳入BoxConstraints類型,約束其child組件的最大尺寸和最小尺寸,同時(shí)Container組件自身的尺寸也可能會(huì)受影響。有關(guān)Flutter布局約束和原理,以及該屬性的具體用法和示例,讀者可參考第6章“進(jìn)階布局”中介紹ConstrainedBox組件的內(nèi)容。

實(shí)戰(zhàn)中,若只需使用約束屬性,而不需要使用Container組件的其他屬性,則可考慮直接使用ConstrainedBox組件。實(shí)際上,Container組件本身只是一個(gè)結(jié)合了各種其他組件于一身的“便利組件”,它最主要的作用就是當(dāng)一段代碼需要同時(shí)使用大量布局組件時(shí)可減少嵌套的層數(shù)。

2)decoration

修飾屬性是一個(gè)相對(duì)復(fù)雜的屬性,可以包括形狀、陰影、邊框、漸變色填充等的修飾。修飾的效果會(huì)渲染在子組件child后面,作為背景。具體用法與DecoratedBox組件的同名屬性相同,讀者可參考第14章“渲染與特效”中關(guān)于DecoratedBox組件的內(nèi)容。

由于本節(jié)介紹的Container組件本質(zhì)是一個(gè)結(jié)合了定義尺寸、約束、形狀、背景顏色、間距、填充、變形等功能于一身的組件,因此若只需用到修飾屬性,則可直接使用DecoratedBox組件。

3)foregroundDecoration

前景修飾,同樣是一個(gè)修飾屬性,可以做到和decoration屬性同樣的效果,唯一的區(qū)別是修飾的效果會(huì)渲染在子組件child的前面,即z軸方向會(huì)疊加在decoration(背景修飾)和child(子組件)的上面。如果使用同樣尺寸且不透明的修飾,則它可能會(huì)完全遮擋住child及背景修飾的內(nèi)容。

例如,可結(jié)合decoration和foregroundDecoration兩種修飾參數(shù)一同使用,代碼如下:

圖1-8 Container組件的背景修飾與前景修飾

這段代碼定義了漸變效果的背景方塊,并添加了陰影效果。內(nèi)部嵌入了白色的正方形Container作為子組件,最后利用前景修飾參數(shù)做出圓形半透明覆蓋層,運(yùn)行效果如圖1-8所示。

4)clipBehavior

裁邊行為,這是為2018年6月的一個(gè)Flutter框架改動(dòng)引起的新概念(4)而新增的一個(gè)參數(shù)。該改動(dòng)取消了默認(rèn)渲染時(shí)的反鋸齒(anti-aliasing),因?yàn)榻^大部分情況下反鋸齒并不會(huì)帶來畫質(zhì)的提升,卻會(huì)造成不必要的資源浪費(fèi)。默認(rèn)關(guān)閉反鋸齒可以大幅增加Flutter渲染的性能,但因?yàn)镃ontainer組件可以通過decoration屬性支持“斜”裁邊(如三角形裁邊),如果裁邊后鋸齒嚴(yán)重,可以通過clipBehavior 屬性手動(dòng)啟用反鋸齒。

除了Container組件外,不少其他支持裁剪效果的組件也都有clipBehavior屬性,本書將不再單獨(dú)介紹。關(guān)于鋸齒現(xiàn)象及clipBehavior屬性,可查閱第14章關(guān)于“裁剪邊框”的內(nèi)容。

5)transform

變形參數(shù),可以接收一個(gè)4×4的矩陣,獲得對(duì)三維物體的縮放、平移和旋轉(zhuǎn)的描述,并在渲染Container時(shí)應(yīng)用變形效果。三維物體的任意縮放、平移和旋轉(zhuǎn)都可以通過一個(gè)4× 4矩陣完成,14.1.5節(jié)將做簡單介紹很多其他的圖形框架采用類似設(shè)計(jì),因此矩陣的計(jì)算方法實(shí)際上并不屬于Flutter框架的知識(shí)范疇。

例如利用一個(gè)適當(dāng)?shù)木仃嚕梢詫?duì)上例(圖1-8)中的Container做出x軸放大至150%,y軸縮小至75%,并沿z軸方向旋轉(zhuǎn)45°的變形效果。數(shù)學(xué)計(jì)算后得出,這樣的變形需要以下矩陣:

圖1-9 利用矩陣達(dá)到變形效果

運(yùn)行效果如圖1-9所示。

實(shí)戰(zhàn)中,如果只需使用變形屬性,則可以直接使用Transform組件。當(dāng)Container組件的transform屬性不為空時(shí),它實(shí)際就在背后自動(dòng)調(diào)用了Transform組件,因此讀者也可參考第14章“渲染與特效”中關(guān)于Transform組件的介紹。

Flutter 框架小知識(shí)

Container組件的尺寸究竟是怎么確定的

簡而言之,沒有子組件(child屬性為空)的Container會(huì)盡量占滿父級(jí)組件的全部可用空間,而有子組件的Container會(huì)盡量將自己與子組件的尺寸匹配。

具體情況如下:

(1)在沒有子組件(child:null)的情況下。

a. 首先綜合父級(jí)約束及自身的width、height、constraints屬性計(jì)算約束;

b. 如果最終計(jì)算出的約束有界,則盡量占滿;

c. 如果最終計(jì)算出的約束無界,則盡量縮小。

(2)在有child子組件的情況下。

a. 首先將父級(jí)約束及自身的width、height、constraints約束傳遞給child;

b. 等child確定完尺寸后,Container盡量縮小,以便匹配child尺寸;

c. 但若提供了alignment屬性,則盡量放大,為對(duì)齊child創(chuàng)造條件;

d. 又若某維度的約束無界,則依然只能盡量縮小,以便匹配child尺寸。

(3)如果Container組件周圍存在留白,則最終尺寸也可能受到影響。其中margin會(huì)直接增加Container組件的尺寸,而padding及decoration屬性(若設(shè)置了邊框修飾),僅在Container組件試圖匹配child尺寸時(shí)額外增加尺寸。

綜合起來也可以這樣理解:沒有child的Container組件,越大越好,除非約束無界;有child的Container組件,匹配child,除非child要對(duì)齊。

舉例說明:

(1)例如某無child的Container組件的父級(jí)組件是Column,垂直方向無界,水平方向有邊界(屏幕寬度),則該Container組件會(huì)選擇高度為0(無界時(shí)盡量縮小),寬度匹配屏幕寬度(有界時(shí)盡量占滿)。由于高度為0,該Container組件的面積為0,肉眼不可見。

(2)假設(shè)上例中的Container組件新增了一個(gè)child組件,并提供了alignment屬性要求居中,則Container組件在垂直方向匹配子組件的尺寸,在水平方向占滿全部可用空間,再將子組件居中。

(3)若Container組件有子組件但未提供對(duì)齊方式,且各種尺寸屬性皆為空,則Container組件會(huì)將父級(jí)組件的布局約束直接傳達(dá)給子組件,當(dāng)子組件確定尺寸后,Container組件再將自身尺寸設(shè)置為子組件尺寸。

主站蜘蛛池模板: 祁门县| 斗六市| 芒康县| 宽甸| 庆云县| 罗田县| 临沂市| 浮山县| 济宁市| 乐都县| 广东省| 板桥市| 太谷县| 龙口市| 绥中县| 浏阳市| 武宁县| 十堰市| 错那县| 新昌县| 修文县| 增城市| 南召县| 那坡县| 顺昌县| 阿勒泰市| 筠连县| 车险| 大关县| 平阴县| 元谋县| 紫云| 界首市| 桑日县| 平乡县| 平安县| 哈尔滨市| 旬阳县| 徐汇区| 林州市| 阳城县|