Skip to content

Instantly share code, notes, and snippets.

@churabou
Last active June 26, 2019 01:57
Show Gist options
  • Save churabou/cd4f2256d7442d9b7c56f4ba32957a0f to your computer and use it in GitHub Desktop.
Save churabou/cd4f2256d7442d9b7c56f4ba32957a0f to your computer and use it in GitHub Desktop.
extension to easy code layout
extension UIView {
var layout: LayoutMaker {
return LayoutMaker(self)
}
}
protocol CGFloatConvertible {
var cgFloatValue: CGFloat { get }
}
extension Int: CGFloatConvertible {
var cgFloatValue: CGFloat {
return CGFloat(self)
}
}
extension Double: CGFloatConvertible {
var cgFloatValue: CGFloat {
return CGFloat(self)
}
}
extension Float: CGFloatConvertible {
var cgFloatValue: CGFloat {
return CGFloat(self)
}
}
extension CGFloat: CGFloatConvertible {
var cgFloatValue: CGFloat {
return CGFloat(self)
}
}
// left, right, centerX
protocol HorizontalConstraints {}
extension Int: HorizontalConstraints {}
extension CGFloat: HorizontalConstraints {}
extension UIView: HorizontalConstraints {}
extension NSLayoutXAxisAnchor: HorizontalConstraints {}
extension AnchorCalculable: HorizontalConstraints where T == NSLayoutXAxisAnchor {}
// top, bottom, centerY
protocol VerticalConstraints {}
extension Int: VerticalConstraints {}
extension CGFloat: VerticalConstraints {}
extension UIView: VerticalConstraints {}
extension NSLayoutYAxisAnchor: VerticalConstraints {}
extension AnchorCalculable: VerticalConstraints where T == NSLayoutYAxisAnchor {}
// width, height
protocol DimensionalConstraints {}
extension Int: DimensionalConstraints {}
extension CGFloat: DimensionalConstraints {}
extension UIView: DimensionalConstraints {}
extension NSLayoutDimension: DimensionalConstraints {}
extension AnchorCalculable: DimensionalConstraints where T == NSLayoutDimension {}
//LayoutAnchor + 10
final class AnchorCalculable<T> {
let target: T
let constant: CGFloat
let multiplier: CGFloat
init(target: T, constant: CGFloat = 0, multiplier: CGFloat = 1) {
self.target = target
self.constant = constant
self.multiplier = multiplier
}
}
extension NSLayoutXAxisAnchor {
static func +(lhd: NSLayoutXAxisAnchor, rhd: CGFloat) -> AnchorCalculable<NSLayoutXAxisAnchor> {
return AnchorCalculable(target: lhd, constant: rhd)
}
static func -(lhd: NSLayoutXAxisAnchor, rhd: CGFloat) -> AnchorCalculable<NSLayoutXAxisAnchor> {
return AnchorCalculable(target: lhd, constant: -rhd)
}
}
extension NSLayoutYAxisAnchor {
static func +(lhd: NSLayoutYAxisAnchor, rhd: CGFloat) -> AnchorCalculable<NSLayoutYAxisAnchor> {
return AnchorCalculable(target: lhd, constant: rhd)
}
static func -(lhd: NSLayoutYAxisAnchor, rhd: CGFloat) -> AnchorCalculable<NSLayoutYAxisAnchor> {
return AnchorCalculable(target: lhd, constant: -rhd)
}
}
extension NSLayoutDimension {
static func +(lhd: NSLayoutDimension, rhd: CGFloat) -> AnchorCalculable<NSLayoutDimension> {
return AnchorCalculable(target: lhd, constant: rhd)
}
static func -(lhd: NSLayoutDimension, rhd: CGFloat) -> AnchorCalculable<NSLayoutDimension> {
return AnchorCalculable(target: lhd, constant: -rhd)
}
static func *(lhd: NSLayoutDimension, rhd: CGFloat) -> AnchorCalculable<NSLayoutDimension> {
return AnchorCalculable(target: lhd, multiplier: rhd)
}
static func /(lhd: NSLayoutDimension, rhd: CGFloat) -> AnchorCalculable<NSLayoutDimension> {
return AnchorCalculable(target: lhd, multiplier: 1/rhd)
}
}
private extension NSLayoutConstraint {
func activate() {
isActive = true
}
}
enum LayoutTarget {
enum XAxis {
case left, right, centerX
}
enum YAxis {
case top, bottom, centerY
}
enum Dimension {
case width, height
}
}
extension UIView {
func layoutAnchor(_ target: LayoutTarget.XAxis) -> NSLayoutXAxisAnchor {
switch target {
case .left: return leftAnchor
case .right: return rightAnchor
case .centerX: return centerXAnchor
}
}
func layoutAnchor(_ target: LayoutTarget.YAxis) -> NSLayoutYAxisAnchor {
switch target {
case .top: return topAnchor
case .bottom: return bottomAnchor
case .centerY: return centerYAnchor
}
}
func layoutAnchor(_ target: LayoutTarget.Dimension) -> NSLayoutDimension {
switch target {
case .width: return widthAnchor
case .height: return heightAnchor
}
}
}
final class LayoutMaker {
private let view: UIView
init (_ view: UIView) {
self.view = view
view.translatesAutoresizingMaskIntoConstraints = false
}
func activateLayoutAnchorXAxis(_ constrain: HorizontalConstraints, target: LayoutTarget.XAxis) {
let anchor = view.layoutAnchor(target)
if let constrain = constrain as? AnchorCalculable<NSLayoutXAxisAnchor> {
anchor.constraint(equalTo: constrain.target, constant: constrain.constant).activate()
}
else if let targetAnchor = constrain as? NSLayoutXAxisAnchor {
anchor.constraint(equalTo: targetAnchor).activate()
}
else if let targetView = constrain as? UIView {
anchor.constraint(equalTo: targetView.layoutAnchor(target)).activate()
}
else if let constant = constrain as? CGFloat {
anchor.constraint(equalTo: view.superview!.layoutAnchor(target), constant: constant).activate()
}
else if let constant = constrain as? Int {
anchor.constraint(equalTo: view.superview!.layoutAnchor(target), constant: CGFloat(constant)).activate()
}
}
func activateLayoutAnchorYAxis(_ constrain: VerticalConstraints, target: LayoutTarget.YAxis) {
let anchor = view.layoutAnchor(target)
if let constrain = constrain as? AnchorCalculable<NSLayoutYAxisAnchor> {
anchor.constraint(equalTo: constrain.target, constant: constrain.constant).activate()
}
else if let targetAnchor = constrain as? NSLayoutYAxisAnchor {
anchor.constraint(equalTo: targetAnchor).activate()
}
else if let targetView = constrain as? UIView {
anchor.constraint(equalTo: targetView.layoutAnchor(target)).activate()
}
else if let constant = constrain as? CGFloat {
anchor.constraint(equalTo: view.superview!.layoutAnchor(target), constant: constant).activate()
}
else if let constant = constrain as? Int {
anchor.constraint(equalTo: view.superview!.layoutAnchor(target), constant: CGFloat(constant)).activate()
}
}
func activateLayoutAnchorDimension(_ constrain: DimensionalConstraints, target: LayoutTarget.Dimension) {
let anchor = view.layoutAnchor(target)
if let constrain = constrain as? AnchorCalculable<NSLayoutDimension> {
anchor.constraint(equalTo: constrain.target, multiplier: constrain.multiplier, constant: constrain.constant).activate()
}
else if let targetAnchor = constrain as? NSLayoutDimension {
anchor.constraint(equalTo: targetAnchor).activate()
}
else if let targetView = constrain as? UIView {
anchor.constraint(equalTo: targetView.layoutAnchor(target)).activate()
}
else if let constant = constrain as? CGFloat {
anchor.constraint(equalToConstant: constant).activate()
}
else if let constant = constrain as? Int {
anchor.constraint(equalToConstant: CGFloat(constant)).activate()
}
}
}
extension LayoutMaker {
@discardableResult
func width(_ width: DimensionalConstraints) -> LayoutMaker {
activateLayoutAnchorDimension(width, target: .width)
return self
}
@discardableResult
func height(_ height: DimensionalConstraints) -> LayoutMaker {
activateLayoutAnchorDimension(height, target: .height)
return self
}
}
extension LayoutMaker {
@discardableResult
func left(_ left: HorizontalConstraints) -> LayoutMaker {
activateLayoutAnchorXAxis(left, target: .left)
return self
}
@discardableResult
func right(_ right: HorizontalConstraints) -> LayoutMaker {
activateLayoutAnchorXAxis(right, target: .right)
return self
}
@discardableResult
func centerX(_ centerX: HorizontalConstraints) -> LayoutMaker {
activateLayoutAnchorXAxis(centerX, target: .centerX)
return self
}
}
extension LayoutMaker {
@discardableResult
func top(_ top: VerticalConstraints) -> LayoutMaker {
activateLayoutAnchorYAxis(top, target: .top)
return self
}
@discardableResult
func bottom(_ bottom: VerticalConstraints) -> LayoutMaker {
activateLayoutAnchorYAxis(bottom, target: .bottom)
return self
}
@discardableResult
func centerY(_ centerY: VerticalConstraints) -> LayoutMaker {
activateLayoutAnchorYAxis(centerY, target: .centerY)
return self
}
}
// shortcut
extension LayoutMaker {
@discardableResult
func size(_ size: DimensionalConstraints) -> LayoutMaker {
width(size); height(size);
return self
}
@discardableResult
func center(_ center: HorizontalConstraints & VerticalConstraints) -> LayoutMaker {
centerY(center); centerX(center);
return self
}
}
extension LayoutMaker {
func equalToSuperView() {
left(0); right(0); top(0); bottom(0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment