動態

詳情 返回 返回

iOS開發框架--MyLayout - 動態 詳情

MyLayout 框架不僅支持 Objective-C,也可以在 Swift 中使用。通過 MyLayout,可以使用面向對象的方式來創建和管理視圖的佈局,簡化了 Auto Layout 中繁瑣的約束設置流程。在 Objective-C 中,MyLayout 提供了相同的佈局類型和屬性,使用方式稍有不同,主要是語法和調用方式上的差異。

先介紹一下如何使用吧,線性佈局和相對佈局是用的比較多的佈局方式。

1. 線性佈局(MyLinearLayout)

線性佈局是一種裏面的子視圖按添加的順序從上到下或者從左到右依次排列的單列(單行)佈局視圖,因此裏面的子視圖是通過添加的順序建立約束和依賴關係的。 子視圖從上到下依次排列的線性佈局視圖稱為垂直線性佈局視圖,而子視圖從左到右依次排列的線性佈局視圖則稱為水平線性佈局

創建一個垂直線性佈局的示例:

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];

在這個例子中,我們創建了一個垂直線性佈局容器 rootLayout,並在其中添加了兩個 UIView 子視圖。每個子視圖都有自己的高度和邊距設置。view1view2 分別設置了不同的高度,且左右邊距為 10。

2. 相對佈局(MyRelativeLayout)

相對佈局允許子視圖通過相對父視圖或者其他子視圖的位置來佈局。

相對佈局示例:

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 對齊
[view2 setBackgroundColor:[UIColor blueColor]];
[rootLayout addSubview:view2];

[self.view addSubview:rootLayout];

在這個示例中,view1 在父視圖中水平居中,並且距離頂部有 10 的間隔。而 view2 則位於 view1 的下方,並保持水平對齊。通過設置 centerXPostopPos 等屬性,MyLayout 可以輕鬆實現相對佈局。

3. 佈局框架的類架構

這張圖展示了 MyLayout 佈局框架的類架構,幫助開發者理解其內部設計和結構。

  1. MyBaseLayout

    • 這是 MyLayout 框架的基礎類,所有具體的佈局類(如 MyLinearLayoutMyFrameLayout 等)都繼承自它。它負責處理佈局容器的基礎功能,如視圖的排列、佈局更新等。
  2. 佈局子類

    • MyBaseLayout 派生的不同佈局類型用於支持多種佈局方式:
      • MyLinearLayout:線性佈局,視圖依次排列,可以是垂直或水平。
      • MyFrameLayout:幀佈局,子視圖重疊在一起,根據設置的大小、位置顯示。
      • MyRelativeLayout:相對佈局,子視圖可以相對於其他視圖或容器進行佈局。
      • MyFlowLayout:流式佈局,子視圖按行或列排列,類似於文本換行的效果。
      • MyFloatLayout:浮動佈局,視圖可以根據容器空間自動排列。
      • MyPathLayout:路徑佈局,子視圖可以沿着路徑排列。
      • MyGridLayout:網格佈局,子視圖按網格排列。
      • MyTableLayout:表格佈局,子視圖按表格形式排列。
  3. MyViewSizeClass 和子類:

    • MyViewSizeClass 是用於定義視圖在不同尺寸類別下的表現,類似於 iOS 的 Size Class 概念。
    • MyLayoutViewSizeClass 是它的子類,用於處理 MyLayout 視圖的大小、邊距、位置等屬性。
    • 不同的佈局有各自的 ViewSizeClass,如 MyLinearLayoutViewSizeClassMyTableLayoutViewSizeClass 等,來定義在這些佈局中的尺寸規則。
  4. UIView 的擴展 (Category)

    • 通過對 UIView 進行擴展,MyLayout 框架為視圖添加了自定義佈局屬性,如 leftPostopPoswidthSizeheightSize 等。這些屬性與 MyLayoutPosMyLayoutSize 類相關聯,幫助開發者通過簡單的設置實現複雜的佈局需求。
  5. MyLayoutPos 和 MyLayoutSize

    • MyLayoutPos:MyLayoutPos類是用來描述一個視圖所在的位置的類。UIView中擴展出了leftPos,topPos,bottomPos,rightPos,centerXPos,centerYPos這六個變量來實現視圖的定位操作。您可以用這些變量的equalTo方法來設置視圖之間的邊距和間距。 equalTo 方法可以設置NSNumber, MyLayoutPos, NSArray<MyLayoutPos*>這幾種值,分別用於不同的場景。同時系統提供了6個簡單的變量myLeft, myTop, myBottom, myRight, myCenterX, mYCenterY來設置NSNumber類型的值,比如 A.leftPos.equalTo(@10); 等價於 A.myLeft = 10;.

    • MyLayoutSize:MyLayoutSize類是用來描述一個視圖的尺寸的類。UIView中擴展出了widthSize,heightSize這兩個變量來實現視圖的寬度和高度尺寸的設置。您可以用其中的equalTo方法來設置視圖的寬度和高度。equalTo方法可以設置NSNumber, MyLayoutSize, NSArray<MyLayoutSize*>這幾種值,分別用於不同的場景。同時系統提供了2個簡單的變量myWidth,myHeight來設置NSNumber類型的值,比如A.widthSize.equalTo(@10); 等價於A.myWidth = 10;.

  6. MyWeight

    • MyWeight 是一個與佈局權重相關的概念,用於控制視圖在容器中佔據的相對空間。

通過這個類架構圖,可以看到 MyLayout 框架是如何通過繼承和擴展的方式,將多種佈局模式整合到一個框架中,從而簡化複雜佈局的實現。

4. 底層原理

MyLayout 的底層原理主要是通過對每個視圖的佈局屬性(如 myLeftMarginmyWidthmyHeight 等)進行計算,並在佈局容器中根據這些屬性重新調整每個子視圖的位置和大小。這個過程與 Auto Layout 系統相似,但 MyLayout 不依賴 iOS 自帶的 Auto Layout 約束機制,而是通過手動佈局來優化性能和簡化實現。

1. 視圖樹遍歷與佈局計算

MyLayout 的核心機制是遍歷視圖樹,逐個計算每個視圖的位置和大小。這個過程在佈局視圖的 layoutSubviews 方法中觸發。當父佈局容器需要重新佈局時,會調用 layoutSubviews,在這個方法中,MyLayout 遍歷所有子視圖,並根據子視圖的佈局屬性(如邊距、寬高、自適應等)進行計算和定位。

每個視圖的佈局屬性都會影響到其最終的 frame,MyLayout 會根據這些屬性和佈局容器的尺寸來動態調整子視圖的位置和大小。例如:

  • myLeftMarginmyRightMargin 決定視圖在父視圖中的左右間距。
  • myWidth 決定視圖的寬度,可以是固定值、百分比或根據內容自適應。
  • weight 屬性用於動態分配剩餘空間,類似於 flexboxflex 屬性。
2. 佈局屬性的自定義與擴展

MyLayout 基於 UIView 的擴展,將自定義的佈局屬性直接掛載在每個子視圖上。通過為 UIView 擴展自定義屬性(例如 myLeftMarginmyHeight),MyLayout 實現了佈局屬性的可訪問性。然後,框架通過在佈局視圖的 layoutSubviews 方法中訪問這些自定義屬性,完成佈局的計算和調整。

這些自定義屬性的設定值可以是固定數值,也可以是相對父視圖或兄弟視圖的動態值,這使得 MyLayout 在佈局時非常靈活。例如:

  • 當視圖的寬度是相對父視圖的寬度時,可以設置 myWidth.equalTo(self.view.myWidth),表示視圖的寬度等於父視圖寬度。
3. 自適應與動態調整

MyLayout 支持子視圖的自適應佈局,通過計算視圖的固有內容大小和父視圖的剩餘空間,動態調整子視圖的尺寸和位置。與 Auto Layout 類似,當某個視圖的內容發生變化時(例如文本視圖內容變長),MyLayout 可以自動調整該視圖的大小,使其適應新的內容。

此外,MyLayout 還支持動態調整佈局。當父視圖的尺寸改變時(例如旋轉屏幕或窗口大小調整),MyLayout 會重新計算所有子視圖的佈局,確保它們始終適應當前的父視圖大小。

4. 避免 Auto Layout 的性能開銷

MyLayout 的一個主要優勢是避免了 Auto Layout 系統帶來的性能開銷。Auto Layout 通過約束系統來管理佈局,內部需要解決一系列的線性方程,這可能在複雜佈局場景下導致性能瓶頸。而 MyLayout 直接操作視圖的 frame 屬性,跳過了約束的解析過程,從而提高了佈局效率,特別是在需要頻繁動態調整佈局的場景中表現更佳。

5. 佈局類型的實現

MyLayout 提供了多種佈局類型(線性佈局、相對佈局、表格佈局等),這些佈局類型的實現原理是根據佈局容器的不同類型,採用不同的算法來計算子視圖的排列方式。例如:

  • 線性佈局:通過遍歷子視圖,按照垂直或水平方向依次排列,並根據 myLeftMarginmyTopMargin 等屬性調整每個視圖的位置。
  • 相對佈局:根據子視圖的相對定位屬性(例如 centerXPos.equalTo()),在佈局時計算相對關係,調整視圖的位置。
  • 表格佈局:按照行列方式排列子視圖,類似於表格的佈局邏輯。
6. 性能優化

MyLayout 的性能優化體現在以下幾個方面:

  • 避免不必要的重繪:在子視圖的佈局屬性發生變化時,MyLayout 會觸發佈局刷新,但它會避免無關子視圖的重繪和佈局調整,減少性能開銷。
  • 輕量級的佈局計算:由於不依賴 Auto Layout 的約束解析,MyLayout 的佈局計算只涉及簡單的幾何運算,避免了複雜的約束求解過程,從而提升佈局效率。
  • 支持緩存機制:在某些複雜場景下,MyLayout 還可以通過緩存佈局結果,進一步減少重複計算的開銷。

4. 使用

podfile中加入,然後運行,命令:pod install

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.0'

pod 'MyLayout'

框架作者還給出了一個y演示demo:

user avatar xiaofeixiang_63ec941cad48a 頭像 zouzaidadaomanshihuaxiang 頭像
點贊 2 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.