經過幾年的打磨和多次的重構,我的iOS開源界面布局庫MyLayout的star數量終于在2018年8月6號破3000了!有圖為證:
還有Swift版本TangramKit:
這個周末發布了最新的MyLayout 1.6.0 版本和TangramKit 1.2.0版本。大家可以到這里去下載:
OC版本MyLayout: https://github.com/youngsoft/MyLinearLayout
Swift版本TangramKit: https://github.com/youngsoft/TangramKit
或者通過cocoapods引入:MyLayout 和TangramKit。
當然如果您覺得不錯就順手點一個贊??。
想說說當時為什么要寫這么一個開源布局庫。因為接觸iOS開發比較早,所以早期基本都是用frame來進行界面布局,那時候也沒有那么多的設備需要適配,所以用frame也還好。 后來在iOS6.0以后,蘋果公司推出了一種新的界面布局方案AutoLayout,這種方法主旨是通過相對的約束設置進行布局來減少代碼中硬編碼的編寫,從而達到多設備適配以及簡化布局的能力。這種新的解決方案也有很多的缺點就是代碼量會劇增而且編寫起來非常麻煩,即使是用XIB或者SB的話也會出現拉約束的線非常的多和混亂。幸好這時候一個開源庫Masonry的出現使得布局編碼得到了簡化,新的方法以及新的語法給了大家很大的幫助。
而我呢,當時也試著去了解學習AutoLayout這種布局方法,后來發現太過于復雜和繁瑣了(其實本質是不想學習新的東西)!然后又因為懂一點點android相關的編程,了解到android中有四大布局體系,而其中用的最多的就是線性布局。于是想既然如此那我為什么不自己寫一個類似android的線性布局呢?于是就開始著手寫了我的布局庫的第一個版本,現在我都還保留著這個類的實現和聲明:
//用于線性布局的子視圖的屬性,描述離兄弟視圖的間隔距離,以及在父視圖中的比重。
@interface UIView(LinearLayoutExtra)
@property(nonatomic, assign) CGFloat headMargin; //距離前面兄弟視圖的距離,這個用于線性布局
@property(nonatomic, assign) CGFloat tailMargin; //距離后面兄弟視圖的距離,這個用于線性布局
@property(nonatomic, assign) CGFloat weight; //比重,用于占用父視圖的比重。取值為>=0 <=1
//@property(nonatomic, assign)
@end
//排列的方向
typedef enum : NSUInteger {
LVORIENTATION_VERT,
LVORIENTATION_HORZ,
} LineViewOrientation;
//調整大小時伸縮的方向
typedef enum : NSUInteger {
LVFLEXDIR_TAIL,
LVFLEXDIR_HEAD,
}LineViewFlexDir;
/*
線性視圖,類似android的LinearLayout布局。支持2個方向。現在的版本要求子視圖的位置或者是否隱藏改變后需要調用
使用線性布局時里面的子視圖的frame.origin.y是無效的,而是通過子視圖的headMargin,tailMargin分別指出其距離他
兄弟的距離以及weight用來表明他在父視圖之中的比重。因此在xib上如果用MyLineView來進行布局則可能實際上顯示的內容
和真實的內容是不一致的。而且線性布局會因為子視圖的大小和邊距而調整自己的尺寸。因此線性布局比較適合通過代碼的方式來
構造視圖。同時適合于將線性布局作為scrollview的子視圖來布局。因為線性布局在位置調整后會
如果是使用自動布局則這個類將無效。
*/
@interface MyLinearLayout : UIView
//方向,默認是縱向的
@property(nonatomic,assign) LineViewOrientation orientation;
//當調整自己大小時是伸縮頂部還是底部三個位置,默認是底部
@property(nonatomic,assign) LineViewFlexDir flexDir;
//如果線性布局的父視圖是UIScrollView或者子類則在線性布局的位置調整后是否調整滾動視圖的contentsize,默認是NO
//這個屬性適合與整個線性布局作為滾動視圖的唯一子視圖來使用。
@property(nonatomic, assign, getter = isAdjustScrollViewContentSize) BOOL adjustScrollViewContentSize;
//是否調整自己的大小,默認是YES的.如果設置為NO的話則adjustScrollViewContentSize就沒有實際的意思了。
@property(nonatomic, assign, getter =isAutoAdjustSize) BOOL autoAdjustSize;
//子視圖是否在指定的方向居中。默認是NO.如果設置為YES的話則邊緣視圖的邊距不起作用了,而且子視圖的weight也不起作用了。而且不是調整自己的大小了
//也就是當垂直方向則所有子視圖按順序排列在中間。
@property(nonatomic, assign,getter = isCentreSubview) BOOL centreSubview;
@end
當時造輪子的原因就是不想去學習新的東西,后來將這個線性布局應用到自己的開發中發現非常的方便和好用,然后就不停的去迭代,不停的去增加新的功能,然后再決定把它開源并放到github上。布局庫最開始只有一個線性布局,后來就分別添加了相對布局、框架布局、表格布局、浮動布局、流式布局、路徑布局、柵格布局等八種布局。這些布局都是借鑒了目前市面上的iOS和android以及HTML5中的各種布局框架和思想而設計的。至于當時為什么以My開頭初衷也是隨手這么一寫,所以后來開源后還是保持以My開頭。有的同學覺得這個開頭比較土而希望起個高大上的名字,后來想想既然都開源了就不要再亂改名字了,還是保持原樣吧。
有人也許會覺得Masonry或者AutoLayout挺好,而且使用受眾也廣也流行,為什么我還要去學習或者掌握一個新的庫。其實這也正常,人總是有懶惰的天性,就如我不想學AutoLayout是一樣的。但實際中我們總是帶著解決問題的想法去使用某個框架和庫的,我這里想說的是當你在使用AutoLayout時因為復雜的約束設置以及更新方法而焦頭爛額時,當你使用AutoLayout而對多屏幕多設備適配而進行多條件編寫時,當你使用AutoLayout對你的布局性能造成影響時,也許你會想著是否有一個新的布局庫能幫我解決這個問題,沒有錯,也許MyLayout就能幫你解決你實際中的眾多復雜布局和性能的問題,而且MyLayout其實也是一直在朝著這方面努力的。 所以你也可以先以嘗試的態度來接觸和使用這種新的布局解決方案,而且為了讓大家能更好的使用這個布局庫,在我的開源庫中為每種布局都建立了異常豐富的演示和使用的DEMO,同時我還建立了一個能供大家交流和解決問題的QQ群:178573773。而且我本人還會一直熱心的為你解答任何在使用過程中的問題。
既然使用一個庫那么總是應該有優缺點的,首先布局庫的優點是:
- 性能高,因為內部實現是基于frame的所以性能是AutoLayout的5倍左右。
- 需要設置的約束少,不需要像AutoLayout那樣無論是位置和尺寸都需要明確的通過設置約束來指定。有些時候可能只需要一兩個屬性就可以把所有子視圖的位置和尺寸都設置完成。
- 可選的布局種類多,有些布局是參照android和iOS的,而有些布局是參照HTML5中的flex-box, css-float等機制,甚至還可以支持從服務器動態下發的能力。因為布局種類多所以總有一款會適合你。
- 多屏幕和多設備適配能力強,布局庫能非常方便和簡單的實現多設備種類的適配,比如提供一些比例設置、浮動間距、浮動尺寸、以及對SizeClass的支持等等,你不再需要編寫很多條件語句來實現不同設備下的布局處理。
同樣布局庫也有一些缺點:
- 上手比較慢,因為很多思想和AutoLayout不一致,而更多的是借鑒了android以及HTML5中的一些布局思想以及布局屬性的設置,所以如果你一直在開發iOS的話可能有些方法和習慣會和以前有非常大的迥異。
- 命名和使用有一些不規范,這個是因為早期在開發時有些屬性和方法命名不規范,后來因為開源后又難以改正所以就一直沿用一些老的命名和方法,導致布局庫的屬性和方法非常的多,學習起來的成本也稍微高一些,但是這個問題在后來的swift版本的TangramKit中得到了有效的解決。
- 布局庫不知名,所有沒有很多的渠道和社區來進行討論和交流。
- 布局種類眾多不知道如何選擇,因為系統提供了8種布局供選擇,因此有可能會出現不知道選哪種最合適而導致迷惑。
在MyLayout的8種布局中其實每種都有一些特定的應用場景,我這邊建議優先使用的布局庫順序是:
浮動布局>流式布局>表格布局>線性布局>框架布局>相對布局>路徑布局>柵格布局。
總之就是一句話:當您覺得使用Masonry或者AutoLayout不適合來解決你目前的問題時,你可以嘗試著試試MyLayout!!
我的博客即將搬運同步至騰訊云+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=26dkiif89jtg