iOS的MyLayout布局體系--浮動布局MyFloatLayout

前言

? ? 在MyLayout的6大布局中,每種布局都有不同的應(yīng)用場景。且每種布局的子視圖的約束機(jī)制不一樣:線性布局MyLinearLayout、表格布局MyTableLayout、流式布局MyFlowLayout浮動布局MyFloatLayout這四種布局的子視圖之間的約束是通過添加到父布局的先后順序來決定的;框架布局MyFrameLayout中的子視圖則只跟父布局視圖有關(guān),而跟添加的先后順序無關(guān);相對布局中MyRelativeLayout的子視圖則是通過設(shè)置視圖之間的依賴關(guān)系來建立約束的,而跟添加的先后順序無關(guān)。即便如此,同一種界面功能在一些情況下都可以用任何一種布局來實(shí)現(xiàn)。在這些布局中相對布局因?yàn)槭峭ㄟ^設(shè)定視圖之間的依賴來建立一種布局約束,因此我們可以用他來構(gòu)造一些復(fù)雜且無規(guī)律的界面布局,但其缺點(diǎn)則是太過于依賴約束,導(dǎo)致當(dāng)界面調(diào)整時需要重新設(shè)定視圖之間的依賴關(guān)系(iOS的AutoLayout其實(shí)就是一種相對布局的實(shí)現(xiàn),布局時需要設(shè)置太多的約束,這也是我一直詬病AutoLayout的原因)。那么是否可以有一種方法不設(shè)置視圖之間的依賴而來實(shí)現(xiàn)一些復(fù)雜的界面布局呢? 這也就是我們推出浮動布局MyFloatLayout的原因。

浮動

? ? ?我們的UI界面中總是有一種場景是:某個容器視圖后續(xù)添加的子視圖的左邊總是緊跟著前面添加的子視圖的右邊,而上邊則跟前面視圖的上邊保持一致進(jìn)行??匡@示,而當(dāng)容器視圖剩余的寬度空間不夠容納新加入的子視圖時則新加入的子視圖自動的往下移動且在不覆蓋已經(jīng)排列好的視圖的前提下尋找出一個可以容納其寬度的最合適的位置進(jìn)行???。我們稱這種機(jī)制為浮動。比如下面的場景:

浮動布局圖1

? ? ? 我們的容器視圖的尺寸為500x300,當(dāng)添加視圖A時,因?yàn)橐晥DA的寬度是80,寬度能夠被容器視圖容納,所以我們將視圖A浮動到容器視圖的左上角位置。而當(dāng)添加視圖B時,因?yàn)橐晥DB的寬度是100,仍然能夠被容器視圖的寬度容納(容器視圖剩余寬度為420),所以將視圖B浮動到視圖A的右邊并且上邊對齊。我們也可以按同樣的方式來處理視圖C的浮動。這樣容器視圖剩余的寬度變?yōu)榱?70(500-80-100-150)。假如這時候我們想再放入一個尺寸為200x100的視圖D的時候,因?yàn)檫@時要添加的視圖D的寬度為200,而容器視圖的剩余寬度只有170了,這時候視圖D將不能浮動到視圖C的右邊了,我們必須要找一個合適的位置來放置視圖D。根據(jù)浮動的原則我們算出最合適的浮動位置是A視圖的右邊,且為了保持前面視圖不被覆蓋,因此視圖D放置的最合適的坐標(biāo)位置是:(80,130)。下面就是視圖D放入后的結(jié)果:

浮動布局2

? ? ?根據(jù)浮動的規(guī)則假如視圖D的寬度不是200而是400的話,那么視圖D將不能浮動到視圖A的右邊(視圖A的右邊的剩余的寬度為320,無法容納400的寬度),那么根據(jù)浮動的規(guī)則,視圖D將再次往下移動,并浮動到容器視圖的最左邊的(0,180)的位置上。我們繼續(xù)來加入一個新的視圖E,視圖E的尺寸為100x50。那么視圖E應(yīng)該是浮動到視圖C的右邊還是視圖D的右邊呢? 答案是D的右邊,雖然C右邊的空間也可以容納100的寬度,但是卻不符合浮動的規(guī)則。我們上面說的浮動的規(guī)則是在可以容納新加入視圖寬度的情況下新加入的視圖的上邊和前一個加入的視圖的上邊對齊,而且新加入的視圖的左邊必須放置在前一個加入視圖的右邊。因此視圖E加入到容器視圖后的結(jié)果如下:

浮動布局3

最后,我們再來考察新視圖F的加入。假如視圖F的尺寸為300x50。那么根據(jù)浮動的規(guī)則視圖將無法浮動到E的右邊,同時也無法浮動到D的右邊了,這時候只能繼續(xù)往下移動,而最終的左邊是浮動到容器視圖的最左邊,而上邊的位置則是視圖D的下方。最終的布局結(jié)果如下:

浮動布局4

? 通過上面的4張圖片中,我們就可以總結(jié)出浮動的規(guī)則,而且上面的浮動規(guī)則只是我們的浮動布局MyFloatLayout中的一種浮動方向:優(yōu)先向左浮動,再向下浮動。我們可以通過浮動布局這種浮動機(jī)制,不再設(shè)置明確設(shè)定每個子視圖之間的依賴關(guān)系,而只是根據(jù)視圖加入到布局視圖的順序就能夠?qū)崿F(xiàn)一種不規(guī)則的視圖排列的布局場景。下面是我們總結(jié)的優(yōu)先向左浮動,再向下浮動的浮動規(guī)則:

1.加入布局視圖的第一個子視圖總是浮動到布局視圖的左上角。

2.如果新加入的子視圖的寬度能夠被放入到前一個加入的視圖右邊到布局視圖右邊的剩余寬度空間中的話,則新加入的視圖的左邊位置是等于前一個加入視圖的右邊位置,且新加入視圖的上邊位置和前一個加入的視圖的上邊位置保持一致。

3.如果新加入的子視圖的寬度不能被放入到前一個加入的視圖的右邊到布局視圖右邊的剩余寬度空間中時,則新加入的視圖將繼續(xù)往左往下尋找到一個能容納其寬度的最小空間,并且不能遮擋掉前面加入的所有子視圖的最佳的位置進(jìn)行放置。

4.如果某個子視圖的寬度大于等于布局視圖的寬度,則總是浮動到布局視圖的最左邊,且上邊的位置是前面所有子視圖的最下邊的位置進(jìn)行放置。

5.總是確保任意的子視圖之間是不能被重疊覆蓋。

? ? ? 上面的5條規(guī)則就是浮動布局中的一種浮動規(guī)則的定義,而浮動布局的規(guī)則定義其實(shí)是從HTML中的CSS中的一種定位:浮動定位的規(guī)則而來的。CSS中的浮動定位最初的設(shè)計(jì)初衷是為實(shí)現(xiàn)圖文混排的效果而設(shè)置的一種浮動定位技術(shù), 在CSS中我們可以為某個元素指定float這個屬性,而這個屬性的值可以設(shè)定為left或者right或者none,分別表示元素是向左浮動還是向右浮動還是不浮動。同時我們還可以為元素指定clear這個屬性來清除浮動,clear這個屬性可以設(shè)置left, right,both,none這四個值。若果您想了解CSS中關(guān)于浮動定位的信息可以訪問:CSS浮動定位CSS浮動知識分享這兩篇文章進(jìn)行詳細(xì)了解。

? ? ?前面說到,在CSS中我們可以通過float屬性來指定浮動的方向,以及clear屬性來指定清除浮動的操作。而我們的浮動布局MyFloatLayout也是支持浮動方向,以及清除浮動這些特性的設(shè)定的。向右浮動我們在后續(xù)會介紹,這里先介紹清除浮動的作用和意義。

清除浮動

? ? 上面的幾個場景中我們發(fā)現(xiàn),不管新加入視圖的寬度如何,只要容器視圖中剩余寬度能夠容納新加入的子視圖,則子視圖總是會浮動到前面一個視圖的右邊。但在實(shí)際的應(yīng)用場景中,我們又希望某個視圖不遵守這種默認(rèn)的浮動規(guī)則,而是讓新加入的子視圖的左邊總是和容器視圖的左邊對齊,且子視圖的上邊則是放入到前面加入的占用最高空間的視圖的下方。比如下面的情況:

浮動布局4

? ? ? ?我們的子視圖C,雖然寬度為150,并且能浮動到視圖B的右邊,但是實(shí)際中我們則想讓視圖C浮動到A的下邊并且左邊和容器視圖對齊,這時候我們就需要用到清除浮動的概念了。? 我們可以為視圖C設(shè)置一個清除浮動的屬性,這樣視圖C就達(dá)到了我們想要的效果。因此我們可以看出,所謂清除浮動就是使得視圖的默認(rèn)的浮動規(guī)則失效,而總是讓視圖的左邊和容器視圖的左邊對齊,而讓視圖的上邊則設(shè)置為前面加入的所有同一個方向浮動的視圖的最高高度的下方。因此我們可以得出浮動布局的第6條規(guī)則:

6.如果子視圖設(shè)定了清除浮動屬性,則視圖在布局時的左邊界總是和容器視圖的左邊界相等,而上邊界則是在所有前面加入的同一個方向浮動視圖的最高的高度的下方顯示。

通過視圖的清除浮動屬性,我們可以設(shè)置讓某些視圖不進(jìn)行浮動,而是達(dá)到另起一行的效果。

比重

? ? ?我們再來考察一種場景,就上面的例子來說,我們先加入了視圖A和B,現(xiàn)在我們想加入一個視圖C,并且想讓視圖C浮動在視圖B的右邊。而且寬度則是已經(jīng)填充的A和B剩余的寬度320(500-80-100)。一個辦法就是我們手動的設(shè)定視圖C的寬度為320,這樣就能達(dá)到想要的效果,但是在實(shí)際的應(yīng)用中,A和B的寬度可能是不確定的,并且容器視圖的寬度也是不確定的,而不管何種情況我們又總想讓視圖C的寬度總是占用剩余的寬度,就像如下的效果圖一樣:

浮動布局6


? ? ? 在上面的場景中,我們希望不需要明確的設(shè)置視圖C的寬度,而是通過一種比重的特性來設(shè)置視圖C總是占用容器視圖的剩余寬度的某個比例值。這里的比重的設(shè)置,是在整體布局視圖的浮動的方向的設(shè)定上的,就是說當(dāng)整體的布局視圖里面的視圖是支持左邊和右邊浮動時則這個比重指定的是視圖的寬度的相對比例值,而當(dāng)布局視圖支持的是上邊和下邊浮動時則這個比重指的是視圖的高度的相對比例值。而且我們約定比重值的設(shè)定必須大于0且小于等于1。通過比重值的設(shè)定,我們可以不需要對某個新加入的視圖設(shè)定具體的寬度或者高度,而只需要指定一個相對的值,而由浮動布局來根據(jù)當(dāng)前的浮動情況來自動計(jì)算出應(yīng)該有的寬度或者寬度。其中的具體的計(jì)算公式為:

某個設(shè)置了比重值的視圖的寬度或者高度 = (布局視圖的寬度或者高度 - 前一個視圖的右邊或者下邊的邊界值)* 視圖的比重值。

? ? ? 就以上面的左右浮動的例子來說,假設(shè)我們設(shè)定視圖C的比重為1。根據(jù)公式的定義,布局視圖的寬度是500,而前面一個視圖B的右邊邊界值是180(100+80)。因此最終視圖C的寬度就是:320 = (500 - 180)*1, 而假如設(shè)定視圖C的比重是0.5的話,則最終視圖C的寬度就是160了。又如果我們再增加一個視圖D的比重設(shè)置為1的話。因?yàn)榍懊娴囊晥DC的寬度已經(jīng)算出是160,他的右邊距值是340(180+160), 因此最終視圖D的寬度就是160 (500 - 340)*1了。其中的效果圖如下:

浮動布局7


? ? ? ?浮動布局中的子視圖可以通過設(shè)定比重來得到剩余的寬度或者高度,因此浮動布局中針對比重屬性定義新的規(guī)則如下:

7.當(dāng)某個子視圖設(shè)定了比重屬性時,這個視圖的寬度或者高度將根據(jù)布局視圖的浮動方向設(shè)定,以及比重的值的設(shè)定自動進(jìn)行計(jì)算,比重的設(shè)置必須大于0小于等于1,而通過比重計(jì)算出來的寬度或高度的公式為:布局視圖的寬度或者高度 - 前一個視圖的右邊或則下邊的邊界值)* 視圖的比重值

左右浮動

? ? ? ?上面我們的介紹的浮動的例子中,都總是默認(rèn)是向左浮動,然后再從上到下的進(jìn)行布局。但前面也有說到CSS中的元素的浮動定位是同時支持向左或向右浮動的。而我們的浮動布局也是支持某個子視圖向左或者向右浮動的。當(dāng)某個子視圖在加入到布局視圖時,可以設(shè)定為向左還是向右浮動,這里的向左和向右是不能同時支持的,視圖要么向左要么向右。對于視圖向右浮動來說,他的機(jī)制是和向左浮動是一樣的。我們可以看如下的視圖:

布局視圖8

? ?可以看出,當(dāng)A,B,C,D,E,F這幾個視圖向右浮動時,除了方向外,其他的規(guī)則是跟視圖向左浮動的規(guī)則是一樣的。一個布局視圖里面的子視圖是可以設(shè)置為向左或者向右浮動的,而前面的例子里的所有子視圖要么都向左,要么都向右。但是實(shí)際場景中我們是可以設(shè)置某些視圖向左浮動,而某些視圖向右浮動的。比如下面的例子:

浮動布局9

? ? ? 上面的例子中我們把子視圖添加到布局視圖的順序分別是A,B,C,D,E,F這個順序,且設(shè)定C,D,E這三個子視圖是向左浮動的,而A,B,F這三個子視圖是向右浮動的。在前面的所有向左浮動的例子中,我們的剩余寬度的比較總是以布局視圖的右邊界為標(biāo)準(zhǔn)的,而前面所有向右浮動的例子中我們的剩余寬度的比較總是以布局視圖的左邊界為標(biāo)準(zhǔn)的。那么當(dāng)我們的布局視圖里面的子視圖又有向左浮動的且又有向右浮動的情況時,我們的寬度邊界又是如何考慮的呢?

? ? ?我們來分析一下上面的左右浮動的例子,因?yàn)槲覀兛偸前刺砑拥南群箜樞騺磉M(jìn)行浮動布局的,所以上面的例子中A,B這兩個子視圖都向右浮動這個很容易理解,而視圖C向左浮動也比較容易理解。我們來考察當(dāng)D視圖向左浮動要插入到容器視圖時,我們發(fā)現(xiàn)如果視圖D浮動到視圖C的右邊并且上邊和視圖C保持一致時,視圖D的布局寬度將會覆蓋掉視圖B的部分空間,如果出現(xiàn)了覆蓋則是不符合浮動布局規(guī)則5中的定義的,因此視圖D必須要往下移動,直到到達(dá)視圖B的底部后才不會出現(xiàn)覆蓋現(xiàn)象,因此視圖D的上邊位置就變?yōu)榱?00,而左邊的位置則仍然等于視圖A的右邊的位置了。視圖E也是向左浮動,這里我們是要求E和最后一個加入的D必須要保持上邊對齊,但是如果保持上邊對齊的話就無法容納E的寬度而將產(chǎn)生覆蓋,因此必須要將視圖E往下移動,直到移到視圖A的下面才能滿足寬度的填充,因此視圖E的上邊位置就設(shè)置為視圖A的下邊,而左邊位置則設(shè)置為D的右邊。最后我們再來考察F的情況,雖然前面最后一個向右浮動的視圖是B,但是根據(jù)浮動規(guī)則2的約定,視圖F的上邊位置必須要和最后一個加入的視圖E的上邊位置保持一致,但是如果和E的上邊位置保持一致的話,F(xiàn)的長度將會覆蓋掉E的位置,因此視圖F必須要往下移動到視圖E的下面,并且右邊要和布局視圖的右邊界保持一致,這樣才能容納視圖F的顯示。通過上面的例子我們可以看出當(dāng)一個布局視圖中同時存在著向左浮動和向右浮動的子視圖時,我們就有浮動布局的將新增規(guī)范8的定義如下:

8.當(dāng)浮動布局中同時存在著向左和向右浮動的子視圖時,向左浮動的視圖剩余寬度的右邊界是在不覆蓋掉右邊視圖的情況下的最小向右浮動的視圖的左邊界,而向右浮動的視圖的剩余寬度的左邊界是在不覆蓋掉左邊視圖的情況下的最大向左浮動的視圖的右邊界。


上下浮動

? ? ? ?前面我們介紹向左和向右浮動的布局視圖的一些場景。在CSS中也只定義了向左和向右浮動的功能,向左向右浮動的布局視圖的原則是按視圖添加的順序,以及設(shè)定的浮動方向優(yōu)先按左或者按右浮動,然后再整體的從上到下進(jìn)行布局展示。但是在實(shí)際的情況中我們會要求有某個子視圖按向上或者向下浮動的來進(jìn)行布局,并且布局的順序是按添加的子視圖的順序優(yōu)先按向上或者按向下進(jìn)行浮動,然后再整體的從左到右進(jìn)行布局展示,這種浮動布局我們稱之為上下浮動布局。上下浮動布局里面的子視圖,進(jìn)行浮動的依據(jù)是根據(jù)子視圖本身的高度,以及布局視圖的高度來決定的(而左右浮動布局則是根據(jù)寬度來決定的)。其中的浮動規(guī)范除了方向上不同外,其他的機(jī)制都是跟左右浮動是一樣的。我們這里就不再進(jìn)行贅述了,下面我們通過一張布局來了解一下上下浮動布局的界面:

浮動布局10


? ? ? ?上圖可以看出上下浮動除了方向上和左右浮動不一樣外,其他的規(guī)則都是一致的,上下浮動布局是依然支持清除浮動的,只不過清除浮動時方向是變?yōu)榱讼蛴乙苿?。同時上下浮動布局也是支持子視圖的比重設(shè)置的,只不過這里的比重是指子視圖的高度。


MyFloatLayout的方法和屬性的介紹

? ? 說了這么多浮動布局的實(shí)現(xiàn)原理以及布局的機(jī)制,那我們怎么來使用和定義浮動布局呢?要實(shí)現(xiàn)和使用浮動布局,我們必須要使用浮動布局MyFloatLayout這個類,這個類的定義如下:

@interface MyFloatLayout : MyBaseLayout

-(id)initWithOrientation:(MyLayoutViewOrientation)orientation;

+(id)floatLayoutWithOrientation:(MyLayoutViewOrientation)orientation;

@property(nonatomic,assign) MyLayoutViewOrientation orientation;

@property(nonatomic,assign) IBInspectable MyGravity gravity;

@end

? ? ? ?從類的初始化方法中我們可以看出,在創(chuàng)建一個浮動布局時必須要指定一個方向,這個方向指的是最終子視圖的布局走向,因?yàn)樽笥腋硬季治覀兪窍劝醋笥腋幼罱K是一個從上到下的排列過程,而上下浮動布局則是先按上下浮動最終則是從左到右排列,因此當(dāng)我們指定orientation的值為MyLayoutViewOrientation_Vert表示的是創(chuàng)建一個左右浮動的浮動布局,而當(dāng)值設(shè)定為MyLayoutViewOrientation_Horz時則表示建立的是一個上下浮動的浮動布局,系統(tǒng)默認(rèn)建立的是左右浮動的浮動布局。而且后續(xù)還可以通過orientation屬性來進(jìn)行動態(tài)的修改浮動的方向。當(dāng)浮動布局的浮動方向指定后,接下來我們就要為某個要添加到浮動布局的子視圖指定浮動方向?qū)傩?、清除浮動屬性、以及比重了,這些則可以通過視圖的擴(kuò)展分類:

@interface UIView(MyFloatLayoutExt)

@property(nonatomic,assign,getter=isReverseFloat) IBInspectable BOOL reverseFloat;

@property(nonatomic,assign) IBInspectable BOOL clearFloat;

@property(nonatomic, assign) IBInspectable CGFloat weight;

@end

?來設(shè)置。 ?在默認(rèn)情況下當(dāng)我們建立的是一個左右浮動布局時,我們添加到布局里面的所有子視圖默認(rèn)都是向左浮動的,而當(dāng)建立的是一個上下浮動布局時,我們添加到布局里面的所有子視圖默認(rèn)都是向上浮動的,因此當(dāng)需要改動子視圖浮動的方向則可以設(shè)置屬性reverseFloat來實(shí)現(xiàn),這個屬性是一個BOOL類型的值,當(dāng)設(shè)置為YES時表示按默認(rèn)方向相反的方向浮動,也就是在左右浮動布局中,如果設(shè)置某個子視圖的reverseFloat為YES的話則表示子視圖是向右浮動,而對于上下浮動布局來數(shù)則表示是向下浮動。視圖的擴(kuò)展屬性clearFloat也是一個BOOL類型,表示是否清除浮動,默認(rèn)值是NO表示不清除浮動,當(dāng)某個子視圖需要有清除浮動的效果時,請將這個屬性設(shè)置為YES。最后一個視圖的擴(kuò)展屬性weight表示視圖的寬度或者高度的比重,這個值默認(rèn)值是0,表示不是按比重來指定寬度,這時候你在添加子視圖時必須明確的指定寬度或者高度,而當(dāng)設(shè)置為非0時則不需要為子視圖指定寬度和高度,而由布局系統(tǒng)來自動幫你計(jì)算。這里的weight的設(shè)置范圍是:0<=weight <=1.

? ? ? ?上面分別的介紹了浮動布局的建立,以及子視圖的擴(kuò)展的屬性設(shè)置來實(shí)現(xiàn)視圖在浮動布局中的浮動方式、是否清除浮動、以及比重的設(shè)置方法。另外對于浮動布局來說,因?yàn)槭菑腗yBaseLayout中派生的,因此浮動布局同樣支持wrapContentWidth以及wrapContentHeight屬性的設(shè)置的,也就是浮動布局的寬高可以由子視圖來決定的,需要明確的是一般情況下我們對于左右浮動布局來說,只需要設(shè)置wrapContentHeight。當(dāng)然你也可以設(shè)置wrapContentWidth(設(shè)置這個屬性的前提是布局視圖里面有一個子視圖特別的寬);同樣對于上下浮動布局來說,只需要設(shè)置wrapContentWidth。當(dāng)然你也可以設(shè)置wrapContentHeight(設(shè)置這個屬性的前提是布局視圖里面有一個子視圖特別的高)。

? ? ? ? 最后,我們看到浮動布局視圖里面還有一個gravity屬性,這個屬性在左右浮動布局視圖中可以用來設(shè)置所有子視圖的整體的上,中,下三種停靠模式,而在上下浮動布局視圖中則可以用來設(shè)置所有子視圖的整體的左,中,右三種停靠模式。

? ? 下面的效果圖就是我們使用浮動布局來實(shí)現(xiàn)的仿天貓和ZAKER界面布局的效果圖:


浮動布局DEMO


? ? ? 上面的gif圖片中有三個DEMO分別介紹浮動布局的,你可以通過DEMO中的FOLTest1ViewController來研究和學(xué)習(xí)浮動布局的各種屬性的設(shè)置以及效果,而FOLTest2ViewController則是介紹的天貓首頁的布局、FOLTest3ViewController介紹的則是ZAKER的卡片式布局的實(shí)現(xiàn)。通過DEMO我們可以看出,當(dāng)我們要實(shí)現(xiàn)一些不規(guī)則的界面布局時,我們并不需要使用相對布局來實(shí)現(xiàn),而只需設(shè)定正確的子視圖的添加順序,以及浮動屬性的設(shè)置就能達(dá)到我們想要的效果,而且采用浮動布局的優(yōu)點(diǎn)時不需要再去考慮視圖之間的依賴關(guān)系的設(shè)置了。

智能邊界線

? ? ?為了說明智能邊界線我們先來看這兩個界面:

浮動布局11

? ? ? ?上面的兩個界面是仿淘寶和天貓首頁以及ZAKER新聞的界面,我們來觀察其中的每個區(qū)塊之間的邊界線。我們發(fā)現(xiàn)處在邊緣部分是沒有顯示邊界線的,而邊界線只會顯示在區(qū)塊交界的地方顯示一條邊界線。在一般情況下,不規(guī)則邊界線的顯示我們有可能需要UI人員提供圖片來完成,或者不提供圖片我們在編程時也需要進(jìn)行條件的判斷以便決定是否需要在特定的位置繪制邊界線,顯然這樣做將會增加我們的代碼量。因此為了解決這個問題,我們的布局系統(tǒng)提供了邊界線以及智能邊界線的功能。如果您用了MyBaseLayout派生的6大布局的話,我們是可以通過基類提供的四個屬性:

@property(nonatomic, strong) MyBorderline *leftBorderline;

@property(nonatomic, strong) MyBorderline *rightBorderline;

@property(nonatomic, strong) MyBorderline *topBorderline;

@property(nonatomic, strong) MyBorderline *bottomBorderline;

來為布局視圖指定要顯示的四邊的邊界線,我們可以支持設(shè)置邊界線的顏色,粗細(xì),縮進(jìn),以及點(diǎn)線等功能,這樣我們就不再需要單獨(dú)的提供邊界線的切圖了。要想看邊界線的例子,可以查看LLTest4ViewController和AllTest3ViewController這兩個DEMO的介紹。即便如此,對于上面的特殊情況,我們還需要進(jìn)行編程以及條件判斷來完成邊界線的指定,因此為了解決這個問題,我們在布局中新增加了一個智能邊界線的屬性:

@property(nonatomic, strong) MyBorderline *intelligentBorderline;

@property(nonatomic, assign) BOOL notUseIntelligentBorderline;

如果為某個布局視圖設(shè)置了智能邊界線的值,那么這個布局視圖里面的子布局視圖將會根據(jù)視圖之間的關(guān)系而自動智能的生成邊界線。這里需要強(qiáng)調(diào)的是只有布局視圖里面的子布局視圖才會生成智能的邊界線,對于布局視圖里面的非布局子視圖是不會生成邊界線的。而如果我們的某個布局視圖里面的子布局視圖不想使用智能的邊界線,而是仍想自己手動設(shè)定,那么只需要將自己的notUseIntelligentBorderline設(shè)置為YES即可,他表示不使用父布局提供的智能邊界線功能。在當(dāng)前的布局庫版本中,我們只有線性布局、浮動布局、表格布局、流式布局支持智能邊界線的設(shè)定,而框架布局、相對布局則是不支持的。正是因?yàn)椴季窒到y(tǒng)里面提供的智能邊界線的功能,就使得我們在設(shè)定布局視圖之間的邊界線時非常的簡單,只需要一句話就能搞定。

浮動布局的實(shí)踐

? ? ? ?上面就是我們要介紹的關(guān)于浮動布局的全部的東西,接下來我們將借著DEMO中的代碼來具體的介紹我們?nèi)绾问褂酶硬季謥韺?shí)現(xiàn)上面的功能的。在介紹之前,我們這里說明一下,我們?nèi)匀皇强梢杂米右晥D的擴(kuò)展屬性myLeft,myRight,myTop,myBottom這4個屬性來指定視圖之間的間距的。同時我們還支持子視圖的寬度擴(kuò)展屬性widthSize的值可以設(shè)置為一個具體值,也可以等于布局視圖的寬度,以及前面已經(jīng)布好局的子視圖的寬度,甚至還可以等于子視圖的高度。 ?

? ? ?因?yàn)樗械年P(guān)于浮動布局的代碼我們都能在DEMO中找到,因?yàn)槲覀冎唤榻B幾個例子,其他的大家可以自己去研究,我們看下面的圖:


浮動布局12


? ? ? ?我們看到上面的界面左上角的區(qū)塊的高度為180,而其余的區(qū)塊都是90,并且每個區(qū)塊的寬度都是屏幕的一半。為了容納上面的界面我們需要先建立左右浮動的浮動布局:

CGFloat itemHeight = 90;

//品牌特賣

MyFloatLayout *layout1 = [MyFloatLayout floatLayoutWithOrientation:MyLayoutViewOrientation_Vert];

layout1.backgroundColor = [UIColor whiteColor];

layout1.wrapContentHeight = YES;

layout1.intelligentBorderline = [[MyBorderline alloc] initWithColor:[UIColor lightGrayColor]];


我們設(shè)定的layout1的高度由子視圖決定,并且設(shè)置了智能邊界線。接下來我們只需要每個區(qū)塊按順序依次添加進(jìn)來即可。且從上面的區(qū)域中我們可以看出一共有3種不同的類型的區(qū)塊分別是A,B, C三種區(qū)塊,這三種區(qū)塊其實(shí)是用MyFloatLayout來實(shí)現(xiàn)的。

? ? ? A區(qū)塊我們也可以用一個浮動布局來實(shí)現(xiàn),我們只需要建立一個上下浮動布局,標(biāo)題,小圖都默認(rèn)往上浮動。剩下的大圖寬度和父布局寬度相等,并且設(shè)置weight=1就可以了,這部分代碼的具體實(shí)現(xiàn)就在FOLTest2ViewController中的createItemLayout1_1的方法中實(shí)現(xiàn)。

? ? ? B區(qū)塊我們也可以用浮動布局來實(shí)現(xiàn),我們只需要建立一個左右浮動布局,大圖片優(yōu)先向右浮動,高度和父布局高度相等,接下來主標(biāo)題向左浮動,并且weight=1表示占用剩余的寬度;副標(biāo)題也是向左浮動,并且設(shè)置清除浮動屬性,同時設(shè)置weight=1表示占用剩余的寬度;最后的小圖也是設(shè)置為左浮動,并且設(shè)置清除浮動屬性。這部分代碼的具體實(shí)現(xiàn)在FOLTest2ViewController中的createItemLayout1_3的方法中實(shí)現(xiàn).

? ? ? ?C區(qū)塊我們也可以用浮動布局來實(shí)現(xiàn),我們只需要建立一個左右浮動布局,主標(biāo)題部分向左浮動,并且寬度和父布局寬度相等,付標(biāo)題部分向左浮動,并且寬度和父布局寬度相等,而圖片部分則向右浮動即可。

最后我們可以依次建立A,B,C三種區(qū)塊然后依次的加入到layout1中去,加入時只需要設(shè)置A的高度為180,而寬度則是layout1的一半即可,而其他兩種則高度設(shè)置為80,且寬度設(shè)置為layout1的一半即可。


小結(jié)

? ? ? 浮動布局是一種功能非常強(qiáng)大的布局體系,從某種程度上來他甚至是相對布局的替代方案,而且要比相對布局要簡單,因?yàn)槔锩娴淖右晥D之間是不需要設(shè)置約束和依賴關(guān)系的,單單憑借加入到布局視圖的順序,以及自身的寬高就能完成我們想要的功能。而且其提供的能力甚至要比CSS中的浮動屬性更加強(qiáng)大。而我們在進(jìn)行WEB前端開發(fā)時很多的界面布局其實(shí)都是通過CSS的浮動屬性來完成的。因此我們也可以借助浮動布局來我們各種復(fù)雜的界面布局,而且浮動布局也能方便的實(shí)現(xiàn)線性布局以及流式布局的能力。如果您想了解更多的關(guān)于流式布局的功能請您訪問我的github站點(diǎn)來了解更多:

OC版本:https://github.com/youngsoft/MyLinearLayout

Swift版本: https://github.com/youngsoft/TangramKit

如果您覺得庫還不錯,記得為我點(diǎn)贊哦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容