Skip to content

Instantly share code, notes, and snippets.

@Austinate
Forked from floriankugler/AutoLayoutHelpers.swift
Last active January 20, 2022 16:43
Show Gist options
  • Save Austinate/396b523192b6c22eb5db0664ca97858c to your computer and use it in GitHub Desktop.
Save Austinate/396b523192b6c22eb5db0664ca97858c to your computer and use it in GitHub Desktop.
Very simple key path based Auto Layout helpers
import UIKit
typealias ConstraintBuilder = (_ child: UIView, _ parent: UIView) -> NSLayoutConstraint
extension UIView {
func addSubview(_ child: UIView, constraints: [ConstraintBuilder]) {
addSubview(child)
child.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(constraints.map { $0(child, self) })
}
@discardableResult
func attach<Axis, Anchor>(_ keyPath: KeyPath<UIView, Anchor>,
to: KeyPath<UIView, Anchor>,
of secondView: UIView,
constant: CGFloat = 0,
relation: NSLayoutConstraint.Relation) -> NSLayoutConstraint where Anchor: NSLayoutAnchor<Axis> {
let builder = attach(keyPath, to, constant: constant, relation: relation)
let constraint = builder(self, secondView)
constraint.isActive = true
return constraint
}
}
func attach<Axis, Anchor>(_ keyPath: KeyPath<UIView, Anchor>,
_ to: KeyPath<UIView, Anchor>,
constant: CGFloat = 0,
relation: NSLayoutConstraint.Relation) -> ConstraintBuilder where Anchor: NSLayoutAnchor<Axis> {
return { view, parent in
switch relation {
case .equal:
return view[keyPath: keyPath].constraint(equalTo: parent[keyPath: to], constant: constant)
case .greaterThanOrEqual:
return view[keyPath: keyPath].constraint(greaterThanOrEqualTo: parent[keyPath: to], constant: constant)
case .lessThanOrEqual:
return view[keyPath: keyPath].constraint(lessThanOrEqualTo: parent[keyPath: to], constant: constant)
@unknown default:
fatalError("Unexpected NSLayoutConstraint.Relation case: \(relation)")
}
}
}
func attach<Axis, Anchor>(_ keyPath: KeyPath<UIView, Anchor>,
constant: CGFloat = 0,
relation: NSLayoutConstraint.Relation) -> ConstraintBuilder where Anchor: NSLayoutAnchor<Axis> {
return attach(keyPath, keyPath, constant: constant, relation: relation)
}
func attach<Anchor>(_ keyPath: KeyPath<UIView, Anchor>,
constant: CGFloat,
relation: NSLayoutConstraint.Relation) -> ConstraintBuilder where Anchor: NSLayoutDimension {
return { view1, _ in
switch relation {
case .equal:
return view1[keyPath: keyPath].constraint(equalToConstant: constant)
case .lessThanOrEqual:
return view1[keyPath: keyPath].constraint(lessThanOrEqualToConstant: constant)
case .greaterThanOrEqual:
return view1[keyPath: keyPath].constraint(greaterThanOrEqualToConstant: constant)
@unknown default:
fatalError("Unexpected NSLayoutConstraint.Relation case: \(relation)")
}
}
}
let v1 = UIView()
v1.backgroundColor = .red
v1.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
let v2 = UIView()
v2.backgroundColor = .green
v1.addSubview(v2, constraints: [
attach(\.leadingAnchor, constant: 10, relation: .equal),
attach(\.trailingAnchor, constant: -10, relation: .equal),
attach(\.heightAnchor, constant: 100, relation: .equal)
])
v2.attach(\.topAnchor, to: \.bottomAnchor, of: v1, relation: .equal)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment