让你爱上用代码自动布局——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));

然后我们看看效果:

/illustrations/2016-03-03-iOS-SDAutoLayout/p00.gif

很好。

添加多个布局

我们举一反三,让这个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);

果然链式编程够简洁,看看效果:

/illustrations/2016-03-03-iOS-SDAutoLayout/p01.gif

不错。

再来俩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的比例约束宽,就会发现蓝绿两个视图不等宽了。看看效果:

/illustrations/2016-03-03-iOS-SDAutoLayout/p02.gif

和手动拖约束一样,你得心里想好了要怎么设置约束,如果有任何一个无法确定的约束,那么涉及到这个约束的视图将不能正常显示。

再来个层级堆叠的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;
}

看看效果:

/illustrations/2016-03-03-iOS-SDAutoLayout/p03.gif

为什么比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。