iOS下的界面布局利器-MyLayout布局框架
簡介
MyLayout 是一套iOS界面視圖布局框架。其內核是基于對UIView的layoutSubviews方法的重載以及對子視圖的bounds和center屬性的設置而實現的。MyLayout功能強大而且簡單易用,它集成了iOS Autolayout和Size Classes、android的5大布局體系、HTML/CSS的浮動定位技術以及flex-box和bootstrap框架等市面上主流的平臺的界面布局功能,同時提供了一套非常簡單和完備的多屏幕尺寸適配的解決方案。MyLayout還提供了Swift版本 TangramKit
MyLayout的優勢
-
MyLayout的實現內核是基于frame的設置,而不是對AutoLayout的封裝。因此在使用上不會受到任何操作系統版本的限制。
-
有文章表明用frame進行布局的性能要高于用AutoLayout進行布局的性能,尤其是當界面內視圖數量增加時效果更加明顯。
-
AutoLayout的思想是通過視圖之間的約束依賴來完成布局,但是約束依賴的結果是造成視圖之間的耦合性高而增大了界面更新的成本。而MyLayout則除了提供約束依賴外,還提供了根據視圖添加順序自動建立約束的功能,從而減少了這種顯示依賴關系建立的問題,最終的結果是簡化了布局的代碼量,以及減少了布局更新時的代碼修改量。
-
AutoLayout只是一種相對約束的布局,而MyLayout除了同時提供具有和AutoLayout相同能力的相對布局外、還提供了線性布局、框架布局、表格布局、流式布局、浮動布局、路徑布局7大布局體系,你完全可以根據你的界面需求來選擇一種最簡易的布局容器來實現你的功能,同時MyLayout還支持Size classes的機制,以及提供了一些實現屏幕尺寸完美適配的方法。
-
MyLayout主要是一種通過代碼進行布局的解決方案,但是框架一樣可以支持和XIB以及SB結合布局的方式。并提供了視圖隱藏和顯示時會自動激發布局、布局視圖的高度自適應(UITableviewCell動態高度)、標簽云實現、左右內容寬度自適應、按比例分配尺寸和間距、整體停靠控制等等各種強大的功能。
AutoLayout和frame布局的性能比較
應用場景
舉例下面一個應用場景:
-
有一個容器視圖S的寬度是100而高度則是由四個從上到下依次排列的子視圖A,B,C,D的高度總和。
-
視圖A的左邊距占用父視圖寬度的20%,而右邊距則占用父視圖寬度的30%,高度則等于自身的寬度。
-
視圖B的左邊距是40,寬度則占用父視圖的剩余寬度,高度是40。
-
視圖C的寬度占用父視圖的所有寬度,高度是40。
-
視圖D的右邊距是20,寬度是父視圖寬度的50%,高度是40。
最終的效果圖如下:
MyLinearLayout *S = [MyLinearLayout linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.subviewMargin = 10;
S.myWidth = 100;
UIView *A = UIView.new;
A.leftPos.equalTo(@0.2);
A.rightPos.equalTo(@0.3);
A.heightDime.equalTo(A.widthDime);
[S addSubview:A];
UIView *B = UIView.new;
B.leftPos.equalTo(@40);
B.widthDime.equalTo(@60);
B.heightDime.equalTo(@40);
[S addSubview:B];
UIView *C = UIView.new;
C.widthDime.equalTo(S.widthDime);
C.heightDime.equalTo(@40);
[S addSubview:C];
UIView *D = UIView.new;
D.rightPos.equalTo(@20);
D.widthDime.equalTo(S.widthDime).multiply(0.5);
D.heightDime.equalTo(@40);
[S addSubview:D];</code></pre>
系統結構

布局位置類MyLayoutPos
MyLayoutPos類是用來描述一個視圖所在的位置的類。UIView中擴展出了leftPos,topPos,bottomPos,rightPos,centerXPos,centerYPos這六個變量來實現視圖的定位操作。您可以用這些變量的equalTo方法來設置視圖之間的邊距和間距。 equalTo 方法可以設置NSNumber, MyLayoutPos, NSArray 這幾種值,分別用于不同的場景。同時系統提供了6個簡單的變量myLeftMargin, myTopMargin, myBottomMargin, myRightMargin, myCenterXOffset, mYCenterYOffset來設置NSNumber類型的值,比如 A.leftPos.equalTo(@10); 等價于 A.myLeftMargin = 10;.
布局尺寸類MyLayoutSize
MyLayoutSize類是用來描述一個視圖的尺寸的類。UIView中擴展出了widthDime,heightDime這兩個變量來實現視圖的寬度和高度尺寸的設置。您可以用其中的equalTo方法來設置視圖的寬度和高度。equalTo方法可以設置NSNumber, MyLayoutSize, NSArray 這幾種值,分別用于不同的場景。同時系統提供了2個簡單的變量myWidth,myHeight來設置NSNumber類型的值,比如A.widthDime.equalTo(@10); 等價于A.myWidth = 10;.
線性布局MyLinearLayout
等價于iOS的UIStackView和android的LinearLayout布局。
線性布局是一種里面的子視圖按添加的順序從上到下或者從左到右依次排列的單列(單行)布局視圖,因此里面的子視圖是通過添加的順序建立約束和依賴關系的。 子視圖從上到下依次排列的線性布局視圖稱為垂直線性布局視圖,而子視圖從左到右依次排列的線性布局視圖則稱為水平線性布局。

演示效果圖
示例代碼:
-(void)loadView
{
[super loadView];
MyLinearLayout *S = [MyLinearLayout linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.myWidth = 120;
S.subviewMargin = 10;
UIView *A = [UIView new];
A.myLeftMargin = A.myRightMargin = 5;
A.myHeight = 40;
[S addSubview:A];
UIView *B = [UIView new];
B.myLeftMargin = 20;
B.myWidth = B.myHeight = 40;
[S addSubview:B];
UIView *C = [UIView new];
C.myRightMargin = 40;
C.myWidth = 50;
C.myHeight = 40;
[S addSubview:C];
UIView *D = [UIView new];
D.myLeftMargin = D.myRightMargin = 10;
D.myHeight = 40;
[S addSubview:D];
[self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
}</code></pre>
相對布局MyRelativeLayout
等價于iOS的AutoLayout 和 Android的RelativeLayout布局。
相對布局是一種里面的子視圖通過相互之間的約束和依賴來進行布局和定位的布局視圖。相對布局里面的子視圖的布局位置和添加的順序無關,而是通過設置子視圖的相對依賴關系來進行定位和布局的。

演示效果圖
示例代碼:
-(void)loadView
{
[super loadView];
MyRelativeLayout *S = [MyRelativeLayout new];
S.widthDime.equalTo(@170);
S.heightDime.equalTo(@280);
UIView *A = [UIView new];
A.leftPos.equalTo(@20);
A.topPos.equalTo(@20);
A.widthDime.equalTo(@40);
A.heightDime.equalTo(A.widthDime);
[S addSubview:A];
UIView *B = [UIView new];
B.leftPos.equalTo(A.centerXPos);
B.topPos.equalTo(A.bottomPos).offset(10);
B.widthDime.equalTo(@60);
B.heightDime.equalTo(A.heightDime);
[S addSubview:B];
UIView *C = [UIView new];
C.leftPos.equalTo(B.rightPos).offset(10);
C.bottomPos.equalTo(B.bottomPos);
C.widthDime.equalTo(@40);
C.heightDime.equalTo(B.heightDime).multiply(0.5);
[S addSubview:C];
UIView *D = [UIView new];
D.bottomPos.equalTo(C.topPos).offset(10);
D.rightPos.equalTo(@15);
D.heightDime.equalTo(A.heightDime);
D.widthDime.equalTo(D.heightDime);
[S addSubview:D];
UIView *E = [UIView new];
E.centerYPos.equalTo(@0);
E.centerXPos.equalTo(@0);
E.heightDime.equalTo(@40);
E.widthDime.equalTo(S.widthDime).add(-20);
[S addSubview:E];
//.. F, G
[self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
E.backgroundColor = [UIColor magentaColor];
}</code></pre>
框架布局MyFrameLayout
等價于Android的FrameLayout布局。
框架布局是一種里面的子視圖停靠在父視圖特定方位并且可以重疊的布局視圖。框架布局里面的子視圖的布局位置和添加的順序無關,只跟父視圖建立布局約束依賴關系。框架布局將垂直方向上分為上、中、下三個方位,而水平方向上則分為左、中、右三個方位,任何一個子視圖都只能定位在垂直方向和水平方向上的一個方位上。

演示效果圖
示例代碼:
-(void)loadView
{
[super loadView];
MyFrameLayout *S = [MyFrameLayout new];
S.mySize = CGSizeMake(320,500);
UIView *A = [UIView new];
A.mySize = CGSizeMake(40,40);
[S addSubview:A];
UIView *B = [UIView new];
B.mySize = CGSizeMake(40,40);
B.myRightMargin = 0;
[S addSubview:B];
UIView *C = [UIView new];
C.mySize = CGSizeMake(40,40);
C.myCenterYOffset = 0;
[S addSubview:C];
UIView *D = [UIView new];
D.mySize = CGSizeMake(40,40);
D.myCenterOffset = CGPointZero;
[S addSubview:D];
//..E,F,G
[self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
}</code></pre>
表格布局MyTableLayout
等價于Android的TableLayout布局和HTML的table元素。
表格布局是一種里面的子視圖可以像表格一樣多行多列排列的布局視圖。子視圖添加到表格布局視圖前必須先要建立并添加行視圖,然后再將子視圖添加到行視圖里面。如果行視圖在表格布局里面是從上到下排列的則表格布局為垂直表格布局,垂直表格布局里面的子視圖在行視圖里面是從左到右排列的;如果行視圖在表格布局里面是從左到右排列的則表格布局為水平表格布局,水平表格布局里面的子視圖在行視圖里面是從上到下排列的。

演示效果圖
示例代碼:
-(void)loadView
{
[super loadView];
MyTableLayout *S = [MyTableLayout tableLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.wrapContentWidth = YES;
S.rowSpacing = 10;
S.colSpacing = 10;
[S addRow:MTLSIZE_WRAPCONTENT colSize:MTLSIZE_WRAPCONTENT];
UIView *A = [UIView new];
A.mySize = CGSizeMake(50,40);
[S addSubview:A];
UIView *B = [UIView new];
B.mySize = CGSizeMake(100,40);
[S addSubview:B];
UIView *C = [UIView new];
C.mySize = CGSizeMake(30,40);
[S addSubview:C];
[S addRow:MTLSIZE_WRAPCONTENT colSize:MTLSIZE_WRAPCONTENT];
UIView *D = [UIView new];
D.mySize = CGSizeMake(200,40);
[S addSubview:D];
//...E,F
[self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
}</code></pre>
流式布局MyFlowLayout
等價于CSS3的flex-box。
流式布局是一種里面的子視圖按照添加的順序依次排列,當遇到某種約束限制后會另起一行再重新排列的多行展示的布局視圖。這里的約束限制主要有數量約束限制和內容尺寸約束限制兩種,而換行的方向又分為垂直和水平方向,因此流式布局一共有垂直數量約束流式布局、垂直內容約束流式布局、水平數量約束流式布局、水平內容約束流式布局。流式布局主要應用于那些子視圖有規律排列的場景,在某種程度上可以作為UICollectionView的替代品。

演示效果圖
示例代碼:
-(void)loadView
{
[super loadView];
MyFlowLayout *S = [MyFlowLayout flowLayoutWithOrientation:MyLayoutViewOrientation_Vert arrangedCount:4];
S.wrapContentHeight = YES;
S.myWidth = 300;
S.padding = UIEdgeInsetsMake(10, 10, 10, 10);
S.gravity = MyMarginGravity_Horz_Fill;
S.subviewMargin = 10;
for (int i = 0; i < 10; i++)
{
UIView *A = [UIView new];
A.heightDime.equalTo(A.widthDime);
[S addSubview:A];
A.backgroundColor = [UIColor greenColor];
}
[self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
}</code></pre>
浮動布局MyFloatLayout
等價于css中的float定位。
浮動布局是一種里面的子視圖按照約定的方向浮動停靠,當尺寸不足以被容納時會自動尋找最佳的位置進行浮動停靠的布局視圖。浮動布局的理念源于HTML/CSS中的浮動定位技術,因此浮動布局可以專門用來實現那些不規則布局或者圖文環繞的布局。根據浮動的方向不同,浮動布局可以分為左右浮動布局和上下浮動布局。

演示效果圖
示例代碼:
-(void)loadView
{
[super loadView];
MyFloatLayout *S = [MyFloatLayout floatLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.wrapContentHeight = YES;
S.padding = UIEdgeInsetsMake(10, 10, 10, 10);
S.subviewMargin = 10;
S.myWidth = 300;
UIView *A = [UIView new];
A.mySize = CGSizeMake(80,70);
[S addSubview:A];
UIView *B = [UIView new];
B.mySize = CGSizeMake(150,40);
[S addSubview:B];
UIView *C = [UIView new];
C.mySize = CGSizeMake(70,40);
[S addSubview:C];
UIView *D = [UIView new];
D.mySize = CGSizeMake(100,140);
[S addSubview:D];
UIView *E = [UIView new];
E.mySize = CGSizeMake(150,40);
E.reverseFloat = YES;
[S addSubview:E];
UIView *F = [UIView new];
F.mySize = CGSizeMake(120,60);
[S addSubview:F];
[self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
E.backgroundColor = [UIColor blackColor];
F.backgroundColor = [UIColor whiteColor];
}</code></pre>
路徑布局MyPathLayout
布局庫獨有
路徑布局是一種里面的子視圖根據您提供的一條特定的曲線函數形成的路徑來進行布局的布局視圖。您需要提供一個實現曲線路徑的函數、一個特定的坐標體系、一種特定的子視圖在曲線上的距離設置這三個要素來實現界面布局。當曲線路徑形成后,子視圖將按相等的距離依次環繞著曲線進行布局。路徑布局主要應用于那些具有特定規律的不規則排列,而且效果很酷炫的的界面布局。

演示效果圖
示例代碼:
-(void)loadView
{
[super loadView];
MyPathLayout *S = [MyPathLayout new];
S.mySize = CGSizeMake(320,320);
S.coordinateSetting.isReverse = YES;
S.coordinateSetting.origin = CGPointMake(0.5, 0.2);
S.polarEquation = ^(CGFloat angle)
{
return 80 * (1 + cos(angle));
};
for (int i = 0; i < 4; i++)
{
UIView *A = [UIView new];
A.mySize = CGSizeMake(40,40);
[S addSubview:A];
A.backgroundColor = [UIColor greenColor];
}
[self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
}</code></pre>
Size Classes的支持
等價于iOS的Size Classes
MyLayout布局體系為了實現對不同屏幕尺寸的設備進行適配,提供了對Size Classes的支持。您可以將Size Classes和上述的6種布局搭配使用,以便實現各種設備界面的完美適配。系統提供2個UIView的擴展方法:
-(instancetype)fetchLayoutSizeClass:(MySizeClass)sizeClass;
-(instancetype)fetchLayoutSizeClass:(MySizeClass)sizeClass copyFrom:(MySizeClass)srcSizeClass;
來實現對Size Classes的支持。比如下面的例子:
//默認所有設備的設置。
MyLinearLayout *rootLayout = [MyLinearLayout linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
rootLayout.padding = UIEdgeInsetsMake(10, 10, 10, 10);
rootLayout.wrapContentHeight = NO;
rootLayout.gravity = MyMarginGravity_Horz_Fill;
//MySizeClass_wAny | MySizeClass_hCompact 表明的是iPhone設備的橫屏.
MyLinearLayout *lsc = [rootLayout fetchLayoutSizeClass:MySizeClass_wAny | MySizeClass_hCompact copyFrom:MySizeClass_wAny | MySizeClass_hAny];
lsc.orientation = MyLayoutViewOrientation_Horz;
lsc.wrapContentWidth = NO;
lsc.gravity = MyMarginGravity_Vert_Fill;</code></pre>
使用方法
直接拷貝
1.將github工程中的Lib文件夾下的所有文件復制到您的工程中。
2.將#import "MyLayout.h" 頭文件放入到您的pch文件中,或者在需要使用界面布局的源代碼位置。
CocoaPods安裝
如果您還沒有安裝cocoapods則請先執行如下命令:
$ gem install cocoapods
為了用CocoaPods整合MyLayout到您的Xcode工程, 請建立如下的Podfile:
source '
pod 'MyLayout', '~> 1.3.4'</code></pre>
然后運行如下命令:
$ pod install
演示效果圖

MyLayout演示效果圖
來自:http://www.cocoachina.com/ios/20170313/18871.html