Swift 纯代码布局框架 SnapKit 入门教程

进行iOS UI开发的时候,主要的布局方式有xib、storyboard和纯代码布局。storyboard布局有个致命的问题就是,如果多人同时进行开发很容易出现代码冲突问题,而且容易变动的布局也不好处理;纯代码布局,苹果为我们提供的适配框架有:VFL、UIViewAutoresizing、Auto Layout、Size Classes等,除以之外,也有很多第三方开源的布局,比如MasonrySnapKitSDAutoLayoutCartographyPureLayoutNeon

SnapKit

每个框架都有自己的特点,开发者可以根据自己的喜欢选择,笔者是使用Swift编写,选择了最多人选择的布局框架SnapKit进行开发,选择SnapKit主要有几个原因,第一是最多人使用,二是还是维护更新,三是语法简单。

cocoapods 依赖
    pod 'SnapKit', '~> 5.0.0'
居中显示

下面的案例是创建一个box的View,设置宽高为100,在父View中居中显示。

import UIKit
import SnapKit
class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box = UIView()
        box.backgroundColor = UIColor.blue
        self.view.addSubview(box)
        box.snp.makeConstraints { (make) in
            // 宽高设置为100
            make.size.equalTo(100)
            // 在父视图居中显示
            make.center.equalToSuperview()
        }
    }
}

dividedBy、multipliedBy

dividedBy、multipliedBy两者的用法都是一样的,dividedBy(x)是除以x,multipliedBy(x)是乘以x。

class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box = UIView()
        box.backgroundColor = UIColor.blue
        self.view.addSubview(box)
        box.snp.makeConstraints { (make) in
            // 在父视图居中显示
            make.center.equalToSuperview()
            // 宽度等于父视图宽度的1/2
            make.width.equalToSuperview().dividedBy(2)
            // 高度等于父视图高度的0.25
            make.height.equalToSuperview().multipliedBy(0.25)
        }
    }
}
offset (偏移量,位移)
class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box = UIView()
        box.backgroundColor = UIColor.blue
        self.view.addSubview(box)
        box.snp.makeConstraints { (make) in
            // 距离父视图上边50dp
            make.top.equalToSuperview().offset(100)
            // 距离父视图左边50dp
            make.left.equalToSuperview().offset(50)
            // 距离父视图下边50dp
            make.bottom.equalToSuperview().offset(-100)
            // 距离父视图右边50dp
            make.right.equalToSuperview().offset(-50)
            // 更加简单的写法,下面一行代码的效果和上面4行代码一样
            // make.edges.equalToSuperview().inset(UIEdgeInsets(top: 100,left: 50,bottom: 100,right: 50))
        }
    }
}
topLayoutGuide、bottomLayoutGuide、safeAreaLayoutGuide

topLayoutGuide、bottomLayoutGuide在iOS 11.0 被弃用了,但是这里还是介绍一下这两者的用法,之所以被废弃是因为iPhone X之后推出的SafeArea概念,所以建议使用 safeAreaLayoutGuide。

class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box1 = UIView()
        box1.backgroundColor = UIColor.blue
        self.view.addSubview(box1)
        box1.snp.makeConstraints { (make) in
            make.size.equalTo(100)
        }
        
        let box2 = UIView()
        box2.backgroundColor = UIColor.red
        self.view.addSubview(box2)
        box2.snp.makeConstraints { (make) in
            make.size.equalTo(100)
            make.right.equalToSuperview().offset(0)
            // bottomLayoutGuide 已经被弃用
            // make.top.equalTo(topLayoutGuide.snp.bottom)
            // 建议使用 safeAreaLayoutGuide
            make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top)
            
        }
        
        let box3 = UIView()
        box3.backgroundColor = UIColor.yellow
        self.view.addSubview(box3)
        box3.snp.makeConstraints { (make) in
            make.size.equalTo(100)
            make.bottom.equalToSuperview().offset(0)
        }

        let box4 = UIView()
        box4.backgroundColor = UIColor.black
        self.view.addSubview(box4)
        box4.snp.makeConstraints { (make) in
            make.size.equalTo(100)
            make.right.equalToSuperview().offset(0)
            // bottomLayoutGuide 已经被弃用
            // make.bottom.equalTo(bottomLayoutGuide.snp.top)
            // 建议使用 safeAreaLayoutGuide
            make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
        }
    }
}
priority 优先级用法

SnapKit一共提供了4种优先级,优先级顺序是:required > high > medium > low。

class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box1 = UIView()
        box1.backgroundColor = UIColor.blue
        self.view.addSubview(box1)
        box1.snp.makeConstraints { (make) in
            // 父视图居中的优先级是medium,距离父视图右边10的优先级是high,距离父视图上边10的优先级是low,所以运行的结果是“垂直居中,距离父视图右边10”
            make.center.equalToSuperview().priority(.medium)
            make.right.equalToSuperview().offset(10).priority(.high)
            make.top.equalToSuperview().offset(10).priority(.low)
            // 运行结果是宽高等于100
            make.size.equalTo(100).priority(.medium)
            make.size.equalTo(200).priority(.low)
        }
    }
}
image.png
equalTo、lessThanOrEqualTo、greaterThanOrEqualTo

配合priority可以实现一些特别的效果。

  • equalTo 是等于
  • lessThanOrEqualTo 小于或等于
  • greaterThanOrEqualTo 大于或等于
    效果一
class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box1 = UIView()
        box1.backgroundColor = UIColor.blue
        self.view.addSubview(box1)
        
        let box2 = UIView()
        box2.backgroundColor = UIColor.red
        self.view.addSubview(box2)
        
        box1.snp.makeConstraints { (make) in
            make.left.equalToSuperview().offset(0)
            make.size.equalTo(100).priority(.high)
            // box1的宽高大于或等于box2宽高
            make.size.greaterThanOrEqualTo(box2).priority(.high)
        }
        box2.snp.makeConstraints { (make) in
            make.right.equalToSuperview().offset(0)
            make.size.equalTo(200).priority(.low)
        }
        let label = UILabel()
        label.text = "效果一"
        self.view.addSubview(label)
        label.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }
    }
}

效果二

class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box1 = UIView()
        box1.backgroundColor = UIColor.blue
        self.view.addSubview(box1)
        
        let box2 = UIView()
        box2.backgroundColor = UIColor.red
        self.view.addSubview(box2)
        
        box1.snp.makeConstraints { (make) in
            make.left.equalToSuperview().offset(0)
            make.size.equalTo(100).priority(.low)
            // box1的宽高大于或等于box2宽高
            make.size.greaterThanOrEqualTo(box2).priority(.high)
        }
        box2.snp.makeConstraints { (make) in
            make.right.equalToSuperview().offset(0)
            make.size.equalTo(200).priority(.high)
        }
        let label = UILabel()
        label.text = "效果二"
        self.view.addSubview(label)
        label.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }
    }
}

效果三

class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let box1 = UIView()
        box1.backgroundColor = UIColor.blue
        self.view.addSubview(box1)
        
        let box2 = UIView()
        box2.backgroundColor = UIColor.red
        self.view.addSubview(box2)
        
        box1.snp.makeConstraints { (make) in
            make.left.equalToSuperview().offset(0)
            make.size.equalTo(100).priority(.high)
            // box1的宽高大于或等于box2宽高
            make.size.greaterThanOrEqualTo(box2).priority(.low)
        }
        box2.snp.makeConstraints { (make) in
            make.right.equalToSuperview().offset(0)
            make.size.equalTo(200).priority(.high)
        }
        let label = UILabel()
        label.text = "效果三"
        self.view.addSubview(label)
        label.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }
    }
}
总结

从上述的例子可以看到,使用SnapKit框架进行纯代码布局还是非常的简单,而且SnapKit还一直在维护更新,非常推荐使用,基于以上的简单的API就可以完成非常复杂的UI布局。

推荐阅读更多精彩内容

  • 前言 在上篇文章中,我们初步学习了SnapKit的基础使用方法,文章:Swift自动布局SnapKit的详细使用介...
    langkee阅读 42,346评论 20 82
  • (转载于http://www.hangge.com/blog/cache/detail_1097.html) Sw...
    6309b0eed1c7阅读 2,173评论 7 2
  • 简介 SnapKit,一个经典的Swift版的第三方库,专门用于项目的自动布局,目前在github上的stars就...
    so_what阅读 3,709评论 7 13
  • (一)Masonry介绍 Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布...
    杨梦鸽阅读 1,767评论 0 3
  • Masonry是一个轻量级的布局框架,拥有自己的描述语法,采用更优雅的链式语法封装自动布局,简洁明了并具有高可读性...
    3dcc6cf93bb5阅读 1,264评论 0 1
  • 好久没有看朋友圈。今天懒懒打开,吓一大跳,满满的都是营养。 其间最正能量的一位女士,发了一篇直指心灵深处的...
    b83499040de0阅读 263评论 0 1
  • kali linux下nmap常用参数翻译记录: 主机扫描: -iL 做成ip地址列表文件 -iR 随机选择目标扫...
    doctordc阅读 1,400评论 0 2
  • 家长会的预请 大宝,昨天晚上你给我打电话,问我本周的家长会谁会参加?我说我会去,你说正想要我去。为什么呢?因为那天...
    顺遂自心阅读 290评论 1 3
  • 今天这科目三 问题——离合:起步抬离合慢抬,先抬一半,车跑起来了,再匀速抬起剩下的。所有挂档都要慢慢抬离合,不能过...
    ppppb423阅读 62评论 0 0