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

1.2.4 Stack

除了前面介紹的Column和Row組件都可以將一系列子組件由一個方向依次擺放外,在布局中還有一種較為常見的情況,就是疊放。例如,在圖片上加水印、在用戶頭像加上一對貓耳朵、把54張撲克牌的圖片疊在一起變成一副牌等。

Stack就是一個可將子組件疊在一起顯示的容器組件。由于它需要同時疊放多個子組件,所以傳入子組件的屬性不是child,而是復數形式children,代碼如下:

圖1-21 用Stack將2個FluterLogo組件疊放顯示

這樣就可以把2個FlutterLogo組件疊放在一起,運行效果如圖1-21所示。

1.布局算法

仔細觀察上例不難發現,對于不同尺寸的組件,Stack默認將它們沿著左上角對齊。實戰中一般需要精確地控制疊放的位置,這就涉及Stack的組件布局算法了,但在此之前,不得不先提一個與Stack密切相關的組件:Positioned。實際上,Stack里的子組件在布局時會被分為“有位置”和“無位置”這2大類,而其中“有位置”特指被Positioned包裹的子組件。

布局時,Stack首先會找到所有“無位置”的子組件,并向它們傳入fit屬性所設置的布局約束,如“不超過父級組件尺寸”等,允許它們一定程度內自由選擇自身的尺寸,并讓它們依次匯報最終確定的尺寸結果。在得到全部“無位置”子組件所確定的最終尺寸后,Stack會把自身尺寸匹配到其中最大的子組件的尺寸,再把其他(可能同等尺寸,或者較小)的子組件按照alignment屬性設置的對齊方式擺放。如果沒有設置對齊方式,則默認為左上角(在從右到左閱讀習慣的設備上默認為右上角)。如果Stack里不存在“無位置”的子組件,即全部子組件都是Positioned組件,則Stack會盡量將自身尺寸設置為父級布局約束所允許的最大尺寸,為對齊children創造條件。

一旦全部“無位置”的子組件都安置到位,同時Stack自身尺寸也確定完畢后,接下來就可以安排“有位置”的Positioned子組件了。具體布局算法將在1.2.5節介紹Positioned組件時詳細講解。

1)fit屬性

尺寸適配屬性用于控制Stack如何將自己的父級組件的尺寸約束傳達給“無位置”的子組件,類型是StackFit,默認值是StackFit. loose(寬松)。例如,某Stack的父級組件要求Stack的尺寸為200×200~500×500單位,在默認的寬松狀態下,Stack可以允許其children在不違背父級約束的前提下,自由選擇尺寸,即可在0×0~500×500單位任意選擇。相反,如果傳入fit:StackFit. expand(擴張),則Stack會要求所有“無位置”的children必須占滿父級約束的最大空間,即尺寸必須為500×500單位。最后,當傳入StackFit. passthrough(穿透)時,Stack會將自己父級組件的尺寸約束直接傳給子組件,即保持原有的200×200~500×500單位的約束。這些“尺寸約束”的內容相對復雜,初學者也可等閱讀完第6章“進階布局”后再來回顧這部分內容。

有些初學者容易誤認為fit屬性用于控制Stack的尺寸,StackFit. expand似乎是讓Stack自身“擴張”到最大尺寸。實際上,fit屬性只是幫助約束Stack中“無位置”的那些子組件的尺寸。前面提到,在布局的過程中,Stack最終會將自身尺寸適配到“無位置”子組件中的最大的那個,因此,當這里fit參數被設置為StackFit. expand時,實際上是Stack要求了“無位置”子組件盡量放大,自己再適配變大后的子組件,看起來就好像是Stack自身尺寸直接變大,但實際上Stack自身尺寸變大只是子組件變大后的一個副作用。

2)alignment屬性

如果子組件的尺寸小于Stack本身,alignment屬性可用來指定對齊方式。類型為Alignment類,需同時指定水平和垂直2個維度的對齊,如Alignment.topCenter等。對此不熟悉的讀者可參考本章之前Container組件中同名屬性的相關介紹。

這里需要指出的是,如果子組件已經使用了Positioned對齊,但沒有設置完整,則默認的維度依然會按照這里alignment屬性所設置的方式對齊。例如,這里通過Positioned組件要求底邊留白10單位,而不特別說明水平方向的對齊情況,代碼如下:

上述代碼中,若不設置alignment 屬性,則Stack依然會按照默認的左上對齊,再遵循Positioned對底邊(垂直方向)的要求,將組件繪制在左下角,并與底邊保留10單位的空白,如圖1-22(a)所示,但因為上述代碼通過alignment屬性修改了默認對齊方式為右上,實際運行時再結合底邊留白10單位的要求,最終Positioned的疊放位置就會變成右下角,如圖1-22(b)所示。

圖1-22 確定底邊留白后默認對齊仍有作用

2.疊放次序

Stack在渲染時會將子組件按照children屬性里的列表順序依次繪制并覆蓋疊放,因此列表里第一個組件會首先被繪制,于是出現在最底層,容易被其他組件覆蓋,而列表里最后一個組件則會被繪制到最頂層,可能遮住其他組件,但自身不會被Stack中的其他子組件遮擋。

3.溢出

默認情況下,溢出Stack尺寸邊界的子組件會被裁剪,不予顯示。這一行為是由clipBehavior屬性控制的,默認為Clip. hardEdge,即迅速地裁剪(不啟用抗鋸齒)多余部分。若需顯示溢出的組件,則開發者可將clipBehavior的屬性修改為Clip. none,要求不裁剪,代碼如下:

圖1-23 Stack子組件溢出部分的裁剪行為

圖1-23展示了子組件溢出部分“裁剪”(圖(a))和“不裁剪”(圖(b))的區別。

這里需要注意的是,雖然溢出Stack的內容可以通過修改裁剪行為繪制出來,但這些區域依然不會被算作觸摸手勢的識別范圍。例如某個按鈕一半在內一半在外,則只有在Stack范圍內的那半個按鈕可響應用戶的單擊事件。Flutter框架的這部分行為目前稍有爭議(5),也許未來某個Flutter版本中會改變,但就目前來講,如果溢出的組件是如按鈕等需要用戶交互的界面元素,則一定要注意測試這一行為,或者盡量想辦法通過更好地設置Stack本身尺寸避免出現子組件溢出。

另外,讀者可能會在一些舊版本的Flutter代碼中見到Stack組件的Overflow屬性,包括Overflow. clip(裁邊)與Overflow. visible(可見)這2種值。這是舊版本的遺留屬性,用于設置同樣的行為,但也可能會在未來版本中被移除,因此目前推薦使用這里介紹的clipBehavior屬性。

主站蜘蛛池模板: 西乌珠穆沁旗| 饶平县| 大厂| 嵩明县| 莱州市| 仙桃市| 陆良县| 汉中市| 岫岩| 佛坪县| 蒙自县| 娱乐| 泽普县| 星座| 柞水县| 宁武县| 凤山市| 舒兰市| 潢川县| 南丰县| 武山县| 新竹县| 称多县| 泽普县| 常宁市| 宁武县| 五指山市| 兴宁市| 江门市| 泗阳县| 抚宁县| 招远市| 正宁县| 常山县| 轮台县| 凤翔县| 永春县| 金川县| 寿阳县| 东源县| 新绛县|