AutoLayout现在是iOS开发布局的必备,对于使用Swift语言开发的项目,我们经常使用SnapKit进行UI布局,因为使用简单,方便。基本的使用方法官方已经写的非常详情了,可以看这里。官方为我们提供了几种方式来修改约束,先了解一下:
1、引用约束(References)
我们能够声明一个局部变量或者类属性来引用我们想要修改的约束,也可以使用数组存储引用多个约束,然后对引用的约束进行修改
var topConstraint: Constraint? = nil
...
// when making constraints
view1.snp.makeConstraints { (make) -> Void in
self.topConstraint = make.top.equalTo(superview).offset(padding.top).constraint
make.left.equalTo(superview).offset(padding.left)
}
...
// then later you can call
self.topConstraint.uninstall()
// or if you want to update the constraint
self.topConstraint.updateOffset(5)
2、使用updateConstraints进行约束更新
如果我们仅仅只想更新约束的常量值,那么我们可以使用updateConstraints方法
// this is Apple's recommended place for adding/updating constraints
// this method can get called multiple times in response to setNeedsUpdateConstraints
// which can be called by UIKit internally or in your code if you need to trigger an update to your constraints
override func updateConstraints() {
self.growingButton.snp.updateConstraints { (make) -> Void in
make.center.equalTo(self);
make.width.equalTo(self.buttonSize.width).priority(250)
make.height.equalTo(self.buttonSize.height).priority(250)
make.width.lessThanOrEqualTo(self)
make.height.lessThanOrEqualTo(self)
}
// according to Apple super should be called at end of method
super.updateConstraints()
}
注意:更新约束是基于现有的约束条件进行修改其常量值,如果不是对已有的约束进行修改,那么会出错,并且不需要将所有的约束重新写一遍,只需要修改想要更新的约束即可。例如:一个UILabel控件,相对于父视图左右边距分别是10,并且居中显示,添加约束如下:
label.snp.makeConstraints { (make) in
make.centerY.equalToSuperview()
make.left.right.equalToSuperview().inset(10)
}
现在修改距离左右两边的约束为30,直接使用updateConstraints方法即可
label.snp.updateConstraints { (make) in
make.left.right.equalToSuperview().inset(30)
}
3、使用remarkConstraints修改约束
使用remarkConstraints跟使用makeConstriants相似,但是首先会将之前所有的约束都去除,然后重新添加相关的约束
func changeButtonPosition() {
self.button.snp.remakeConstraints { (make) -> Void in
make.size.equalTo(self.buttonSize)
if topLeft {
make.top.left.equalTo(10)
} else {
make.bottom.equalTo(self.view).offset(-10)
make.right.equalTo(self.view).offset(-10)
}
}
}
开发的过程中,我们可能会碰到这样的需求:一个UI控件事先已经添加好约束了,这时候我想修改改控件其中的一个约束或者多个约束,并且约束的对象也发生了改变。实现思路有2种:
1)使用remarkConstraints方法在对应的条件下添加约束
2)事先添加所需要的所有约束并对约束进行引用,然后配合Constraints的activate()方法和deactivate()方法,使用deactivate()处理暂时不需要的约束,在需要的时候activate()需要的约束。
看一个简单例子
添加两个UILabel和一个UISwitch控件,点击UISwitch修改对应的约束。初始化基本约束和页面效果如下:
func setupConstraints() {
label1.snp.makeConstraints { (make) in
make.left.top.equalToSuperview().inset(50)
make.size.equalTo(CGSize(width: 100, height: 100))
}
label2.snp.makeConstraints { (make) in
make.left.size.equalTo(label1)
make.top.equalTo(label1.snp.bottom).offset(50)
}
st.snp.makeConstraints { (make) in
make.center.equalToSuperview()
}
st.addTarget(self, action: #selector(tapSwitch(_:)), for: .touchUpInside)
}
页面效果
1)使用remarkConstraints方法修改约束,如果是点击打开,那么将label2设置约束为距离父视图的右边为50,大小变为200,顶部相对于label1的底部,如果是关闭,那么回到最初的约束
@objc func tapSwitch(_ st: UISwitch) {
if st.isOn {
label2.snp.remakeConstraints { (make) in
make.right.equalToSuperview().offset(-50)
make.size.equalTo(CGSize(width: 200, height: 200))
make.top.equalTo(label1.snp.bottom)
}
} else {
label2.snp.remakeConstraints { (make) in
make.left.size.equalTo(label1)
make.top.equalTo(label1.snp.bottom).offset(50)
}
}
}
可以看到操作也挺简单,直接使用remarkConstraints方法添加想要的约束即可。
2)使用activate()和deactivate()
1、需要使用变量引用对应的约束
var leftConstraint: Constraint!
var rightConstraint: Constraint!
var originalSizeConstraint: Constraint!
var orignalTopConstraint: Constraint!
var targetTopConstraint: Constraint!
var targetSizeConstraint: Constraint!
var originalConstraints: [Constraint] = []
var targetConstraints: [Constraint] = []
2、为label2添加所有的约束
label2.snp.makeConstraints { (make) in
leftConstraint = make.left.equalTo(label1).constraint
originalSizeConstraint = make.size.equalTo(label1).constraint
orignalTopConstraint = make.top.equalTo(label1.snp.bottom).offset(50).constraint
targetTopConstraint = make.top.equalTo(label1.snp.bottom).priority(999).constraint
targetSizeConstraint = make.size.equalTo(CGSize(width: 200, height: 200)).priority(999).constraint
rightConstraint = make.right.equalToSuperview().offset(-50).priority(999).constraint
}
这里需要将目标约束降低优先级,不然会出现约束冲突,因为系统不知道什么使用约束,当约束优先级被降低之后,会默认先使用高优先级。
3、使用数组存储对应的约束,方便后续的操作,注意:失效目标约束,即去除多余的约束
// 添加到对应的数组
originalConstraints.append(leftConstraint)
originalConstraints.append(orignalTopConstraint)
originalConstraints.append(originalSizeConstraint)
targetConstraints.append(targetTopConstraint)
targetConstraints.append(targetSizeConstraint)
targetConstraints.append(rightConstraint)
// 失效之后的约束
targetConstraints.forEach {$0.deactivate()}
4、点击开关修改约束
@objc func tapSwitch(_ st: UISwitch) {
if st.isOn { // 失效原有约束,生效目标约束
originalConstraints.forEach {$0.deactivate()}
targetConstraints.forEach {$0.activate()}
} else { // 失效目标约束,生效原有的约束
targetConstraints.forEach {$0.deactivate()}
originalConstraints.forEach {$0.activate()}
}
}