iOS開(kāi)發(fā)框架--MyLayout
MyLayout 框架不僅支持 Objective-C,也可以在 Swift 中使用。通過(guò) MyLayout,可以使用面向?qū)ο蟮姆绞絹?lái)創(chuàng)建和管理視圖的布局,簡(jiǎn)化了 Auto Layout 中繁瑣的約束設(shè)置流程。在 Objective-C 中,MyLayout 提供了相同的布局類(lèi)型和屬性,使用方式稍有不同,主要是語(yǔ)法和調(diào)用方式上的差異。
先介紹一下如何使用吧,線性布局和相對(duì)布局是用的比較多的布局方式。
1. 線性布局(MyLinearLayout)
線性布局是一種里面的子視圖按添加的順序從上到下或者從左到右依次排列的單列(單行)布局視圖,因此里面的子視圖是通過(guò)添加的順序建立約束和依賴(lài)關(guān)系的。 子視圖從上到下依次排列的線性布局視圖稱(chēng)為垂直線性布局視圖,而子視圖從左到右依次排列的線性布局視圖則稱(chēng)為水平線性布局
創(chuàng)建一個(gè)垂直線性布局的示例:
MyLinearLayout *rootLayout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
rootLayout.frame = self.view.bounds;
rootLayout.topPos.equalTo(@0);
rootLayout.leftPos.equalTo(@0);
rootLayout.rightPos.equalTo(@0);
rootLayout.bottomPos.equalTo(@0);
// 添加子視圖
UIView *view1 = [UIView new];
view1.myHeight = 50;
view1.leftPos.equalTo(@10);
view1.rightPos.equalTo(@10);
[view1 setBackgroundColor:[UIColor redColor]];
[rootLayout addSubview:view1];
UIView *view2 = [UIView new];
view2.myHeight = 100;
view2.leftPos.equalTo(@10);
view2.rightPos.equalTo(@10);
[view2 setBackgroundColor:[UIColor blueColor]];
[rootLayout addSubview:view2];
[self.view addSubview:rootLayout];
在這個(gè)例子中,我們創(chuàng)建了一個(gè)垂直線性布局容器 rootLayout,并在其中添加了兩個(gè) UIView 子視圖。每個(gè)子視圖都有自己的高度和邊距設(shè)置。view1 和 view2 分別設(shè)置了不同的高度,且左右邊距為 10。
2. 相對(duì)布局(MyRelativeLayout)
相對(duì)布局允許子視圖通過(guò)相對(duì)父視圖或者其他子視圖的位置來(lái)布局。
相對(duì)布局示例:
MyRelativeLayout *rootLayout = [MyRelativeLayout new];
rootLayout.frame = self.view.bounds;
rootLayout.topPos.equalTo(@0);
rootLayout.leftPos.equalTo(@0);
rootLayout.rightPos.equalTo(@0);
rootLayout.bottomPos.equalTo(@0);
UIView *view1 = [UIView new];
view1.mySize = CGSizeMake(100, 100);
view1.centerXPos.equalTo(rootLayout.centerXPos); // 水平居中
view1.topPos.equalTo(@10); // 距離父視圖頂部 10
[view1 setBackgroundColor:[UIColor redColor]];
[rootLayout addSubview:view1];
UIView *view2 = [UIView new];
view2.mySize = CGSizeMake(100, 100);
view2.topPos.equalTo(view1.bottomPos).offset(10); // 位于 view1 底部,間隔 10
view2.centerXPos.equalTo(view1.centerXPos); // 水平與 view1 對(duì)齊
[view2 setBackgroundColor:[UIColor blueColor]];
[rootLayout addSubview:view2];
[self.view addSubview:rootLayout];
在這個(gè)示例中,view1 在父視圖中水平居中,并且距離頂部有 10 的間隔。而 view2 則位于 view1 的下方,并保持水平對(duì)齊。通過(guò)設(shè)置 centerXPos 和 topPos 等屬性,MyLayout 可以輕松實(shí)現(xiàn)相對(duì)布局。
3. 布局框架的類(lèi)架構(gòu)
這張圖展示了 MyLayout 布局框架的類(lèi)架構(gòu),幫助開(kāi)發(fā)者理解其內(nèi)部設(shè)計(jì)和結(jié)構(gòu)。

-
MyBaseLayout:
- 這是 MyLayout 框架的基礎(chǔ)類(lèi),所有具體的布局類(lèi)(如
MyLinearLayout、MyFrameLayout等)都繼承自它。它負(fù)責(zé)處理布局容器的基礎(chǔ)功能,如視圖的排列、布局更新等。
- 這是 MyLayout 框架的基礎(chǔ)類(lèi),所有具體的布局類(lèi)(如
-
布局子類(lèi):
- 從
MyBaseLayout派生的不同布局類(lèi)型用于支持多種布局方式:- MyLinearLayout:線性布局,視圖依次排列,可以是垂直或水平。
- MyFrameLayout:幀布局,子視圖重疊在一起,根據(jù)設(shè)置的大小、位置顯示。
- MyRelativeLayout:相對(duì)布局,子視圖可以相對(duì)于其他視圖或容器進(jìn)行布局。
- MyFlowLayout:流式布局,子視圖按行或列排列,類(lèi)似于文本換行的效果。
- MyFloatLayout:浮動(dòng)布局,視圖可以根據(jù)容器空間自動(dòng)排列。
- MyPathLayout:路徑布局,子視圖可以沿著路徑排列。
- MyGridLayout:網(wǎng)格布局,子視圖按網(wǎng)格排列。
- MyTableLayout:表格布局,子視圖按表格形式排列。
- 從
-
MyViewSizeClass 和子類(lèi):
MyViewSizeClass是用于定義視圖在不同尺寸類(lèi)別下的表現(xiàn),類(lèi)似于 iOS 的 Size Class 概念。MyLayoutViewSizeClass是它的子類(lèi),用于處理 MyLayout 視圖的大小、邊距、位置等屬性。- 不同的布局有各自的
ViewSizeClass,如MyLinearLayoutViewSizeClass、MyTableLayoutViewSizeClass等,來(lái)定義在這些布局中的尺寸規(guī)則。
-
UIView 的擴(kuò)展 (Category):
- 通過(guò)對(duì)
UIView進(jìn)行擴(kuò)展,MyLayout 框架為視圖添加了自定義布局屬性,如leftPos、topPos、widthSize、heightSize等。這些屬性與MyLayoutPos和MyLayoutSize類(lèi)相關(guān)聯(lián),幫助開(kāi)發(fā)者通過(guò)簡(jiǎn)單的設(shè)置實(shí)現(xiàn)復(fù)雜的布局需求。
- 通過(guò)對(duì)
-
MyLayoutPos 和 MyLayoutSize:
-
MyLayoutPos:MyLayoutPos類(lèi)是用來(lái)描述一個(gè)視圖所在的位置的類(lèi)。UIView中擴(kuò)展出了leftPos,topPos,bottomPos,rightPos,centerXPos,centerYPos這六個(gè)變量來(lái)實(shí)現(xiàn)視圖的定位操作。您可以用這些變量的equalTo方法來(lái)設(shè)置視圖之間的邊距和間距。 equalTo 方法可以設(shè)置NSNumber, MyLayoutPos, NSArray<MyLayoutPos*>這幾種值,分別用于不同的場(chǎng)景。同時(shí)系統(tǒng)提供了6個(gè)簡(jiǎn)單的變量myLeft, myTop, myBottom, myRight, myCenterX, mYCenterY來(lái)設(shè)置NSNumber類(lèi)型的值,比如 A.leftPos.equalTo(@10); 等價(jià)于 A.myLeft = 10;.
-
MyLayoutSize:MyLayoutSize類(lèi)是用來(lái)描述一個(gè)視圖的尺寸的類(lèi)。UIView中擴(kuò)展出了widthSize,heightSize這兩個(gè)變量來(lái)實(shí)現(xiàn)視圖的寬度和高度尺寸的設(shè)置。您可以用其中的equalTo方法來(lái)設(shè)置視圖的寬度和高度。equalTo方法可以設(shè)置NSNumber, MyLayoutSize, NSArray<MyLayoutSize*>這幾種值,分別用于不同的場(chǎng)景。同時(shí)系統(tǒng)提供了2個(gè)簡(jiǎn)單的變量myWidth,myHeight來(lái)設(shè)置NSNumber類(lèi)型的值,比如A.widthSize.equalTo(@10); 等價(jià)于A.myWidth = 10;.
-
-
MyWeight:
MyWeight是一個(gè)與布局權(quán)重相關(guān)的概念,用于控制視圖在容器中占據(jù)的相對(duì)空間。
通過(guò)這個(gè)類(lèi)架構(gòu)圖,可以看到 MyLayout 框架是如何通過(guò)繼承和擴(kuò)展的方式,將多種布局模式整合到一個(gè)框架中,從而簡(jiǎn)化復(fù)雜布局的實(shí)現(xiàn)。
4. 底層原理
MyLayout 的底層原理主要是通過(guò)對(duì)每個(gè)視圖的布局屬性(如 myLeftMargin、myWidth、myHeight 等)進(jìn)行計(jì)算,并在布局容器中根據(jù)這些屬性重新調(diào)整每個(gè)子視圖的位置和大小。這個(gè)過(guò)程與 Auto Layout 系統(tǒng)相似,但 MyLayout 不依賴(lài) iOS 自帶的 Auto Layout 約束機(jī)制,而是通過(guò)手動(dòng)布局來(lái)優(yōu)化性能和簡(jiǎn)化實(shí)現(xiàn)。
1. 視圖樹(shù)遍歷與布局計(jì)算
MyLayout 的核心機(jī)制是遍歷視圖樹(shù),逐個(gè)計(jì)算每個(gè)視圖的位置和大小。這個(gè)過(guò)程在布局視圖的 layoutSubviews 方法中觸發(fā)。當(dāng)父布局容器需要重新布局時(shí),會(huì)調(diào)用 layoutSubviews,在這個(gè)方法中,MyLayout 遍歷所有子視圖,并根據(jù)子視圖的布局屬性(如邊距、寬高、自適應(yīng)等)進(jìn)行計(jì)算和定位。
每個(gè)視圖的布局屬性都會(huì)影響到其最終的 frame,MyLayout 會(huì)根據(jù)這些屬性和布局容器的尺寸來(lái)動(dòng)態(tài)調(diào)整子視圖的位置和大小。例如:
myLeftMargin和myRightMargin決定視圖在父視圖中的左右間距。myWidth決定視圖的寬度,可以是固定值、百分比或根據(jù)內(nèi)容自適應(yīng)。weight屬性用于動(dòng)態(tài)分配剩余空間,類(lèi)似于flexbox的flex屬性。
2. 布局屬性的自定義與擴(kuò)展
MyLayout 基于 UIView 的擴(kuò)展,將自定義的布局屬性直接掛載在每個(gè)子視圖上。通過(guò)為 UIView 擴(kuò)展自定義屬性(例如 myLeftMargin、myHeight),MyLayout 實(shí)現(xiàn)了布局屬性的可訪問(wèn)性。然后,框架通過(guò)在布局視圖的 layoutSubviews 方法中訪問(wèn)這些自定義屬性,完成布局的計(jì)算和調(diào)整。
這些自定義屬性的設(shè)定值可以是固定數(shù)值,也可以是相對(duì)父視圖或兄弟視圖的動(dòng)態(tài)值,這使得 MyLayout 在布局時(shí)非常靈活。例如:
- 當(dāng)視圖的寬度是相對(duì)父視圖的寬度時(shí),可以設(shè)置
myWidth.equalTo(self.view.myWidth),表示視圖的寬度等于父視圖寬度。
3. 自適應(yīng)與動(dòng)態(tài)調(diào)整
MyLayout 支持子視圖的自適應(yīng)布局,通過(guò)計(jì)算視圖的固有內(nèi)容大小和父視圖的剩余空間,動(dòng)態(tài)調(diào)整子視圖的尺寸和位置。與 Auto Layout 類(lèi)似,當(dāng)某個(gè)視圖的內(nèi)容發(fā)生變化時(shí)(例如文本視圖內(nèi)容變長(zhǎng)),MyLayout 可以自動(dòng)調(diào)整該視圖的大小,使其適應(yīng)新的內(nèi)容。
此外,MyLayout 還支持動(dòng)態(tài)調(diào)整布局。當(dāng)父視圖的尺寸改變時(shí)(例如旋轉(zhuǎn)屏幕或窗口大小調(diào)整),MyLayout 會(huì)重新計(jì)算所有子視圖的布局,確保它們始終適應(yīng)當(dāng)前的父視圖大小。
4. 避免 Auto Layout 的性能開(kāi)銷(xiāo)
MyLayout 的一個(gè)主要優(yōu)勢(shì)是避免了 Auto Layout 系統(tǒng)帶來(lái)的性能開(kāi)銷(xiāo)。Auto Layout 通過(guò)約束系統(tǒng)來(lái)管理布局,內(nèi)部需要解決一系列的線性方程,這可能在復(fù)雜布局場(chǎng)景下導(dǎo)致性能瓶頸。而 MyLayout 直接操作視圖的 frame 屬性,跳過(guò)了約束的解析過(guò)程,從而提高了布局效率,特別是在需要頻繁動(dòng)態(tài)調(diào)整布局的場(chǎng)景中表現(xiàn)更佳。
5. 布局類(lèi)型的實(shí)現(xiàn)
MyLayout 提供了多種布局類(lèi)型(線性布局、相對(duì)布局、表格布局等),這些布局類(lèi)型的實(shí)現(xiàn)原理是根據(jù)布局容器的不同類(lèi)型,采用不同的算法來(lái)計(jì)算子視圖的排列方式。例如:
- 線性布局:通過(guò)遍歷子視圖,按照垂直或水平方向依次排列,并根據(jù)
myLeftMargin、myTopMargin等屬性調(diào)整每個(gè)視圖的位置。 - 相對(duì)布局:根據(jù)子視圖的相對(duì)定位屬性(例如
centerXPos.equalTo()),在布局時(shí)計(jì)算相對(duì)關(guān)系,調(diào)整視圖的位置。 - 表格布局:按照行列方式排列子視圖,類(lèi)似于表格的布局邏輯。
6. 性能優(yōu)化
MyLayout 的性能優(yōu)化體現(xiàn)在以下幾個(gè)方面:
- 避免不必要的重繪:在子視圖的布局屬性發(fā)生變化時(shí),MyLayout 會(huì)觸發(fā)布局刷新,但它會(huì)避免無(wú)關(guān)子視圖的重繪和布局調(diào)整,減少性能開(kāi)銷(xiāo)。
- 輕量級(jí)的布局計(jì)算:由于不依賴(lài) Auto Layout 的約束解析,MyLayout 的布局計(jì)算只涉及簡(jiǎn)單的幾何運(yùn)算,避免了復(fù)雜的約束求解過(guò)程,從而提升布局效率。
- 支持緩存機(jī)制:在某些復(fù)雜場(chǎng)景下,MyLayout 還可以通過(guò)緩存布局結(jié)果,進(jìn)一步減少重復(fù)計(jì)算的開(kāi)銷(xiāo)。
4. 使用
podfile中加入,然后運(yùn)行,命令:pod install
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.0'
pod 'MyLayout'
框架作者還給出了一個(gè)y演示demo:


浙公網(wǎng)安備 33010602011771號(hào)