歡迎訪問歐陽大哥的github站點
CSS中的float屬性簡介
幾乎所有會WEB前端開發的同學都知道CSS中有一個float屬性用於實現HTML元素的浮動定位展示。float 屬性定義元素在哪個方向浮動。以往這個屬性總應用於圖像,使文本圍繞在圖像周圍。不過在 CSS 中,任何元素都可以浮動,假如在一行之上只有極少的空間可供浮動元素,那麼這個元素會跳至下一行,這個過程會持續到某一行擁有足夠的空間為止。 浮動布局主要用於那些圖文環繞以及實現一些界面不規則排列的場景,並且浮動定位技術在WEB前端開發中應用的非常普遍。iOS中實現不規則排列的方式
在iOS中我們可以通過frame以及AutoLayout兩種方法來實現界面的布局。如果是通過frame方式在一些不規則界面的場景中就需要進行大量計算來實現布局,而AutoLayout則可以通過設置視圖之間的依賴約束來實現布局,這兩者的布局方式都和子視圖加入到父視圖的順序無關,越是不規則的界面,計算量以及約束依賴的設置就越復雜。我們在開發程序時是會碰到一個概念叫高內聚低耦合,如果對象之間都存在著相互依賴約束關系的話則意味著程序越復雜和難以理解,所以我們要進行對象之間的解耦處理。就以某些不規則的界面來說,表面上看起來雜亂無章實際仍然是有一些規律可循的:視圖之間展示的關系是按添加到父視圖的先後順序並且只和自己的尺寸以及父視圖的尺寸有關。這樣我們就把這種子視圖之間的強耦合關聯轉化為了按排列順序以及只和自身尺寸有關的弱耦合關聯。 怎麼來實現這種布局時的弱耦合以便減少約束依賴的復雜性,這就是本文要探討的浮動實現機制。本文將會先從浮動的原理開始入手介紹浮動的各種特性,然後再介紹淘寶天貓首頁的不規則布局以及ZAKER新聞版面的那種不規則的卡片式布局的實現機制,最後再說明怎麼去實現這種不規則浮動布局的方法。
浮動
我們的UI界面中總是有一種場景是:某個容器視圖後續添加的子視圖的左邊總是緊跟著前面添加的子視圖的右邊,而上邊則跟前面視圖的上邊保持一致進行停靠顯示,而當容器視圖剩余的寬度空間不夠容納新加入的子視圖時則新加入的子視圖自動的往下移動且在不覆蓋已經排列好的視圖的前提下尋找出一個可以容納其寬度的最合適的位置進行停靠。我們稱這種機制為浮動。
上面的場景中我們的容器視圖的尺寸為500x300,當添加視圖A時,因為視圖A的寬度是80,寬度能夠被容器視圖容納,所以我們將視圖A浮動到容器視圖的左上角位置。而當添加視圖B時,因為視圖B的寬度是100,仍然能夠被容器視圖的寬度容納(容器視圖剩余寬度為420),所以將視圖B浮動到視圖A的右邊並且上邊對齊。我們也可以按同樣的方式來處理視圖C的浮動。這樣容器視圖剩余的寬度變為了170(500-80-100-150)。假如這時候我們想再放入一個尺寸為200x100的視圖D的時候,因為這時要添加的視圖D的寬度為200,而容器視圖的剩余寬度只有170了,這時候視圖D將不能浮動到視圖C的右邊了,我們必須要找一個合適的位置來放置視圖D。根據浮動的原則我們算出最合適的浮動位置是A視圖的右邊,且為了保持前面視圖不被覆蓋,因此視圖D放置的最合適的坐標位置是:(80,130)。下面就是視圖D放入後的結果:
根據浮動的規則假如視圖D的寬度不是200而是400的話,那麼視圖D將不能浮動到視圖A的右邊(視圖A的右邊的剩余的寬度為320,無法容納400的寬度),那麼根據浮動的規則,視圖D將再次往下移動,並浮動到容器視圖的最左邊的(0,180)的位置上。我們繼續來加入一個新的視圖E,視圖E的尺寸為100x50。那麼視圖E應該是浮動到視圖C的右邊還是視圖D的右邊呢? 答案是D的右邊,雖然C右邊的空間也可以容納100的寬度,但是卻不符合浮動的規則。我們上面說的浮動的規則是在可以容納新加入視圖寬度的情況下新加入的視圖的上邊和前一個加入的視圖的上邊對齊,而且新加入的視圖的左邊必須放置在前一個加入視圖的右邊。因此視圖E加入到容器視圖後的結果如下:
最後,我們再來考察新視圖F的加入。假如視圖F的尺寸為300x50。那麼根據浮動的規則視圖將無法浮動到E的右邊,同時也無法浮動到D的右邊了,這時候只能繼續往下移動,而最終的左邊是浮動到容器視圖的最左邊,而上邊的位置則是視圖D的下方。最終的布局結果如下:
通過上面的4張圖片我們就可以總結出浮動時優先向左浮動,再向下浮動的浮動規則:
R1:加入布局視圖的第一個子視圖總是浮動到布局視圖的左上角。
R2:如果新加入的子視圖的寬度能夠被放入到前一個加入的視圖右邊到布局視圖右邊的剩余寬度空間中的話,則新加入的視圖的左邊位置是等於前一個加入視圖的右邊位置,且新加入視圖的上邊位置和前一個加入的視圖的上邊位置保持一致。
R3:如果新加入的子視圖的寬度不能被放入到前一個加入的視圖的右邊到布局視圖右邊的剩余寬度空間中時,則新加入的視圖將繼續往左往下尋找到一個能容納其寬度的最小空間,並且不能遮擋掉前面加入的所有子視圖的最佳的位置進行放置。
R4:如果某個子視圖的寬度大於等於布局視圖的寬度,則總是浮動到布局視圖的最左邊,且上邊的位置是前面所有子視圖的最下邊的位置進行放置。
R5:總是確保任意的子視圖之間是不能被重疊覆蓋。
上面的5條規則就是一種浮動規則的定義,在CSS中我們可以為某個元素指定float這個屬性,而這個屬性的值可以設定為left或者right或者none,分別表示元素是向左浮動還是向右浮動還是不浮動。同時我們還可以為元素指定clear這個屬性來清除浮動,clear這個屬性可以設置left, right,both,none這四個值,下面我再介紹清除浮動的作用和意義。
清除浮動
上面的幾個場景中我們發現,不管新加入視圖的寬度如何,只要容器視圖中剩余寬度能夠容納新加入的子視圖,則子視圖總是會浮動到前面一個視圖的右邊。但在實際的應用場景中,我們又希望某個視圖不遵守這種默認的浮動規則,而是讓新加入的子視圖的左邊總是和容器視圖的左邊對齊,且子視圖的上邊則是放入到前面加入的占用最高空間的視圖的下方。比如下面的情況:
我們的子視圖C,雖然寬度為150,並且能浮動到視圖B的右邊,但是實際中我們則想讓視圖C浮動到A的下邊並且左邊和容器視圖對齊,這時候我們就需要用到清除浮動的概念了。 我們可以為視圖C設置一個清除浮動的屬性,這樣視圖C就達到了我們想要的效果。因此我們可以看出,所謂清除浮動就是使得視圖的默認的浮動規則失效,而總是讓視圖的左邊和容器視圖的左邊對齊,而讓視圖的上邊則設置為前面加入的所有同一個方向浮動的視圖的最高高度的下方。因此我們可以得出浮動布局的第6條規則:
R6:如果子視圖設定了清除浮動屬性,則視圖在布局時的左邊界總是和容器視圖的左邊界相等,而上邊界則是在所有前面加入的同一個方向浮動視圖的最高的高度的下方顯示。
通過視圖的清除浮動屬性,我們可以設置讓某些視圖不進行浮動,而是達到另起一行的效果。
比重
我們再來考察一種場景,就上面的例子來說,我們先加入了視圖A和B,現在我們想加入一個視圖C,並且想讓視圖C浮動在視圖B的右邊。而且寬度則是已經填充的A和B剩余的寬度320(500-80-100)。一個辦法就是我們手動的設定視圖C的寬度為320,這樣就能達到想要的效果,但是在實際的應用中,A和B的寬度可能是不確定的,並且容器視圖的寬度也是不確定的,而不管何種情況我們又總想讓視圖C的寬度總是占用剩余的寬度,就像如下的效果圖一樣:
在上面的場景中,我們希望不需要明確的設置視圖C的寬度,而是通過一種比重的特性來設置視圖C總是占用容器視圖的剩余寬度的某個比例值。這裡的比重的設置,是在整體布局視圖的浮動的方向的設定上的,就是說當整體的布局視圖裡面的視圖是支持左邊和右邊浮動時則這個比重指定的是視圖的寬度的相對比例值,而當布局視圖支持的是上邊和下邊浮動時則這個比重指的是視圖的高度的相對比例值。而且我們約定比重值的設定必須大於0且小於等於1。通過比重值的設定,我們可以不需要對某個新加入的視圖設定具體的寬度或者高度,而只需要指定一個相對的值,而由浮動布局來根據當前的浮動情況來自動計算出應該有的寬度或者寬度。其中的具體的計算公式為:
某個設置了比重值的視圖的寬度或者高度 = (布局視圖的寬度或者高度 - 前一個視圖的右邊或者下邊的邊界值)* 視圖的比重值。
就以上面的左右浮動的例子來說,假設我們設定視圖C的比重為1。根據公式的定義,布局視圖的寬度是500,而前面一個視圖B的右邊邊界值是180(100+80)。因此最終視圖C的寬度就是:320 = (500 - 180)*1, 而假如設定視圖C的比重是0.5的話,則最終視圖C的寬度就是160了。又如果我們再增加一個視圖D的比重設置為1的話。因為前面的視圖C的寬度已經算出是160,他的右邊距值是340(180+160), 因此最終視圖D的寬度就是160 (500 - 340) *1了。其中的效果圖如下:
浮動布局中的子視圖可以通過設定比重來得到剩余的寬度或者高度,因此浮動布局中針對比重屬性定義新的規則如下:
R7:當某個子視圖設定了比重屬性時,這個視圖的寬度或者高度將根據布局視圖的浮動方向設定,以及比重的值的設定自動進行計算,比重的設置必須大於0小於等於1,而通過比重計算出來的寬度或高度的公式為:布局視圖的寬度或者高度 - 前一個視圖的右邊或則下邊的邊界值)* 視圖的比重值
左右浮動
上面我們的介紹的浮動的例子中,都總是默認是向左浮動,然後再從上到下的進行布局。但前面也有說到CSS中的元素的浮動定位是同時支持向左或向右浮動的。當某個子視圖在加入到布局視圖時,可以設定為向左還是向右浮動(float屬性的值設置為left或者right),這裡的向左和向右是不能同時支持的,視圖要麼向左要麼向右。對於視圖向右浮動來說,他的機制是和向左浮動是一樣的。我們可以看如下的視圖:
可以看出,當A,B,C,D,E,F這幾個視圖向右浮動時,除了方向外,其他的規則是跟視圖向左浮動的規則是一樣的。一個布局視圖裡面的子視圖是可以設置為向左或者向右浮動的,而前面的例子裡的所有子視圖要麼都向左,要麼都向右。但是實際場景中我們是可以設置某些視圖向左浮動,而某些視圖向右浮動的。比如下面的例子:
上面的例子中我們把子視圖添加到布局視圖的順序分別是A,B,C,D,E,F這個順序,且設定C,D,E這三個子視圖是向左浮動的,而A,B,F這三個子視圖是向右浮動的。在前面的所有向左浮動的例子中,我們的剩余寬度的比較總是以布局視圖的右邊界為標准的,而前面所有向右浮動的例子中我們的剩余寬度的比較總是以布局視圖的左邊界為標准的。那麼當我們的布局視圖裡面的子視圖又有向左浮動的且又有向右浮動的情況時,我們的寬度邊界又是如何考慮的呢?
我們來分析一下上面的左右浮動的例子,因為我們總是按添加的先後順序來進行浮動布局的,所以上面的例子中A,B這兩個子視圖都向右浮動這個很容易理解,而視圖C向左浮動也比較容易理解。我們來考察當D視圖向左浮動要插入到容器視圖時,我們發現如果視圖D浮動到視圖C的右邊並且上邊和視圖C保持一致時,視圖D的布局寬度將會覆蓋掉視圖B的部分空間,如果出現了覆蓋則是不符合浮動布局規則5中的定義的,因此視圖D必須要往下移動,直到到達視圖B的底部後才不會出現覆蓋現象,因此視圖D的上邊位置就變為了100,而左邊的位置則仍然等於視圖A的右邊的位置了。視圖E也是向左浮動,這裡我們是要求E和最後一個加入的D必須要保持上邊對齊,但是如果保持上邊對齊的話就無法容納E的寬度而將產生覆蓋,因此必須要將視圖E往下移動,直到移到視圖A的下面才能滿足寬度的填充,因此視圖E的上邊位置就設置為視圖A的下邊,而左邊位置則設置為D的右邊。最後我們再來考察F的情況,雖然前面最後一個向右浮動的視圖是B,但是根據浮動規則2的約定,視圖F的上邊位置必須要和最後一個加入的視圖E的上邊位置保持一致,但是如果和E的上邊位置保持一致的話,F的長度將會覆蓋掉E的位置,因此視圖F必須要往下移動到視圖E的下面,並且右邊要和布局視圖的右邊界保持一致,這樣才能容納視圖F的顯示。通過上面的例子我們可以看出當一個布局視圖中同時存在著向左浮動和向右浮動的子視圖時,我們就有浮動布局的將新增規范8的定義如下:
R8:當浮動布局中同時存在著向左和向右浮動的子視圖時,向左浮動的視圖剩余寬度的右邊界是在不覆蓋掉右邊視圖的情況下的最小向右浮動的視圖的左邊界,而向右浮動的視圖的剩余寬度的左邊界是在不覆蓋掉左邊視圖的情況下的最大向左浮動的視圖的右邊界。
上下浮動
前面我們介紹向左和向右浮動的布局視圖的一些場景。在CSS中也只定義了向左和向右浮動的功能,向左向右浮動的布局視圖的原則是按視圖添加的順序,以及設定的浮動方向優先按左或者按右浮動,然後再整體的從上到下進行布局展示。但是在實際的情況中我們會要求有某個子視圖按向上或者向下浮動的來進行布局,並且布局的順序是按添加的子視圖的順序優先按向上或者按向下進行浮動,然後再整體的從左到右進行布局展示,這種浮動布局我們稱之為上下浮動布局。上下浮動布局裡面的子視圖,進行浮動的依據是根據子視圖本身的高度,以及布局視圖的高度來決定的(而左右浮動布局則是根據寬度來決定的)。其中的浮動規范除了方向上不同外,其他的機制都是跟左右浮動是一樣的。我們這裡就不再進行贅述了,下面我們通過一張布局來了解一下上下浮動布局的界面:
上圖可以看出上下浮動除了方向上和左右浮動不一樣外,其他的規則都是一致的,上下浮動布局是依然支持清除浮動的,只不過清除浮動時方向是變為了向右移動。同時上下浮動布局也是支持子視圖的比重設置的,只不過這裡的比重是指子視圖的高度。
淘寶天貓首頁以及ZAKER新聞的布局機制
上面介紹的浮動規則可以看出,通過浮動這種機制,我們將不再通過設置子視圖之間的約束來進行不規則布局了,而是通過調整子視圖的加入順序以及設置子視圖浮動的方向就能達到不規則布局的效果。就以具體的App例子來說,我們發現淘寶和天貓應用的首頁中的每個條目就是以一種看似不規則且無規律的方式依次從上而下的排列,同樣類似ZAKER新聞每頁中的每個新聞條目也是一種不規則無規律的方式而排列。如果真要實現這種完全不規則排列並且充滿整個頁面而沒有多余的空閒縫隙區域的算法也未嘗沒有,我們可以通過集裝箱算法來實現(集裝箱算法的目標就是讓某個具有固定尺寸的集裝箱,盡可能多的放入一些不規則尺寸的貨物,且要盡可能保證最大的容積利用率)。集裝箱算法其實是一個動態規劃的問題,在實踐中我們不大可能利用這種方法來實現完全不規則的布局。而是另辟蹊徑采用靜態模板的方式來實現。也就是說可以預先提供N種不規則布局的模板,然後每個頁面或者每個區域從這N個不同的模板中隨機的選取其中幾個進行組合排列來達到那種看似不規則的排列效果。而所有的這些都可以通過浮動技術來簡單解決。下面就是通過浮動技術來實現的模擬效果圖:
MyFloatLayout的方法和屬性的介紹
說了這麼多浮動布局的實現原理以及布局的機制,那我們怎麼來使用和定義浮動布局呢?要實現和使用浮動布局,我們必須要使用浮動布局MyFloatLayout這個類。MyFloatLayout類是MyLayout(Swift版本:TangramKit)布局體系中的一員,它是一個容器視圖類,主要目的是為裡面的子視圖提供浮動的能力,從而實現裡面的子視圖的不規則的排列。這個類的定義如下:
@interface MyFloatLayout : MyBaseLayout -(id)initWithOrientation:(MyLayoutViewOrientation)orientation; +(id)floatLayoutWithOrientation:(MyLayoutViewOrientation)orientation; @property(nonatomic,assign) MyLayoutViewOrientation orientation; @property(nonatomic,assign) MyMarginGravity gravity; @property(nonatomic, assign) CGFloat subviewVertMargin; @property(nonatomic, assign) CGFloat subviewHorzMargin; @property(nonatomic, assign) CGFloat subviewMargin; @property(nonatomic, assign) BOOL noBoundaryLimit; -(void)setSubviewsSize:(CGFloat)subviewSize minSpace:(CGFloat)minSpace maxSpace:(CGFloat)maxSpace; @end
從類的初始化方法中我們可以看出,在創建一個浮動布局時必須要指定一個方向,這個方向指的是最終子視圖的布局走向,因為左右浮動布局我們是先按左右浮動最終是一個從上到下的排列過程,而上下浮動布局則是先按上下浮動最終則是從左到右排列,因此當我們指定orientation的值為MyLayoutViewOrientation_Vert表示的是創建一個左右浮動的浮動布局,而當值設定為MyLayoutViewOrientation_Horz時則表示建立的是一個上下浮動的浮動布局,系統默認建立的是左右浮動的浮動布局。而且後續還可以通過orientation屬性來進行動態的修改浮動的方向。當浮動布局的浮動方向指定後,接下來我們就要為某個要添加到浮動布局的子視圖指定浮動方向屬性、清除浮動屬性、以及比重了,這些則可以通過視圖的擴展分類:
@interface UIView(MyFloatLayoutExt) @property(nonatomic,assign,getter=isReverseFloat) BOOL reverseFloat; @property(nonatomic,assign) BOOL clearFloat; @property(nonatomic, assign) CGFloat weight; @end
來設置。 在默認情況下當我們建立的是一個左右浮動布局時,我們添加到布局裡面的所有子視圖默認都是向左浮動的,而當建立的是一個上下浮動布局時,我們添加到布局裡面的所有子視圖默認都是向上浮動的,因此當需要改動子視圖浮動的方向則可以設置屬性reverseFloat來實現,這個屬性是一個BOOL類型的值,當設置為YES時表示按默認方向相反的方向浮動,也就是在左右浮動布局中,如果設置某個子視圖的reverseFloat為YES的話則表示子視圖是向右浮動,而對於上下浮動布局來數則表示是向下浮動。視圖的擴展屬性clearFloat也是一個BOOL類型,表示是否清除浮動,默認值是NO表示不清除浮動,當某個子視圖需要有清除浮動的效果時,請將這個屬性設置為YES。最後一個視圖的擴展屬性weight表示視圖的寬度或者高度的比重,這個值默認值是0,表示不是按比重來指定寬度,這時候你在添加子視圖時必須明確的指定寬度或者高度,而當設置為非0時則不需要為子視圖指定寬度和高度,而由布局系統來自動幫你計算。這裡的weight的設置范圍是:0<=weight <=1.
浮動布局的包裹屬性
上面分別的介紹了浮動布局的建立,以及子視圖的擴展的屬性設置來實現視圖在浮動布局中的浮動方式、是否清除浮動、以及比重的設置方法。另外對於浮動布局來說,因為是從MyBaseLayout中派生的,因此浮動布局同樣支持wrapContentWidth以及wrapContentHeight屬性的設置的,也就是浮動布局的寬高可以由子視圖來決定的,需要明確的是一般情況下我們對於左右浮動布局來說,只需要設置wrapContentHeight。當然你也可以設置wrapContentWidth(設置這個屬性的前提是布局視圖裡面有一個子視圖特別的寬,或者將布局視圖的noBoundaryLimit屬性設置為YES);同樣對於上下浮動布局來說,只需要設置wrapContentWidth。當然你也可以設置wrapContentHeight(設置這個屬性的前提是布局視圖裡面有一個子視圖特別的高,或者將布局視圖的noBoundaryLimit屬性設置為YES)。
浮動布局的停靠屬性
我們看到浮動布局視圖裡面還有一個gravity屬性,這個屬性在左右浮動布局視圖中可以用來設置所有子視圖的整體的上,中,下三種停靠模式,而在上下浮動布局視圖中則可以用來設置所有子視圖的整體的左,中,右三種停靠模式。
浮動布局的邊界限制屬性
我們再來考察布局視圖的noBoundaryLimit屬性。在上下浮動布局中,我們要求布局視圖要有明確的高度,這樣當某個子視圖的高度不能被容納後將會自動的換列。但是在實際中我們可能有一些場景是子視圖並不想受到布局視圖高度邊界的約束,一直往上浮動,而直到某個子視圖設置了clearFloat才換列顯示,同時布局視圖的高度也是包裹的(wrapContentHeight設置為YES的)。比如下面這個場景:
這個場景是一個上下浮動布局來實現的,但是這裡面要求布局視圖的高度是動態的(默認上下浮動布局的高度必須明確),因為右邊區域的高度是不確定的,因為D子視圖的高度會影響整個布局視圖的高度。所以為了用上下浮動布局來實現這個場景,我們就必須將布局視圖的高度設置為wrapContentHeight,並且將布局視圖的noBoundaryLimit屬性設置為YES以便表明由我們來控制換列,而不是由布局視圖的高度來控制換列。這樣在實現時我們就只需要如下偽代碼就可以了:
MyFloatLayout *S = [MyFloatLayout floatLayoutWithOrientation:MyLayoutViewOrientation_Horz]; S.wrapContentHeight = YES; S.wrapContentWidth = YES; S.noBoundaryLimit = YES; [S addSubview:A]; B.clearFloat = YES; //手動控制換列 [S addSubview:B]; [S addSubview:C]; [S addSubview:D]; [S addSubview:E]; [S addSubview:F]; [S addSubview:G];
智能邊界線
為了說明智能邊界線我們先來看這兩個界面:
上面的兩個界面是仿淘寶和天貓首頁以及ZAKER新聞的界面,我們來觀察其中的每個區塊之間的邊界線。我們發現處在邊緣部分是沒有顯示邊界線的,而邊界線只會顯示在區塊交界的地方顯示一條邊界線。在一般情況下,不規則邊界線的顯示我們有可能需要UI人員提供圖片來完成,或者不提供圖片我們在編程時也需要進行條件的判斷以便決定是否需要在特定的位置繪制邊界線,顯然這樣做將會增加我們的代碼量。因此為了解決這個問題,我們的布局系統提供了邊界線以及智能邊界線的功能。如果您用了MyBaseLayout派生的6大布局的話,我們是可以通過基類提供的四個屬性:
@property(nonatomic, strong) MyBorderLineDraw *leftBorderLine; @property(nonatomic, strong) MyBorderLineDraw *rightBorderLine; @property(nonatomic, strong) MyBorderLineDraw *topBorderLine; @property(nonatomic, strong) MyBorderLineDraw *bottomBorderLine;
來為布局視圖指定要顯示的四邊的邊界線,我們可以支持設置邊界線的顏色,粗細,縮進,以及點線等功能,這樣我們就不再需要單獨的提供邊界線的切圖了。要想看邊界線的例子,可以查看LLTest4ViewController和AllTest3ViewController這兩個DEMO的介紹。即便如此,對於上面的特殊情況,我們還需要進行編程以及條件判斷來完成邊界線的指定,因此為了解決這個問題,我們在布局中新增加了一個智能邊界線的屬性:
@property(nonatomic, strong) MyBorderLineDraw *IntelligentBorderLine; @property(nonatomic, assign) BOOL notUseIntelligentBorderLine;
如果為某個布局視圖設置了智能邊界線的值,那麼這個布局視圖裡面的子布局視圖將會根據視圖之間的關系而自動智能的生成邊界線。這裡需要強調的是只有布局視圖裡面的子布局視圖才會生成智能的邊界線,對於布局視圖裡面的非布局子視圖是不會生成邊界線的。而如果我們的某個布局視圖裡面的子布局視圖不想使用智能的邊界線,而是仍想自己手動設定,那麼只需要將自己的notUseIntelligentBorderLine設置為YES即可,他表示不使用父布局提供的智能邊界線功能。在當前的布局庫版本中,我們只有線性布局、浮動布局、表格布局、流式布局支持智能邊界線的設定,而框架布局、相對布局則是不支持的。正是因為布局系統裡面提供的智能邊界線的功能,就使得我們在設定布局視圖之間的邊界線時非常的簡單,只需要一句話就能搞定。
浮動布局的實踐
上面就是我們要介紹的關於浮動布局的全部的東西,接下來我們將借著DEMO中的代碼來具體的介紹我們如何使用浮動布局來實現上面的功能的。在介紹之前,我們這裡說明一下,我們仍然是可以用子視圖的擴展屬性myLeftMargin,myRightMargin,myTopMargin,myBottomMargin這4個屬性來指定視圖之間的間距的。同時我們還支持子視圖的寬度擴展屬性widthDime的值可以設置為一個具體值,也可以等於布局視圖的寬度,以及前面已經布好局的子視圖的寬度,甚至還可以等於子視圖的高度。
因為所有的關於浮動布局的代碼我們都能在DEMO中找到,因為我們只介紹幾個例子,其他的大家可以自己去研究,我們看下面的圖:
我們看到上面的界面左上角的區塊的高度為180,而其余的區塊都是90,並且每個區塊的寬度都是屏幕的一半。為了容納上面的界面我們需要先建立左右浮動的浮動布局:
CGFloat itemHeight = 90; MyFloatLayout *layout1 = [MyFloatLayout floatLayoutWithOrientation:MyLayoutViewOrientation_Vert]; layout1.backgroundColor = [UIColor whiteColor]; layout1.wrapContentHeight = YES; layout1.IntelligentBorderLine = [[MyBorderLineDraw alloc] initWithColor:[UIColor lightGrayColor]];
我們設定的layout1的高度由子視圖決定,並且設置了智能邊界線。接下來我們只需要每個區塊按順序依次添加進來即可。且從上面的區域中我們可以看出一共有3種不同的類型的區塊分別是A,B, C三種區塊,這三種區塊其實也是用MyFloatLayout來實現的:
A區塊我們也可以用一個浮動布局來實現,我們只需要建立一個上下浮動布局,標題,小圖都默認往上浮動。剩下的大圖寬度和父布局寬度相等,並且設置weight=1就可以了,這部分代碼的具體實現就在FOLTest2ViewController中的createItemLayout1_1的方法中實現。
B區塊我們也可以用浮動布局來實現,我們只需要建立一個左右浮動布局,大圖片優先向右浮動,高度和父布局高度相等,接下來主標題向左浮動,並且weight=1表示占用剩余的寬度;副標題也是向左浮動,並且設置清除浮動屬性,同時設置weight=1表示占用剩余的寬度;最後的小圖也是設置為左浮動,並且設置清除浮動屬性。這部分代碼的具體實現在FOLTest2ViewController中的createItemLayout1_3的方法中實現。
C區塊我們也可以用浮動布局來實現,我們只需要建立一個左右浮動布局,主標題部分向左浮動,並且寬度和父布局寬度相等,付標題部分向左浮動,並且寬度和父布局寬度相等,而圖片部分則向右浮動即可。
最後我們可以依次建立A,B,C三種區塊然後依次的加入到layout1中去,加入時只需要設置A的高度為180,而寬度則是layout1的一半即可,而其他兩種則高度設置為80,且寬度設置為layout1的一半即可。
小結
浮動布局是一種功能非常強大的布局體系,從某種程度上來他甚至是相對布局的替代方案,而且要比相對布局要簡單,因為裡面的子視圖之間是不需要設置約束和依賴關系的,單單憑借加入到布局視圖的順序,以及自身的寬高就能完成我們想要的功能。而且其提供的能力甚至要比CSS中的浮動屬性更加強大。而我們在進行WEB前端開發時很多的界面布局其實都是通過CSS的浮動屬性來完成的。因此我們也可以借助浮動布局來我們各種復雜的界面布局,而且浮動布局也能方便的實現線性布局以及流式布局的能力。如果您想了解更多的關於流式布局的功能請您訪問我的github站點來了解更多:
OC版本:https://github.com/youngsoft/MyLinearLayout
Swift版本:https://github.com/youngsoft/TangramKit
如果您覺得庫還不錯,記得給我star哦。