0x00 背景:
开发的时候现在用到的最多的AutoLayout第三方框架就是Masonry(Swift为SnapKit)了,里面有一种非常舒服的调用方法用流行的 话来讲就是链式调用方法,是把一块组合调用方法使用.连接的方式写出来,使得编码方式更直观,更容易理解。下面我们看一下如何在UILabel中使用这种技巧。
0x01 问题
首先,假设我们有一个view,我们需要它在距他的parentView左边15sp,右边30sp,上边20sp,下边20sp,看一下使用SnapKit如何来实现这个布局的
let view = UIView()
view.backgroundColor = UIColor.red
self.view.addSubview(view);
view.snp.makeConstraints { (make) in
make.left.equalTo(20)
make.right.equalTo(self.view).offset(-20)
make.top.equalTo(20)
make.bottom.equalTo(self.view).offset(-20)
}
其中,描述当前view距parentView的下边距为20sp,就是make.bottom.equealTo(self.view).offset(-20),从字面意思很容易就能看出所表达的内容。
- 给定一个UILabel,设置字体为系统12号,颜色为Red,背景色为Yellow,text为"One coin has two sides"
通常我们会这么写:
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 12)
label.textColor = UIColor.red
label.backgroundColor = UIColor.yellow
label.text = "One coin has two sides"
那么我们考虑一下,是不是能和SnapKit一样用链式调用来达到同样的效果呢?
let label = UILabel()
label
.font(UIFont.systemFont(ofSize: 12))
.textColor(UIColor.red)
.backgroundColor(UIColor.yellow)
.text("One coin has two sides")
0x02 过程
我们来看一下上述的这句话:
make.bottom.equalTo(self.view).offset(-20)
我们查看一下里面bottom的源码:
public var bottom: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.bottom)
}
返回的是 “ConstraintMakerExtendable”对象,我们再点击这个这个查看源码:
public class ConstraintMakerExtendable: ConstraintMakerRelatable {
public var left: ConstraintMakerExtendable {
self.description.attributes += .left
return self
}
public var top: ConstraintMakerExtendable {
self.description.attributes += .top
return self
}
public var bottom: ConstraintMakerExtendable {
self.description.attributes += .bottom
return self
}
...
看出来什么来了吗?它们每个在自身内部计算完之后,最终返回的还是自己,即“ConstraintMakerExtendable”对象,所以“ConstraintMakerExtendable”对象才可以不断的再调用自身其它的属性。
那么基于此,我们也可以为UILabel构造这么一些方法(我们和上述有一点点不同,所以不能以属性的方式来处理,因为需要传入的的值和返回的值并不一致),并返回UILabel自己来达到这样的效果。
0x03 实现
新起一个Swift Playground
新那家一个UILabel的extension,实现我们需要的4个方法,如下:
extension UILabel {
func sn_font(_ font: UIFont?) -> UILabel {
self.font = font
return self
}
func sn_textColor(_ color: UIColor?) -> UILabel {
self.textColor = color
return self
}
func sn_backgroundColor(_ backgroundColor: UIColor?) -> UILabel {
self.backgroundColor = backgroundColor
return self
}
func sn_text(_ text: String?) -> UILabel {
self.text = text
return self
}
}
我们每次接收传过来的值,并在本身使用之后,再返回自身self,因为返回的还是UILabel对象,所以可以继续调用其他的方法。
下面我们写一段代码测试一下:
let label = UILabel()
label.sn_font(UIFont.systemFont(ofSize: 12)).sn_textColor(.red).sn_backgroundColor(.yellow).sn_text("One coin has two sides")
label.sizeToFit()
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view.addSubview(label)
PlaygroundPage.current.liveView = view
效果如图:
0x04 总结
通过类似的写法,我们还可以把layer用到的一些方法比如说cornerRadius,borderWdith, borderColor等写成上述extension里面的方法,以一种更直观的方式来描述你想达到的界面效果。