iOS下的介面布局利器-MyLayout布局架構,ios-mylayout
- Swift:TangramKit: https://github.com/youngsoft/TangramKit
- OC:MyLayout: https://github.com/youngsoft/MyLinearLayout
簡介
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布局的效能比較
參考的文章地址: http://floriankugler.com/2013/04/22/auto-layout-performance-on-ios/
應用情境
舉例下面一個應用情境:
- 有一個[內容] 檢視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];
系統結構
布局位置類MyLayoutPos
MyLayoutPos類是用來描述一個視圖所在的位置的類。UIView中擴充出了leftPos,topPos,bottomPos,rightPos,centerXPos,centerYPos這六個變數來實現視圖的定位操作。您可以用這些變數的equalTo
方法來設定視圖之間的邊距和間距。 equalTo
方法可以設定NSNumber, MyLayoutPos, NSArray<MyLayoutPos*>這幾種值,分別用於不同的情境。同時系統提供了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<MyLayoutSize*>這幾種值,分別用於不同的情境。同時系統提供了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]; }
相對布局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];}
架構布局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]; }
表格版面配置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];}
流式布局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];}
浮動布局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];}
路徑布局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]; }
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;
使用方法直接拷貝CocoaPods安裝
如果您還沒有安裝cocoapods則請先執行如下命令:
$ gem install cocoapods
為了用CocoaPods整合MyLayout到您的Xcode工程, 請建立如下的Podfile:
source 'https://github.com/CocoaPods/Specs.git'platform :ios, '7.0'pod 'MyLayout', '~> 1.3.4'
然後運行如下命令:
$ pod install
示範 連結:
歡迎大家訪問我的github網站,並關注@歐陽大哥
- Swift:TangramKit: https://github.com/youngsoft/TangramKit
- OC:MyLayout: https://github.com/youngsoft/MyLinearLayout