经过几年的打磨和多次的重构,我的iOS开源界面布局库MyLayout的star数量终于在2018年8月6号破3000了!有图为证:
MyLayout
还有Swift版本TangramKit:
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!!
作者:欧阳大哥2013