典型的,加入一个子视图的作法就是建立实例,指定位置,而后把它加入到视图里面来。在指定位置的代码处,通常就是设置frame属性便可,就像这样:javascript
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window!.rootViewController = Page()
self.window?.makeKeyAndVisible()
return true
}
}
class Page: UIViewController{
var vw : UIView!
override func viewDidLoad() {
super.viewDidLoad()
vw = UIView()
vw.backgroundColor = .red
vw.frame = CGRect(x: 5, y: 5, width: 50, height: 50)
view.addSubview(vw)
}
}复制代码
代码把一个边长为50的正方形加入到x: 5, y: 5的位置上,位置相对于它的父视图的左上脚点。若是咱们的相对点变化了,好比说但愿把这个正方形以自身的右下脚点为惨遭,放到相对于父视图的右下脚点的的-5,-5的位置上的话,会产生些问题:java
解决此问题的要点在于,App只是声明本身的位置关系,具体的坐标有UIKit来计算。如今UIKit提供的AutoLayout技术就能够解决此问题。app
就以此问题为例,能够去掉:ide
vw.frame = CGRect(x: 5, y: 5, width: 50, height: 50)复制代码
改为以下的约束:函数
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window!.rootViewController = Page()
self.window?.makeKeyAndVisible()
return true
}
}
class Page: UIViewController{
var vw : UIView!
override func viewDidLoad() {
super.viewDidLoad()
vw = UIView()
vw.backgroundColor = .red
view.addSubview(vw)
vw.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = NSLayoutConstraint(item: vw, attribute: NSLayoutAttribute.right, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.right, multiplier: 1, constant: -5)
let verticalConstraint = NSLayoutConstraint(item: vw, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: -5)
let widthConstraint = NSLayoutConstraint(item: vw, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)
let heightConstraint = NSLayoutConstraint(item: vw, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)
view.addConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
}复制代码
首先必须设置此视图的属性:布局
vw.translatesAutoresizingMaskIntoConstraints = false复制代码
这样AutoLayout才能生效。随后建立的第一约束:spa
let horizontalConstraint = NSLayoutConstraint(item: vw, attribute: NSLayoutAttribute.right, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.right, multiplier: 1, constant: -5)复制代码
看起来有些复杂,可是若是知道一个公式就更容易读懂此代码。NSLayoutConstraint用来建立阅读,其函数参数标签有:code
公式由此标签指定以下:对象
item.attribute relatedBy toItem.attribute*multiplier + constant复制代码
标签relatedBy指定的是一个操做符号,此处为“=”,所以此公式简化为:ip
item.attribute = toItem.attribute*multiplier + constant复制代码
再次的把标签带入参数值,就是这样:
vw.right = view.right*1 - 5复制代码
读出来的意思就是:
视图vw的右边x值约束为视图view的右边x值乘以1再减去5复制代码
因而能够类推第二个约束为正方形的下边y值和父视图的下边y值的约束定义:
视图vw的下边y值约束为视图view的下边y值乘以1再减去5复制代码
此案例中,正方形的宽度则只是一个常数值,并不须要相对于任何视图的任何属性,所以建立类NSLayoutConstraint时,公式中:
item.attribute relatedBy toItem.attribute*multiplier + constant复制代码
的toItem.attribute*multiplier总体是无心义的,而简化为:
item.attribute = constant复制代码
这也就是代码:
let widthConstraint = NSLayoutConstraint(item: vw, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)复制代码
标签toItem为nil, 标签attribute为NSLayoutAttribute.notAnAttribute的含义。一样的,正方形的高度也是如此分析。
使用自动布局,一个视图的位置的参照物再也不仅仅是父视图的左上脚点,而是变得丰富多彩,依据不一样的状况有不一样的选择:
如此等等。所以以前的指定xy值的作法,就称为自动布局方法的一个特殊案例。