SnapKit-自动布局库学习笔记
本文介绍快速上手指南,想100%掌握移步别的教程
大体使用方法
- 1、初始化子视图(不需要frame参数),addSubview到父视图上
2、调用 subView.snp.makeConstraints { make in … }
尽情享受简洁代码实现 AutoLayout吧!
_UIView.snp.makeConstraints 方法给view添加约束,约束种类 常用的:centerX/Y,宽,高,上下左右距离。同时,添加过约束后可以有修正(inset、offset)//其他不常用的以后再说
约束条件参数
读下面的代码,就可以直接上手用了
import UIKit
import SnapKit
//例一
class ViewController: UIViewController {
var box = UIView()
override func viewDidLoad() {
super.viewDidLoad()
box.backgroundColor = UIColor.orange
view.addSubview(box)
box.snp.makeConstraints { make in
make.width.equalTo(100)
make.height.equalTo(100)
make.center.equalTo(self.view)
//笔记一:如果参数是一个UIView或其子类,就相当于view.snp.center
//前面是center就省略的 snp.center,前面是width就省略的 snp.width
}
}
}
//例二
class ViewController2: UIViewController {
var box = UIView()
override func viewDidLoad() {
super.viewDidLoad()
box.backgroundColor = UIColor.orange
self.view.addSubview(box)
box.snp.makeConstraints { make in
make.width.height.equalTo(100)
//笔记二:可以 宽 高等等属性 串联用,像上面这句
make.center.equalTo(self.view)
}
}
}
一、所有属性(很多不常用)
视图属性(ViewAttribute) | 布局属性(NSLayoutAttribute) |
---|---|
view.snp.left | NSLayoutAttribute.Left |
view.snp.right | NSLayoutAttribute.Right |
view.snp.top | NSLayoutAttribute.Top |
view.snp.bottom | NSLayoutAttribute.Bottom |
view.snp.leading | NSLayoutAttribute.Leading |
view.snp.trailing | NSLayoutAttribute.Trailing |
view.snp.width | NSLayoutAttribute.Width |
view.snp.height | NSLayoutAttribute.Height |
view.snp.centerX | NSLayoutAttribute.CenterX |
view.snp.centerY | NSLayoutAttribute.CenterY |
view.snp.baseline | NSLayoutAttribute.Baseline |
二、视图关系(不常用,可跳过)
想让view.left 大于等于 label.left:
make.left.greaterThanOrEqualTo(label)
像刚才说的,它就等价于:
make.left.greaterThanOrEqualTo(label.snp.left)
三、确定值 (常用)
比如将宽度和高度属性设置为常量值:(常量值根据设备不同适配不同的值)
make.height.equalTo(20)
make.width.equalTo(20)
make.top.equalTo(42)
给视图的各种属性设置约束
直接看代码
class ViewController: UIViewController {
//外部方块
var boxOutter = UIView()
//内部方块
var boxInner = UIView()
override func viewDidLoad() {
super.viewDidLoad()
boxOutter.backgroundColor = UIColor.orange
view.addSubview(boxOutter)
boxInner.backgroundColor = UIColor.green
boxOutter.addSubview(boxInner)
boxOutter.snp.makeConstraints { make in
make.width.height.equalTo(200)
make.center.equalTo(self.view)
}
//注意两个view是嵌套的
boxInner.snp.makeConstraints { make in
make.width.height.equalTo(100)
make.right.equalTo(0)
make.bottom.equalTo(0)
}
/*
box2.snp.makeConstraints { make in
make.width.height.equalTo(box1)
make.left.equalTo(box1)
make.top.equalTo(box1.snp.bottom)
}
*/
}
}
edges(边缘)
(先说下偏移,一会见到:offset多少 是往右或往下或往外多少,inset相反)
让当前视图 的 上下左右(top,left,bottom,right) 等于 view2
make.edges.equalTo(view2)
// 内偏移
make.edges.equalTo(view2).inset(UIEdgeInsetsMake(10, 15, 20, 25))
// 外偏移
make.top.equalTo(view2).offset(20)
size(尺寸)
// 外偏移 -50,就是内移。。
make.size.equalTo(boxOutter).offset(-50)
//size就是让 width = 父视图.width - 50, height = 父视图.height - 50
center(中心)
当前视图与 button1中心相同 (centerX 和 centerY)
make.center.equalTo(button1)
//倍率:multipliedBy 将视图的尺寸设置成父视图几倍大小,乘法
make.center.equalTo(boxOutter)
make.size.equalTo(boxOutter).multipliedBy(0.5)
//即 width = superview.width * 0.5, height = superview.height / 2
修改约束
我们可以通过 约束的引用 来修改约束。
删除
开始我们给方块添加宽高150约束,以及页面居中约束,然后另点一个击按钮调用其 deactivate() 方法把这尺寸约束给移除,方块消失(即长宽变成0,0) demo:
import UIKit
import SnapKit
class ViewController: UIViewController {
var box = UIView()
//声明一个约束的引用
var sizeConstraint:Constraint?
override func viewDidLoad() {
super.viewDidLoad()
box.backgroundColor = UIColor.orange
self.view.addSubview(box)
box.snp.makeConstraints { (make) in
self.sizeConstraint = make.width.height.equalTo(150).constraint
//上句解释:在把宽高设为150同时,把约束赋值给那个变量
make.center.equalTo(self.view)
}
}
//按钮点击
@IBAction func btnTouch(_ sender: AnyObject) {
//移除约束
self.sizeConstraint?.deactivate()
//相反:sizeConstraints?.activate()
/*注意:这个方法是针对宽高的约束,如果是下面这样位置的约束就没反应:
make.width.height.equalTo(100)
sizeConstraints = make.left.top.equalTo(100).constraint
下面关于更新约束的内容会涉及。
*/
}
}
更新
把 make 修改为:
make.width.height.equalTo(150) //大小
make.centerX.equalTo(self.view) // x轴方向,下面y轴方向:
myConstraint = make.top.equalTo(self.view).offset(40).constraint
把按钮事件内容修改为:
myConstraint?.update(offset: 60) //把offset设置为60,不是加60;参数可以是inset,原理相同。
snp的其他方法
前面我们只用到了 snp.makeConstriants ,下面是其他几个方法及用途:
snp.updateConstraints
更新某项约束。应用:转屏 自动设置和屏幕等宽
class ViewController: UIViewController {
var box = UIView()
override func viewDidLoad() {
super.viewDidLoad()
box.backgroundColor = UIColor.orange
self.view.addSubview(box)
box.snp.makeConstraints { (make) in
make.width.equalTo(self.view)
make.height.equalTo(150)
make.centerX.equalTo(self.view)
}
}
//视图约束更新,在 1、界面将出现时 2、转屏时 自动调用。
override func updateViewConstraints() {
self.box.snp.updateConstraints{ (make) in
make.width.equalTo(self.view)
}
super.updateViewConstraints() //文档里让一定要最后写上这句==
}
//注意!界面显示时一定会调用该方法来重新设置width,但是在上面 makeConstraints里必须设置width,不然等崩(snp库自报fatalError)
//但是如果没有重写这个update方法,就可以不设置width,并默认为0(没有人会不去设置的对吧)==
}
snp.remakeConstraints
//三分钟 remake了
snp.remakeConstraints 首先会先清除掉之前所有被SnapKit设置的约束。比如你点击某个按钮,响应里调这个方法。其他用法完全同makeConstraints.
约束优先级
优先级高的约束覆盖优先级低的约束(看demo就明白)
通过 priority() 方法,参数是0-1000的数字,默认优先级1000
box.snp.makeConstraints { (make) in
make.center.equalTo(self.view) //居中
make.width.height.equalTo(200).priority(250) //250级
make.width.lessThanOrEqualTo(100) //1000级!
make.height.lessThanOrEqualTo(100).priority(200) //200级
make.height.lessThanOrEqualTo(100).priority(250) //250级,同样级数比谁定义的早
//结果宽高分别是: 100,200
}
约束改变时配动画效果
demo
import Foundation
import UIKit
import SnapKit
class SignInViewController: UIViewController {
var box = UIView()
var scale = 1.0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
box.backgroundColor = UIColor.lightGray
//使用 snp.makeConstraints 方法必须先添加到父视图
view.addSubview(box)
box.snp.makeConstraints{ (make) in
make.width.equalTo(100)
make.top.height.equalTo(100)
}
box.isUserInteractionEnabled = true
let gesture = UITapGestureRecognizer(target: self, action: #selector(onTap))
box.addGestureRecognizer(gesture)
}
override func updateViewConstraints() {
print("updating")
box.snp.updateConstraints{ (make) in
make.width.equalTo(100*scale)
}
super.updateViewConstraints()
print("updated")
}
func onTap(){
scale += 0.5
view.setNeedsUpdateConstraints()
print("needed")
UIView.animate(withDuration: 0.5){
print("start animating")
self.view.layoutIfNeeded() // mark1
print("start sleeping")
//Thread.sleep(forTimeInterval: 2) //mark2
print("stop animating")
}
print("func end")
}
}
先解释几个方法:
setNeedsUpdateConstraints()
声明 view 处于 需要更新约束的状态。注意是声明。到底什么时候开始更新呢?看下面
layoutIfNeeded()
如果view处于 需要布局的状态,就立刻开始布局 ( 调用updateViewConstraints() )
如果 setNeedsUpdateConstraints() 所处的代码块 { } 内代码全都执行完了还没遇见 layoutIfNeeded() 指令,就开始执行updateViewConstraints()
现在 把 mark2 那行注释去掉,跑两遍:
mark1 那行注释掉与不注释掉分别跑一遍,看打印就能理解了。