让你爱上用代码自动布局——SDAutoLayout
在刚开始接触用代码写自动布局的时候,我是拒绝的。相信各位开发者也有同样的困惑——由系统提供的自动布局API臃肿、繁琐;在IB里拖约束呢,多人合作的时候,合并冲突也是个麻烦事。
就我个人而言,由于是独立开发,所以基本使用IB来拖。像知名的Masonry,我也关注过,但SDAutoLayout,我必须要安利一把。她有着更为性感的API。
链式编程思想
在这里简单地提一下,链式编程思想是一种能让开发者高潮的编程思想,特点在于所有方法的调用,均可通过一连串的方法调用来实现。可以说只要你的显示器够宽,你就可以在一行内完成对一个控件的所有约束。
这种编程思想的好处不言而喻,代码整洁、增强可读性、减少重复代码。
实现链式编程的关键点在于每个调用的方法的返回值都是一个block,block的返回值是这个对象的本身。这样才能保证每次调用完一个方法之后,仍然可以用点语法来继续调用方法。
SDAutoLayout就是用这种编程思想实现的。(Masonry也是,但还是不如SDAutoLayout性感)
用起来看
小试牛刀
我们随便在一个VC中,添加一个红色的View。
1 2 3 | UIView *redView = [[UIView alloc] init]; [redView setBackgroundColor:[UIColor redColor]]; [self.view addSubview:redView]; |
对它做自动布局,让这个redView距边界永远保持一个距离,只有一句话:
1
| redView.sd_layout.spaceToSuperView(UIEdgeInsetsMake(20, 40, 20, 40));
|
然后我们看看效果:
很好。
添加多个布局
我们举一反三,让这个redView占屏幕的上半部分,并且永远保持屏幕一半大小,左右边距为40,上边距为20,对照着API我们可以很清晰地根据需求敲出代码:
1 2 3 4 | redView.sd_layout.topSpaceToView(self.view, 20) .leftSpaceToView(self.view, 40) .rightSpaceToView(self.view, 40) .heightRatioToView(self.view, 0.5); |
果然链式编程够简洁,看看效果:
不错。
再来俩View。
1 2 3 4 5 6 7 | UIView *blueView = [[UIView alloc] init]; [blueView setBackgroundColor:[UIColor blueColor]]; [self.view addSubview:blueView]; UIView *greenView = [[UIView alloc] init]; [greenView setBackgroundColor:[UIColor greenColor]]; [self.view addSubview:greenView]; |
让绿视图和蓝视图各占下半部一半:
1 2 3 4 5 6 7 8 9 | blueView.sd_layout.topSpaceToView(redView, 40) .leftSpaceToView(self.view, 20) .bottomSpaceToView(self.view, 20) .widthIs(self.view.frame.size.width/2-30); greenView.sd_layout.topSpaceToView(redView, 40) .rightSpaceToView(self.view, 20) .bottomSpaceToView(self.view, 20) .leftSpaceToView(blueView, 20); |
由于我们对视图的边界做了约束,所以如果像红色视图一样,按照父视图0.5的比例约束宽,就会发现蓝绿两个视图不等宽了。看看效果:
和手动拖约束一样,你得心里想好了要怎么设置约束,如果有任何一个无法确定的约束,那么涉及到这个约束的视图将不能正常显示。
再来个层级堆叠的Demo,我们要创建多个层叠的View,让他们中心对齐,逐个缩小。
来个工厂模式批量设置下:
1 2 3 4 5 6 | - (UIView *)getView { UIView *view = [[UIView alloc] init]; [view setBackgroundColor:[self randomColor]]; [view setAlpha:1.0f]; return view; } |
我们需要递归地创建子视图,所以来个指针:
1
| UIView *tempView = self.view;
|
然后循环:
1 2 3 4 5 6 7 8 9 | for (int i=0; i<6; ++i) { UIView *newView = [self getView]; [tempView addSubview:newView]; newView.sd_layout.heightRatioToView(tempView.superview, 0.8f) .widthRatioToView(tempView.superview, 0.8f) .centerXEqualToView(tempView.superview) .centerYEqualToView(tempView.superview); tempView = newView; } |
看看效果:
为什么比Masonry性感
性感这个词,其实就是说API用起来更舒服。我就举一个例子:用Masonry让redView设置与父视图边距:
1 2 3 4 | UIEdgeInsets padding = UIEdgeInsetsMake(20, 40, 20, 40); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(superview).with.insets(padding); }]; |
比较下SDAutoLayout:
1 2 | UIEdgeInsets padding = UIEdgeInsetsMake(20, 40, 20, 40); redView.sd_layout.spaceToSuperView(padding); |
完爆。
同样是链式编程思想,SDAutoLayout封装了更优美的API。