Flex的Layout機制具體的說就是Flex對組件的大小和位置的控制演算法。從
Flash開始初學Flex,也許會對Flex中設定組件的大小有些不適應。在Flash中,DisplayObject的width和height會根
據DisplayObject所包含的“可視化元素”的大小自動調整,例如mc中的children的移動或者縮放都可能引起mc的width和
height變化,而如果直接改變mc的width和height,會使mc內的可視化元素放大或縮小(但不會引起可視化元素重組),mc的scaleX
和scaleY也同時改變。在Flex中,組件的width和height已經被override,因此其表現和Flash有所不同:Flex中組建
width和height不一定根據可視化元素大小而定,例如設定了精確大小的Container,即使其內部的可視化元素超出了Container的範
圍,Container的大小仍然是指定的精確值,同樣的設定Flex控制項的width和height時,不是對控制項可視化元素的縮放,通常都會引起可視
化元素重畫成新的大小,而不引起scaleX和scaleY的變化。
以前從來沒想過override能有那麼大的“威力”,所以被Flex的width和height搞的糊裡糊塗的,呵呵看來菜鳥就是菜鳥,還好隨
著不斷的學習總算逐漸更領會到OOP的概念和Flash與Flex這些差別。發了點小感慨作為開場白,接下來就說說初學Flex的Layout機制的一些
收穫吧。
設定Flex組件的大小的方式有三種:精確大小explicit sizing、預設大小default
sizing、百分比大小percent
sizing。精確大小是指通過ActionScript或者MXML明確設定了組件的width或height為多少像素,是一個精確值;預設大小指的
是沒有通過ActionScript或者MXML設定組件的width或height;百分比大小是指通過ActionScript設定了組件的
percentWidth或percentHeight,也可以通過MXML設定組件的width或height為一個百分數。
Flex組件大小有以下幾種:
1.實際大小:也就是最終顯示出來的組件的大小,可以通過width和height指定和獲得;
2.精確大小:也就是通過精確大小的方式設定組件大小時,所指定的值,可以通過explicitWidth和explicitHeight獲得;
3.預設大小:也就是Flex自動計算出的組件大小,可以通過measuredWidth和measuredHeight獲得,如果設定組件的大小為預設大小時,那麼組件的預設大小也就是實際大小;
4.百分比大小:也就是通過百分比大小的方式設定組件大小時,所指定的值,可以通過percentWidth和percentHeigh指定和t獲得;
5.組件大小的範圍:也就是限制組件的大小應該處於某個區間內,可以通過minWidth、maxWidth、minHeight和maxHeight指定和獲得這個區間。
知道了Flex組件大小的設定方式合類型之後,再瞭解一下Flex的Layout流程。Layout流程分為三步,第一步是重新整理組件的屬性,稱為
Commitment
Pass。第二步是在組件屬性更新後,從DisplayList中最深層的組件開始,計算每個組件的測量大小,即查看控制項使用的是精確大小還是預設大小,
並擷取相應的值,這一步稱為Measurement
Pass。第三步是從DisplayList中的最外層也就是Application開始向內計算每個組件的實際的大小,並完成對控制項的大小和位置設定,
同時也觸發控制項的重畫等方法,這個過程叫做Layout Pass。
這麼多和大小相關的東西,相對Flash確實複雜多了,但是有了這些東西,才讓Flex的Layout相對Flash更自動化。在實際使用時,不同的大小設定方式如何產生影響?這就需要更具體概述一下了。
1.採用精確大小的方式設定組件大小
當使用者明確指定了組件的width和height的像素值時,布局時Flex就會強制使用使用者指定的像素值,注意這種設定是強制的,Flex會保證組件的
實際大小width和height就等於設定值,並且指定的大小不受組件大小的範圍限制。在使用者通過width和height設定精確大小時,同時也就設
定了組件的explicitWidth和explicitHeight。
2.採用預設大小的方式設定組件大小
當使用者不設定組件width和height,也不設定組件的percentWidth和percentHeigth時,布局時就自動計算群組件的大小,也就
是使用組件的預設值作為組件的實際大小。不同組件有不同的預設值,組件的預設值也會因為某些屬性改變而改變,例如Button的預設值就與button的
label字元長度有關,並且組件的預設大小一定會在[minWidth,maxWidth]和[minHeight,maxHeight]之間,但不一
定就是這個區間內的最小值。
3.採用百分比大小方式設定組件大小
當使用者使用百分比的方式指定了組件的大小時,布局時將使用空間的百分比大小。組件的百分比大小是建議性的,Flex只是盡量保證組件的大小與parent的可視地區大小成所設定的比例。有以下幾點需要注意:
組件的百分比大小和精確大小是互斥的屬性,當設定了組件的percentWidth和percentHeight時,相應的explicitWidth和
explicitHeight屬性就是NaN,反之亦然。而width和height指的是組件在版面配置階段執行完成後實際的長寬,並不會因為設定了百分比
大小就為NaN。只是通過width和height設定精確大小時,會同時設定explicitWidth和explicitHeight屬性,從而使
percentWidth和percentHeight屬性為NaN。
組件百分比大小指的是相對其parent中的可視地區的大小的百分比,也就是刨除parent的border
width、padding、gap等地區後(gap個數會根據組件數量而定),用於放置組件的那個地區的大小,並不是parent的實際大小。對於
Tile container或者TileLayout,children的百分比是指相對於每個tile
cell的百分比,對於其它大部分Container,百分比是相對於整個容器可視地區的。
當組件設定為百分比大小時,組件的實際大小是在parent的大小調整過程中計算出來的,如果按照設定的比例超出了組件的minimum
size和maximun size範圍,那麼組件會被設定成minimum size或maximun size(組件的minimum
size會根據組件和組件所包含的child不同而不同),而不是百分比指定的大小(因此百分比大小隻是一個建議值)。
當組件設定為百分比時,如果組件的parent是自動布局的,並且還包含了其它組件,那麼parent會先保證設定為精確大小和預設大小的child組件
以及parent相應的border
width、padding和gap先分配空間;對於設定成百分比大小的child組件,會根據parent的可視地區大小(排除border
width、padding和相應數量的gap之後的地區大小)嘗試按照設定的百分比設定組件的大小,但是如果這些組件的大小超出了parent剩餘的空
間,那麼parent會把剩餘空間按照組件的百分比所構成的比例,分配給每個百分比組件(同時也要保證組件大小在minimum
size或maximun size之間)。例如Hbox的實際寬度是400(確定實際寬度時,是先layout
pass過程,先確定parent才確定child),包含左右padding各50,包含一個設定了寬度為120的button,parent的gap
為40,還有兩個設定了寬度為60%和30%的組件,那麼計算這兩個組件實際寬度時,首先分配一個button和左右padding以及2個gap(3個
組件因此有2個gap)的空間,總大小為120 + 2×50 + 2×40 =
300,parent中剩餘的地區還有100。根據百分比兩個組件的大小是(400- 2×50 - 2×40)×60%和(400- 2×50 -
2×40)×30%,分別為132和66,但是132+66大於parent剩餘的空間,因此,parent把剩餘的100空間分為兩個分給兩個組
件,60%的組件分到的空間是100×60/(60+30),30%的組件分到的空間是100×30/(60+30),分別是67和33,分配到的大小滿
足在minimum size或maximun size之間,因此最終組件的實際大小就是這個值。如果手動設定兩個百分比組件的minimum
size為70和50,那麼67和33就不滿足可取的值範圍,因此組件實際大小會被設定為70和50,這樣就會超出HBox的可視地區,由此就會出現滾動
條(也可以設定不出現捲軸)。
當組件設定為百分比時,如果組件的parent是絕對布局的,對於halo
Container的child,會根據parent的可視地區大小乘以百分比計算實際大小,同時還考慮minimum size或maximun
size約束,也考慮組件的位置,保證組件處於哪個位置上時實際大小不會超出parent的邊界。對於spark
Container的child,會根據parent的可視地區大小乘以百分比計算實際大小,同時還考慮minimum size或maximun
size約束,但不考慮child自身位置的影響。