为了适应各种屏幕尺寸,iOS 6后引入了自动布局(Auto Layout)的概念,通过使用各种 Constraint(约束)来实现页面自适应弹性布局。(想了解更多可查看我原来写的这篇文章:Swift - 使用Auto Layout和Size Classes实现页面自适应弹性布局

在 StoryBoard 中使用约束实现自动布局很方便,但如果用纯代码来设置约束就很麻烦了。这里向大家推荐一个好用的第三方布局库:SnapKit(其前身是 Masonry,一个OC版的布局库)

1,SnapKit介绍

SnapKit是一个优秀的第三方自适应布局库,它可以让iOS、OS X应用更简单地实现自动布局(Auto Layout)。
GtiHub地址:https://github.com/SnapKit/SnapKit
 
2,SnapKit配置

(1)将下载下来的SnapKit项目的 SnapKit.xcodeproj 拖进自己的项目目录当中

(2)在 工程 -> General -> Embedded Binaries 中点击加号,添加SnapKit库到项目中来

3,先看一个简单的使用样例
在页面正中央放置一个100*100的正方形view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
    lazy var box = UIView()
 
    override func viewDidLoad() {
        super.viewDidLoad()
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            make.width.equalTo(100)
            make.height.equalTo(100)
            make.center.equalTo(self.view)
        }
    }
}

由于长宽都一样,我们还可以串连视图属性,增加可读性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
    lazy var box = UIView()
 
    override func viewDidLoad() {
        super.viewDidLoad()
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(100)
            make.center.equalTo(self.view)
        }
    }
}

4,SnapKit的使用方法
通过 snp_makeConstraints 方法给view添加约束,约束有几种,分别是边距,宽,高,左上右下距离,基准线。同时,添加过约束后可以有修正,修正有位移修正(inset、offset)和倍率修正(multipliedBy)

语法一般是: make.equalTo 或 make.greaterThanOrEqualTo 或 make.lessThanOrEqualTo + 倍数和位移修正。

.equalTo:等于 
.lessThanOrEqualTo:小于等于
.greaterThanOrEqualTo:大于等于

注意: 使用 snp_makeConstraints 方法的元素必须事先添加到父元素的中,例如:self.view.addSubview(view)

5,约束条件参数支持如下三种类型:
(1)视图属性(ViewAttribute)

视图属性(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
1
2
//使当前视图对象的中心x坐标小于等于视图view2的左边的x坐标
make.centerX.lessThanOrEqualTo(view2.snp_left)

(2)视图关系(UIView/NSView)

比如想让view.left 大于等于 label.left:

1
make.left.greaterThanOrEqualTo(label)

这个其实等价于:

1
make.left.greaterThanOrEqualTo(label.snp_left)

(3)严格检测(Strick Checks)
比如将宽度和高度属性设置为常量值:

1
2
3
make.height.equalTo(20)
make.width.equalTo(20)
make.top.equalTo(42)

6,给视图的各种属性设置约束
(1)width、height属性
自动布局允许宽度、高度设置为常量值。

1
2
3
4
make.height.equalTo(20)
make.width.equalTo(self.buttonSize.width)
//当前视图与label的顶部齐平
make.top.equalTo(label.snp_top)

(2) left、right、top、centerX、centerY等其他属性
这些属性直接设置常量值,表示他们相对于父容器的相对约束条件。比如我们将绿色方块放置橙色方块内部的右下角位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    //外部方块
    lazy var boxOutter = UIView()
    //内部方块
    lazy var boxInner = UIView()
 
    override func viewDidLoad() {
        super.viewDidLoad()
         
        boxOutter.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(boxOutter)
        boxInner.backgroundColor = UIColor.greenColor()
        boxOutter.addSubview(boxInner)
         
        boxOutter.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(200)
            make.center.equalTo(self.view)
        }
         
        boxInner.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(100)
            make.right.equalTo(0)
            make.bottom.equalTo(0)
        }
    }
}

当然也可以使用与其他视图的关系来添加约束。比如:下面绿色方块视图大小同上面橙色方块相同,下面视图与上面视图左侧平齐,下面视图顶部与上面视图底部平齐。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    //方块1
    lazy var box1 = UIView()
    //方块2
    lazy var box2 = UIView()
 
    override func viewDidLoad() {
        super.viewDidLoad()
         
        box1.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box1)
        box2.backgroundColor = UIColor.greenColor()
        self.view.addSubview(box2)
         
        box1.snp_makeConstraints { (make) -> Void in
            make.left.equalTo(20)
            make.right.equalTo(-20)
            make.height.equalTo(40)
            make.top.equalTo(20)
        }
         
        box2.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(box1)
            make.left.equalTo(box1) //等同于 make.left.equalTo(box1.snp_left)
            make.top.equalTo(box1.snp_bottom)
        }
    }
}

(3)edges(边缘)

1
2
//让当前视图 的 上下左右(top,left,bottom,right) 等于 view2
make.edges.equalTo(view2)

(4)size(尺寸)

1
2
//当前视图宽高 >= titleLabel
make.size.greaterThanOrEqualTo(titleLabel)

(5)center(中心)

1
2
//当前视图与 button1中心相同 (centerX 和 centerY)
make.center.equalTo(button1)

7,位移修正与倍率修正
(1)内位移修正:inset
比如下图中绿色视图view,它距离父视图上、左、下、右边距分别是10、15、20、25

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    //外部方块
    lazy var boxOutter = UIView()
    //内部方块
    lazy var boxInner = UIView()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        boxOutter.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(boxOutter)
        boxInner.backgroundColor = UIColor.greenColor()
        boxOutter.addSubview(boxInner)
         
        boxOutter.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(200)
            make.center.equalTo(self.view)
        }
         
        boxInner.snp_makeConstraints { (make) -> Void in
            make.edges.equalTo(boxOutter).inset(UIEdgeInsetsMake(10, 15, 20, 25))
        }
    }
}

上面边距的偏移设置实际上相当于如下形式:

1
2
3
4
make.top.equalTo(boxOutter).offset(10)
make.left.equalTo(boxOutter).offset(15)
make.bottom.equalTo(boxOutter).offset(-20)
make.right.equalTo(boxOutter).offset(-25)

(2)外位移修正:offset 

下面让绿色视图比橙色视图宽度加50,高度减50。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    //外部方块
    lazy var boxOutter = UIView()
    //内部方块
    lazy var boxInner = UIView()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        boxOutter.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(boxOutter)
        boxInner.backgroundColor = UIColor.greenColor()
        boxOutter.addSubview(boxInner)
         
        boxOutter.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(200)
            make.center.equalTo(self.view)
        }
         
        boxInner.snp_makeConstraints { (make) -> Void in
            make.center.equalTo(boxOutter)
            // make width = superview.width + 100, height = superview.height - 50
            make.size.equalTo(boxOutter).offset(CGSizeMake(50, -50))
        }
    }
}

(3)倍率修正:multipliedBy 

下面将绿色视图的尺寸设置成橙色视图一半大小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    //外部方块
    lazy var boxOutter = UIView()
    //内部方块
    lazy var boxInner = UIView()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        boxOutter.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(boxOutter)
        boxInner.backgroundColor = UIColor.greenColor()
        boxOutter.addSubview(boxInner)
         
        boxOutter.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(200)
            make.center.equalTo(self.view)
        }
         
        boxInner.snp_makeConstraints { (make) -> Void in
            make.center.equalTo(boxOutter)
            // make width = superview.width / 2, height = superview.height / 2
            make.size.equalTo(boxOutter).multipliedBy(0.5)
        }
    }
}
 

二、Swift - 自动布局库SnapKit的使用详解2(约束的更新、移除、重做)

在之前的文章中我介绍了如何使用SnapKit的 snp_makeConstraints 方法进行各种约束的设置。但有时我们的页面并不是一直固定不变的,这就需要修改已经存在的约束。本文介绍如何更新、移除、代替现有的约束。

 
1,删除约束

要实现对现有的约束进行更新或者移除,我们需要先将约束的结果赋值给一个局部变量或一个类属性,然后对这个约束的引用进行操作。
比如下面样例:开始时我们给橙色方块添加了个距屏幕上方40像素的约束,点击按钮后使用 uninstall() 方法把这个约束给移除。

            
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    lazy var box = UIView()
     
    //保存约束的引用
    var topConstraint:Constraint?
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(150)
            make.centerX.equalTo(self.view)
            self.topConstraint = make.top.equalTo(self.view).offset(40).constraint
        }
    }
     
    //按钮点击
    @IBAction func btnTouch(sender: AnyObject) {
        //移除约束
        self.topConstraint?.uninstall()
    }
}

2,通过约束的引用来更新约束
还是以上面距屏幕上方40像素的约束为例,点击按钮后,通过调用约束引用的 updateOffset() 方法把距离修改成60像素。

            
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    lazy var box = UIView()
     
    //保存约束的引用
    var topConstraint:Constraint?
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(150)
            make.centerX.equalTo(self.view)
            self.topConstraint = make.top.equalTo(self.view).offset(40).constraint
        }
    }
     
    //按钮点击
    @IBAction func btnTouch(sender: AnyObject) {
        //更新修改约束
        self.topConstraint?.updateOffset(60)
    }
}

3,使用snp_updateConstraints更新约束
我们还可以用 snp_updateConstraints 方法来代替 snp_makeConstraints 进行约束的更新,这个更新操作通常放在 UIViewController 的 updateViewConstraints() 方法中,或者 UIView 的 updateConstraints() 方法中执行,这样视图约束需要更新的时候会自动调用。
比如下面样例,我们使用 snp_updateConstraints() 方法设置橙色视图的宽度约束为与屏幕等宽,这样不管设备如何旋转,视图都回自动更新约束撑满屏幕。

            
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    lazy var box = UIView()
     
    
    override func viewDidLoad() {
        super.viewDidLoad()
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            make.height.equalTo(150)
            make.centerX.equalTo(self.view)
        }
    }
   
    //视图约束更新
    override func updateViewConstraints() {
        self.box.snp_updateConstraints{ (make) -> Void in
            //视图宽度与屏幕等宽
            make.width.equalTo(self.view)
        }
   
        super.updateViewConstraints()
    }
}

4,使用snp_remakeConstraints重做约束
snp_remakeConstraints 与 snp_makeConstraints 用法类似,不同的是 snp_remakeConstraints 首先会先清除掉之前所有被SnapKit设置的约束。

下面样例:初始化时橙色视图约束是宽高150,水平居中。点击按钮后重做约束,宽高变100,且不再居中。
            
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    lazy var box = UIView()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            make.width.height.equalTo(150)
            make.centerX.equalTo(self.view)
        }
    }
   
    //按钮点击
    @IBAction func btnTouch(sender: AnyObject) {
        //重做约束
        box.snp_remakeConstraints { (make) -> Void in
            make.width.height.equalTo(100)
        }
    }
}

三、Swift - 自动布局库SnapKit的使用详解3(约束优先级,约束做动画)

1,约束优先级

我们使用SnapKit的时候,还可以定义约束的优先级。这样当约束出现冲突的时候,优先级高的约束覆盖优先级低的约束。具体优先级可以放在约束链的结束处。

 
(1)可以设置如下几种优先级

priorityLow():设置低优先级,优先级为250
priorityMedium():设置中优先级,优先级为500(这个也就是默认的优先级)
priorityHigh():设置高优先级,优先级为750
priority():可以设置任意的优先级,接受的参数是0-1000的数字。比如:priority(600)

(2)使用优先级的样例
下面我们在屏幕中央放置一个100*100的橙色方块,给其定义了长宽尺寸小于等于屏幕的大小的默认优先级约束。同时,每次点击屏幕的时候,会更新放大它的尺寸。但由于这个约束的优先级是低,所有方块顶到屏幕边缘后就会不再放大。

      

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    lazy var box = UIView()
     
    var scacle = 1.0
    
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //单击监听
        let tapSingle=UITapGestureRecognizer(target:self,action:#selector(tapSingleDid))
        tapSingle.numberOfTapsRequired=1
        tapSingle.numberOfTouchesRequired=1
        self.view.addGestureRecognizer(tapSingle)
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            //视图居中
            make.center.equalTo(self.view)
            //初始宽、高为100(优先级低)
            make.width.height.equalTo(100 * self.scacle).priorityLow();
            //最大尺寸不能超过屏幕
            make.width.height.lessThanOrEqualTo(self.view.snp_width)
            make.width.height.lessThanOrEqualTo(self.view.snp_height)
        }
    }
     
    //点击屏幕
    func tapSingleDid(){
        self.scacle += 0.5
        self.box.snp_updateConstraints{ (make) -> Void in
            //放大视图(优先级最低)
            make.width.height.equalTo(100 * self.scacle).priorityLow();
        }
    }
}
 

2,带有动画效果
配合 UIView.animateWithDuration,我们可以在约束改变的时候有动画效果。 
还是以上面的样例演示,不够这次点击屏幕时橙色视图放大的时候会有过渡,而不是一下就变大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    lazy var box = UIView()
     
    var scacle = 1.0
    
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //单击监听
        let tapSingle=UITapGestureRecognizer(target:self,action:#selector(tapSingleDid))
        tapSingle.numberOfTapsRequired=1
        tapSingle.numberOfTouchesRequired=1
        self.view.addGestureRecognizer(tapSingle)
         
        box.backgroundColor = UIColor.orangeColor()
        self.view.addSubview(box)
         
        box.snp_makeConstraints { (make) -> Void in
            //视图居中
            make.center.equalTo(self.view)
            //初始宽、高为100(优先级低)
            make.width.height.equalTo(100 * self.scacle).priorityLow();
            //最大尺寸不能超过屏幕
            make.width.height.lessThanOrEqualTo(self.view.snp_width)
            make.width.height.lessThanOrEqualTo(self.view.snp_height)
        }
    }
     
    //视图约束更新
    override func updateViewConstraints() {
        self.box.snp_updateConstraints{ (make) -> Void in
            //放大尺寸(优先级低)
            make.width.height.equalTo(100 * self.scacle).priorityLow();
        }
         
        super.updateViewConstraints()
    }
     
    //点击屏幕
    func tapSingleDid(){
        self.scacle += 0.5
        //告诉self.view约束需要更新
        self.view.setNeedsUpdateConstraints()
        //动画
        UIView.animateWithDuration(0.3) {
            self.view.layoutIfNeeded()
        }
    }
}

四、Swift - 自动布局库SnapKit的使用详解4(样例1:实现一个登录页面)

前面的几篇文章讲解了自动布局库SnapKit的使用方法(点击查看SnapKit的配置方法)。本文通过一个完整的样例(登录页面)来演示在实际项目中如何使用SnapKit来实现自动化布局的。
 
1,效果图如下
                     
 
2,代码讲解
(1)用户名、密码输入区域(白色区域)设置垂直居中约束,其高度是固定90,宽度自适应(距离屏幕左右侧都为15像素)
(2)用户名、密码输入框之间分割线是使用灰色背景的UIView实现,其高度是1像素,同样设置垂直居中约束。
(3)登录按钮距离上方输入区域20像素,高度固定是40,宽度同样自适应(距离屏幕左右侧都为15像素)
(4)上方标题标签据下方输入区域20像素,宽度自适应,内容居中。
(5)当键盘出现时,修改输入区域的垂直约束偏移量,使其向上移动(移动时,登陆按钮、标题标签也会同步移动)。避免在使用小屏设备时,键盘把登录框给挡住。
(6)键盘消失时,整个登录区域又会下移回复原位(上移、下移过程都有动画效果)
 
3,页面代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import UIKit
import SnapKit
 
class ViewControllerUIViewControllerUITextFieldDelegate {
     
    var txtUser: UITextField//用户名输入框
    var txtPwd: UITextField//密码输入款
    var formView: UIView//登陆框视图
    var horizontalLine: UIView//分隔线
    var confirmButton:UIButton//登录按钮
    var titleLabel: UILabel//标题标签
     
    var topConstraint: Constraint//登录框距顶部距离约束
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //视图背景色
        self.view.backgroundColor = UIColor(red: 1/255, green: 170/255, blue: 235/255,
                                            alpha: 1)
         
        //登录框高度
        let formViewHeight = 90
        //登录框背景
        self.formView = UIView()
        self.formView.layer.borderWidth = 0.5
        self.formView.layer.borderColor = UIColor.lightGrayColor().CGColor
        self.formView.backgroundColor = UIColor.whiteColor()
        self.formView.layer.cornerRadius = 5
        self.view.addSubview(self.formView)
        //最常规的设置模式
        self.formView.snp_makeConstraints { (make) -> Void in
            make.left.equalTo(15)
            make.right.equalTo(-15)
            //存储top属性
            self.topConstraint = make.centerY.equalTo(self.view).constraint
            make.height.equalTo(formViewHeight)
        }
         
        //分隔线
        self.horizontalLine =  UIView()
        self.horizontalLine.backgroundColor = UIColor.lightGrayColor()
        self.formView.addSubview(self.horizontalLine)
        self.horizontalLine.snp_makeConstraints { (make) -> Void in
            make.height.equalTo(0.5)
            make.left.equalTo(15)
            make.right.equalTo(-15)
            make.centerY.equalTo(self.formView)
        }
         
        //密码图
        let imgLock1 =  UIImageView(frame:CGRectMake(11, 11, 22, 22))
        imgLock1.image = UIImage(named:"iconfont-user")
         
        //密码图
        let imgLock2 =  UIImageView(frame:CGRectMake(11, 11, 22, 22))
        imgLock2.image = UIImage(named:"iconfont-password")
         
        //用户名输入框
        self.txtUser = UITextField()
        self.txtUser.delegate = self
        self.txtUser.placeholder = "用户名"
        self.txtUser.tag = 100
        self.txtUser.leftView = UIView(frame:CGRectMake(0, 0, 44, 44))
        self.txtUser.leftViewMode = UITextFieldViewMode.Always
        self.txtUser.returnKeyType = UIReturnKeyType.Next
         
        //用户名输入框左侧图标
        self.txtUser.leftView!.addSubview(imgLock1)
        self.formView.addSubview(self.txtUser)
         
        //布局
        self.txtUser.snp_makeConstraints { (make) -> Void in
            make.left.equalTo(15)
            make.right.equalTo(-15)
            make.height.equalTo(44)
            make.centerY.equalTo(0).offset(-formViewHeight/4)
        }
         
        //密码输入框
        self.txtPwd = UITextField()
        self.txtPwd.delegate = self
        self.txtPwd.placeholder = "密码"
        self.txtPwd.tag = 101
        self.txtPwd.leftView = UIView(frame:CGRectMake(0, 0, 44, 44))
        self.txtPwd.leftViewMode = UITextFieldViewMode.Always
        self.txtPwd.returnKeyType = UIReturnKeyType.Next
         
        //密码输入框左侧图标
        self.txtPwd.leftView!.addSubview(imgLock2)
        self.formView.addSubview(self.txtPwd)
         
        //布局
        self.txtPwd.snp_makeConstraints { (make) -> Void in
            make.left.equalTo(15)
            make.right.equalTo(-15)
            make.height.equalTo(44)
            make.centerY.equalTo(0).offset(formViewHeight/4)
        }
         
        //登录按钮
        self.confirmButton = UIButton()
        self.confirmButton.setTitle("登录", forState: UIControlState.Normal)
        self.confirmButton.setTitleColor(UIColor.blackColor(),
                                         forState: UIControlState.Normal)
        self.confirmButton.layer.cornerRadius = 5
        self.confirmButton.backgroundColor = UIColor(colorLiteralRed: 1, green: 1, blue: 1,
                                                     alpha: 0.5)
        self.confirmButton.addTarget(self, action: #selector(loginConfrim),
                                     forControlEvents: .TouchUpInside)
        self.view.addSubview(self.confirmButton)
        self.confirmButton.snp_makeConstraints { (make) -> Void in
            make.left.equalTo(15)
            make.top.equalTo(self.formView.snp_bottom).offset(20)
            make.right.equalTo(-15)
            make.height.equalTo(44)
        }
         
        //标题label
        self.titleLabel = UILabel()
        self.titleLabel.text = "hangge.com"
        self.titleLabel.textColor = UIColor.whiteColor()
        self.titleLabel.font = UIFont.systemFontOfSize(36)
        self.view.addSubview(self.titleLabel)
        self.titleLabel.snp_makeConstraints { (make) -> Void in
            make.bottom.equalTo(self.formView.snp_top).offset(-20)
            make.centerX.equalTo(0)
            make.height.equalTo(44)
        }
    }
     
    //输入框获取焦点开始编辑
    func textFieldDidBeginEditing(textField:UITextField)
    {
         
        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.topConstraint?.updateOffset(-125)
            self.view.layoutIfNeeded()
        })
    }
     
    //输入框返回时操作
    func textFieldShouldReturn(textField:UITextField) -> Bool
    {
        let tag = textField.tag
        switch tag {
        case 100:
            self.txtPwd.becomeFirstResponder()
        case 101:
            loginConfrim()
        default:
            print(textField.text)
        }
        return true
    }
     
    //登录按钮点击
    func loginConfrim(){
        //收起键盘
        self.view.endEditing(true)
        //视图约束恢复初始设置
        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.topConstraint?.updateOffset(0)
            self.view.layoutIfNeeded()
        })
    }
}

源码下载:hangge_1112.zip

五、Swift - 自动布局库SnapKit的使用详解5(样例2:实现一个计算器界面)

前面演示了使用SnapKit实现一个登录页面(点击此处查看),本文再来一个稍微复杂点的样例:模仿iOS系统自带的计算器布局。(SnapKit具体配置方法可参考:Swift - 自动布局库SnapKit的使用详解1(配置、使用方法、样例)

1,效果图如下

2,代码讲解
(1)首先将视图分成上下两部分,上面部分用来显示数字,下面部分是键盘区域(放置计算器按钮)。
(2)键盘区域宽高比是4:5(保证每个按钮是正方形)。
(3)按从上到下,从左往右的顺序添加每个按钮,并设置对应的约束。
(4)按钮的垂直位置约束是:下一排的按钮顶部紧跟着上一排按钮的底部。
(5)按钮的水平位置约束是:第1列按钮左侧等于页面左边缘,第4列按钮右侧等于页面右边缘。第2列按钮右侧等于页面中线位置,第3列按钮左侧等于页面中线位置。

 

3,页面代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import UIKit
import SnapKit
 
class ViewControllerUIViewController {
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //申明区域,keyboardView是键盘区域
        let keyboardView =  UIView()
        keyboardView.backgroundColor = UIColor(red:212/255, green:213/255, blue:216/255,
                                               alpha:1)
        self.view.addSubview(keyboardView)
         
        //键盘区域约束
        keyboardView.snp_makeConstraints { (make) -> Void in
             
            make.bottom.equalTo(self.view.snp_bottom)
            make.left.right.equalTo(self.view)
            make.height.equalTo(self.view.snp_width).multipliedBy(1.25)
        }
         
        //displayView是显示区
        let displayView =  UIView()
        displayView.backgroundColor = UIColor.blackColor()
        self.view.addSubview(displayView)
         
        //显示区域约束
        displayView.snp_makeConstraints { (make) -> Void in
            make.top.equalTo(self.view.snp_top)
            make.bottom.equalTo(keyboardView.snp_top)
            make.left.right.equalTo(self.view)
        }
         
        //设置显示位置的数字为0
        let displayNum =  UILabel()
        displayNum.text = "0"
        displayNum.font = UIFont(name:"HeiTi SC", size:70)
        displayNum.textColor = UIColor.whiteColor()
        displayNum.textAlignment = .Right
        displayView.addSubview(displayNum)
         
        //数字标签约束
        displayNum.snp_makeConstraints { (make) -> Void in
            make.left.right.equalTo(displayView).offset(-10)
            make.bottom.equalTo(displayView).offset(-10)
        }
         
        //定义键盘键名称(?号是占位符,代表合并的单元格)
        let keys = ["AC","+/-","%","÷"
            ,"7","8","9","x"
            ,"4","5","6","-"
            ,"1","2","3","+"
            ,"0","?",".","="]
         
        //保存所有的按钮
        var keyViews = [UIButton]()
         
        //循环添加按钮
        for in 0..<5{
            for in 0..<4 {
                let indexOfKeys = i * 4 + j
                let key = keys[indexOfKeys]
                 
                //键样式
                let keyView =  UIButton(type:.Custom)
                keyboardView.addSubview(keyView)
                keyViews.append(keyView)
                keyView.setTitleColor(UIColor.blackColor(), forState: .Normal)
                keyView.setTitle(key, forState: .Normal)
                keyView.layer.borderWidth = 0.5
                keyView.layer.borderColor = UIColor.blackColor().CGColor
                keyView.titleLabel?.font = UIFont(name:"Arial-BoldItalicMT", size:30)
                 
                 //处理合并单元格(不用添加到界面上,也不用添加约束)
                if key == "?"{
                    keyView.removeFromSuperview()
                        continue
                }
                 
                //设置按键约束
                keyView.snp_makeConstraints { (make) -> Void in
                    //添加高度约束
                    make.height.equalTo(keyboardView.snp_height).multipliedBy(0.2)
                     
                    //添加宽度约束
                    if key == "0" {
                        //处理 0
                        make.width.equalTo(keyboardView.snp_width).multipliedBy(0.5)
                    }else {
                        //正常的单元格
                        make.width.equalTo(keyboardView.snp_width).multipliedBy(0.25)
                    }
                     
                    //添加垂直位置约束
                    if i == 0{
                        make.top.equalTo(0)
                        keyView.backgroundColor = UIColor(red:201/255, green:202/255,
                            blue:204/255, alpha:1)
                    }else{
                        make.top.equalTo(keyViews[indexOfKeys-4].snp_bottom)
                    }
                     
                    //添加水平位置约束
                    switch (j) {
                    case 0:
                        make.left.equalTo(keyboardView.snp_left)
                    case 1:
                        make.right.equalTo(keyboardView.snp_centerX)
                    case 2:
                        make.left.equalTo(keyboardView.snp_centerX)
                    case 3:
                        make.right.equalTo(keyboardView.snp_right)
                        keyView.backgroundColor = UIColor(red:249/255, green:138/255,
                            blue:17/255, alpha:1)
                    default:
                        break
                    }
                }
            }
        }
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

源码下载:hangge_1113.zip

链接:

航哥Swift

Swift - 自动布局库SnapKit的使用详解1(配置、使用方法、样例)

仿简友动态时间轴:使用Snapkit来实现UITableViewCell的动态布局

swift约束框架SnapKit使用的更多相关文章

  1. Swift 自动布局框架-SnapKit

    官方网址:http://snapkit.io/ Github: https://github.com/SnapKit/SnapKit SnapKit is a DSL to make Auto Lay ...

  2. swift 约束 - SnapKit 适配iPhoneX 安全区 和苹果自带的VFL ,auto layout 安全区适配

    这里tableview 是从最顶上的安全区适配的, nextBtn是最下边从安全区设置的,如果是在中间的view还是原来的写法,看2 1.安全区适配适用于Vc里面, 如果是自定义的view或封装的vi ...

  3. Swift - 自动布局库SnapKit的使用详解3(约束优先级,约束做动画)

    1,约束优先级我们使用SnapKit的时候,还可以定义约束的优先级.这样当约束出现冲突的时候,优先级高的约束覆盖优先级低的约束.具体优先级可以放在约束链的结束处. (1)可以设置如下几种优先级 pri ...

  4. Swift - 自动布局库SnapKit的使用详解2(约束的更新、移除、重做)

    在之前的文章中我介绍了如何使用SnapKit的 snp_makeConstraints 方法进行各种约束的设置.但有时我们的页面并不是一直固定不变的,这就需要修改已经存在的约束.本文介绍如何更新.移除 ...

  5. Swift - 开源框架总结

    苹果官方Swift文档<The Swift Programming Language> 苹果开发者Swift文档及介绍 网友整理的Swift中文文档< Apple Swift编程语言 ...

  6. Swift - 自动布局库SnapKit的使用详解4(样例1:实现一个登录页面)

    前面的几篇文章讲解了自动布局库SnapKit的使用方法.本文通过一个完整的样例(登录页面)来演示在实际项目中如何使用SnapKit来实现自动化布局的.1,效果图如下

  7. Swift - 自动布局库SnapKit的使用详解1(配置、使用方法、样例)

    为了适应各种屏幕尺寸,iOS 6后引入了自动布局(Auto Layout)的概念,通过使用各种 Constraint(约束)来实现页面自适应弹性布局. 在 StoryBoard 中使用约束实现自动布局 ...

  8. 在oc代码中使用swift第三方框架

    swift现在使用越来越多了,一些主流的框架或者效果比较好的demo都陆陆续续使用swift写了.所以,要学会如何在oc的项目中调用swift. 这里主要借助一个桥梁文件,这个桥梁文件一般在你导入sw ...

  9. iOS - Swift Foundation 框架

    前言 框架是由许多类.方法.函数和文档按照一定的逻辑组织起来的集合,以使研发程序更容易. Foundation 框架:为所有程序开发奠定基础的框架称为 Foundation 框架. Cocoa :是指 ...

随机推荐

  1. 【代码笔记】iOS-关于UIFont的一些define

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...

  2. c中的指针

    一. 指针前奏 1. 指针的重要性 指针是C语言中非常重要的数据类型,如果你说C语言中除了指针,其他你都学得很好,那你干脆说没学过C语言. 2. 小需求 l void change(int  n)函数 ...

  3. View相关知识学习总结

    (一)LayoutInflater原理分析 LayoutInflater主要用于加载布局.通常情况下,加载布局的任务都是在Activity中调用setContentView()方法来完成的,该方法内部 ...

  4. tomcat常见错误及解决方案

    一,tomcat启动时错误 1:The JAVA_HOME environment variable is not defined This environment variable is neede ...

  5. vs出现“已经在解决方案中打开了具有该名称的项目”问题的解决方案

    经过本人测试,这种问题一般出现在装了svn的项目. 其实删除了删除sln和csproj文件中的SVN配置信息就行了 需要删除的信息 sln文件中: GlobalSection(SubversionSc ...

  6. [在线] html 转 pdf

    http://www.htm2pdf.co.uk/

  7. 软件开发与UML的关系

    今天,我们上<统一建模语言UML>.课上老师给我们讲解了软件开发与UML之间的关系:UML常用于建立软件系统的模型,适用于系统开发的不同阶段.UML的应用贯穿于系统开发的不同阶段.1.需求 ...

  8. vs.net git版本仓库使用 之解决冲突方法 原创

    vs.net git 之解决冲突方法 如果别人已经修改推送到服务器,但自已本地未进行同部更新,那么就会出现要解决冲突的提示! 具体解决方法为: ... ... 下载word离线版:vs.net_git ...

  9. CSS Sprites (CSS图像拼合技术)教程工具

    什么是CSS Sprites? “Sprite”(精灵)这个词在计算机图形学中有它独特的定义,由于游戏.视频等画质越来越高,必须有一种技术可以智能的处理材质和贴图,并且要 同时保持画面流畅.“Spri ...

  10. yii2开发后记

    h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...