SnapKit is a tool allowing iOS developers to manipulate auto-layout constraints easily. By using SnapKit, you can create, update, remove and manage layout constraints of the UI views.
snp.makeConstraint method is used to add constraints, including: margin, width, height, left and right distance. SnapKit also supports deletion constraints, update constraints, and relative position (inset, offset) and multiple correction (multipleBy and divideBy).
SnapKit supports the following properties:
| ViewAttribute | Layout Attribute |
|---|---|
| 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 |
Without SnapKit, the code would look similar to the following:
child.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.leadingAnchor.constraint(equalTo: parent.leadingAnchor),
child.topAnchor.constraint(equalTo: parent.topAnchor),
child.trailingAnchor.constraint(equalTo: parent.trailingAnchor),
child.bottomAnchor.constraint(equalTo: parent.bottomAnchor),
])
SnapKit represents those constraints like this:
child.snp.makeConstraints { make in
make.leading.equalToSuperview()
make.top.equalToSuperview()
make.trailing.equalToSuperview()
make.bottom.equalToSuperview()
}
First of all, you need to install SnapKit via CocoaPods. Add this to your Podfile:
pod 'SnapKit'
Let’s display a UIView pinned to the four edges of its superview.
import UIKit
import SnapKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let child = UIView()
child.backgroundColor = .red
let child1 = UIView()
child1.backgroundColor = .green
self.view.addSubview(child)
self.view.addSubview(child1)
child.snp.makeConstraints { (make) in
make.edges.equalTo(self.view)
}
child1.snp.makeConstraints { (make) in
make.size.equalTo(CGSize(width: 300, height: 300))
make.top.equalTo(self.view.snp.top).offset(100)
make.centerX.equalTo(self.view)
}
}
}
Let’s try sme other things in SnapKit:
child.snp.makeConstraints { (make) in
make.size.equalTo(CGSize(width: 300, height: 300))
make.top.equalTo(self.view.snp.top).offset(100)
make.centerX.equalTo(self.view)
}
child2.snp.makeConstraints { (make) in
make.size.equalTo(child)
make.top.equalTo(child.snp.bottom).offset(50)
make.centerX.equalTo(self.view)
}
child3.snp.makeConstraints { (make) -> Void in
make.top.left.right.equalTo(0)
make.height.equalTo(self.view.snp_height).multipliedBy(0.5)
}
child4.snp.makeConstraints { (make) -> Void in
make.center.equalTo(topView.center)
make.width.equalTo(100)
make.height.equalTo(110)
}
child5.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(16)
//make.edges.equalTo(child2).inset(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))
}
child6.snp.makeConstraints { make in
make.leading.trailing.equalTo(view.safeAreaLayoutGuide)
}
child7.snp.makeConstraints { make in
make.leading.trailing.equalTo(child6)
make.top.equalTo(child6.snp.bottom).offset(16)
make.height.equalTo(80)
}
Aspect ratio
view.snp.makeConstraints { make in
make.width.equalTo(view.snp.height).multipliedBy(1.0 / 1.0)
}
UITableView example
import UIKit
import SnapKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
lazy var tbl: UITableView = {
let v = UITableView()
v.rowHeight = 100
v.separatorStyle = .none
return v
}()
var items: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
items.append(contentsOf: (1...20).map { index in "Item \(index)"})
setupUI()
}
func setupUI() {
tbl.delegate = self
tbl.dataSource = self
tbl.register(CustomCell.self, forCellReuseIdentifier: CustomCell.cellId)
self.view.addSubview(tbl)
tbl.snp.makeConstraints { (make) in
make.edges.equalTo(self.view.safeAreaLayoutGuide)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.cellId, for: indexPath) as! CustomCell
cell.lblTitle.text = items[indexPath.row]
return cell
}
}
class CustomCell: UITableViewCell {
static var cellId = "cell"
let lblTitle: UILabel = {
let v = UILabel()
v.backgroundColor = .systemGreen
v.textColor = .white
v.textAlignment = .center
v.layer.cornerRadius = 5
v.layer.masksToBounds = true
return v
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupUI() {
self.addSubview(lblTitle)
lblTitle.snp.makeConstraints { (make) in
make.top.left.equalTo(20)
make.right.bottom.equalTo(-20)
}
}
}