NSLayoutConstraint由名字翻译过去就是布局约束。该类是表示用户界面上两个对象之间的布局关系,并且该关系必须满足基本约束的布局系统。
布局视图(view)定义为一系列的线性方程,每一个约束(constraint)都代表一个方程,格式如下:
上面的约束表示RedView的左边距(left或者说leading)是在blue view右边(right/trailing)偏移8个点.
item1.attribute1 = multiplier × item2.attribute2 + constant
Item1 :表示方程式中的第一个对象,这里是 RedView。
Attribute 1:第一个item对象约束的属性(attribute),这里是RedView的leading
Relationship:关系,即等式左边和等式右边的约束关系。relationship可以含有3个值之一:等于(equal),大于或者等于(greater than or equal),小于或者等于(or less than equal).上面的例子是使用了equal。
Multiplier:倍数,attribute 2的值乘以这个值。上面Multiplier是1.0
Item2:方程式的第二个对象,这里是blue view,不像第一个对象(item),这里可以为空,表示只有常量值
Attribute 2:对第二个对象的约束,上面表示右边(right/trailing尾部)。如果第二个item为空,那么表示没有Attribute
Constant:常量值,偏移量,这里是8,该值是加在Attribute 2上的
在Auto Layout中属性能够添加约束,属性(Attribute)包括4个边缘部分(leading, trailing, top, and bottom),高度(height),宽度(width),垂直和水平中心(horizontal centers)等。对于文本对象(Text items )也包含一个或者多个 baseline attributes.
对于完整的属性列表,可以看这里。
注意:为视图(view)添加约束必须是有效布局,有效布局是指约束不模糊,约束之间没有冲突。有效的约束布局,实现的方式不止一种。如果约束添加无效,那么会导致约束模糊或者冲突。
此外,约束并没有限制只使用等于关系,正像前面说提到的,存在大于等于或者小于等于关系。约束也有优先级,从1到1000,1000表示必须的(required),所有小于1000的约束都是可选的(optional),默认情况下,所有的约束都是1000.
在处理了所有required的约束之后,Auto Layout将按可选约束的优先级由高到低进行处理。如果不能够处理可选约束(optional constraints),Auto Layout将尝试尽可能靠近预期的结果,并移动到下一个约束。
public convenience init(item view1: Any,
attribute attr1: NSLayoutAttribute,
relatedBy relation: NSLayoutRelation,
toItem view2: Any?,
attribute attr2: NSLayoutAttribute,
multiplier: CGFloat,
constant c: CGFloat)
open class func constraints(withVisualFormat format: String,
options opts: NSLayoutFormatOptions = [],
metrics: [String : Any]?,
views: [String : Any]) -> [NSLayoutConstraint]
具体使用NSLayoutConstraint
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.yellow
let testView = UIView()
testView.backgroundColor = UIColor.red
// 1 添加约束之前,需要将视图添加到父视图上
view.addSubview(testView)
// 2 为视图添加约束
let leading = NSLayoutConstraint(item: testView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 20)
let top = NSLayoutConstraint(item: testView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 20)
let trailing = NSLayoutConstraint(item: testView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1.0, constant: -20)
let bottom = NSLayoutConstraint(item: testView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: -20)
view.addConstraints([leading, top, trailing, bottom])
}
添加约束很简单,创建各个方面的约束并添加,但是却看不到我们的testView,而且console中打印了很多的信息,如下:
testView.translatesAutoresizingMaskIntoConstraints = false
3)创建约束之后,将约束添加到父视图(view)上
4)注意bottom和trailing是为负值
5)当约束引用两个视图时,这两个视图一定要属于同一个视图层次结构中,对于引用两个视图的约束,只有两种合法的情况:要么一个视图是另一个视图的父视图,要么两个视图必须是某种类型的兄弟(即它们必须有一个非nil的共同视图祖先)。如果视图让约束引用其它情况的视图,将会崩溃。
let subView = UIView()
subView.backgroundColor = UIColor.cyan
subView.translatesAutoresizingMaskIntoConstraints = false
testView.addSubview(subView)
let centerX = NSLayoutConstraint(item: subView, attribute: .centerX, relatedBy: .equal, toItem: testView, attribute: .centerX, multiplier: 1.0, constant: 0)
let centerY = NSLayoutConstraint(item: subView, attribute: .centerY, relatedBy: .equal, toItem: testView, attribute: .centerY, multiplier: 1.0, constant: 0)
let width = NSLayoutConstraint(item: subView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 200)
let height = NSLayoutConstraint(item: subView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 200)
testView.addConstraints([centerX, centerY, width, height])
class ViewController: UIViewController {
lazy var redView: UIView = {
let redView = UIView()
redView.backgroundColor = UIColor.red
redView.translatesAutoresizingMaskIntoConstraints = false
return redView
}()
lazy var blackView: UIView = {
let blackView = UIView()
blackView.backgroundColor = UIColor.black
blackView.translatesAutoresizingMaskIntoConstraints = false
return blackView
}()
lazy var blueView: UIView = {
let blueView = UIView()
blueView.backgroundColor = UIColor.blue
blueView.translatesAutoresizingMaskIntoConstraints = false
return blueView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.yellow
setupSubView()
setupConstraints()
}
func setupSubView() {
view.addSubview(redView)
view.addSubview(blackView)
view.addSubview(blueView)
}
func setupConstraints() {
let space: CGFloat = 20
let height: CGFloat = (UIScreen.main.bounds.height - 20 * 4) / 3.0
// 为红色视图添加约束,leading、top、trailing间距各20
let redViewLeading = NSLayoutConstraint(item: redView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: space)
let redViewTop = NSLayoutConstraint(item: redView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: space)
let redViewTrailing = NSLayoutConstraint(item: redView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1.0, constant: -space)
let redViewHeight = NSLayoutConstraint(item: redView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: height)
view.addConstraints([redViewLeading, redViewTop, redViewTrailing, redViewHeight])
// 为黑色视图添加约束,黑色视图除了top是相对于redView布局,其它等同于redView
let blackViewLeading = NSLayoutConstraint(item: blackView, attribute: .leading, relatedBy: .equal, toItem: redView, attribute: .leading, multiplier: 1.0, constant: 0)
let blackViewTop = NSLayoutConstraint(item: blackView, attribute: .top, relatedBy: .equal, toItem: redView, attribute: .bottom, multiplier: 1.0, constant: space)
let blackViewTrailing = NSLayoutConstraint(item: blackView, attribute: .trailing, relatedBy: .equal, toItem: redView, attribute: .trailing, multiplier: 1.0, constant: 0)
let blackViewHeight = NSLayoutConstraint(item: blackView, attribute: .height, relatedBy: .equal, toItem: redView, attribute: .height, multiplier: 1.0, constant: 0)
view.addConstraints([blackViewLeading, blackViewTop, blackViewTrailing, blackViewHeight])
// 为蓝色视图添加约束,黑色视图除了top是相对于blackView布局,其它等同于blackView
let blueViewLeading = NSLayoutConstraint(item: blueView, attribute: .leading, relatedBy: .equal, toItem: blackView, attribute: .leading, multiplier: 1.0, constant: 0)
let blueViewTop = NSLayoutConstraint(item: blueView, attribute: .top, relatedBy: .equal, toItem: blackView, attribute: .bottom, multiplier: 1.0, constant: space)
let blueViewTrailing = NSLayoutConstraint(item: blueView, attribute: .trailing, relatedBy: .equal, toItem: blackView, attribute: .trailing, multiplier: 1.0, constant: 0)
let blueViewHeight = NSLayoutConstraint(item: blueView, attribute: .height, relatedBy: .equal, toItem: blackView, attribute: .height, multiplier: 1.0, constant: 0)
view.addConstraints([blueViewLeading, blueViewTop, blueViewTrailing, blueViewHeight])
}
}
实现效果如下: