Created
December 11, 2015 00:20
-
-
Save pcperini/efec6c717ec0a6dc2579 to your computer and use it in GitHub Desktop.
don't try this at home, kids
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// LayoutConstraint.swift | |
// LayoutConstraints | |
// | |
// Created by PATRICK PERINI on 12/10/15. | |
// Copyright © 2015 atomic. All rights reserved. | |
// | |
import UIKit | |
public struct LayoutConstraint { | |
// MARK: Properties | |
let relation: NSLayoutRelation? | |
let multiplier: CGFloat? | |
let constant: CGFloat? | |
let firstView: UIView? | |
let firstAttribute: NSLayoutAttribute? | |
let secondView: UIView? | |
let secondAttribute: NSLayoutAttribute? | |
var layoutConstraint: NSLayoutConstraint? { | |
guard let firstView = self.firstView else { return nil } | |
return NSLayoutConstraint(item: firstView, | |
attribute: self.firstAttribute ?? .NotAnAttribute, | |
relatedBy: self.relation ?? .Equal, | |
toItem: self.secondView, | |
attribute: self.secondAttribute ?? .NotAnAttribute, | |
multiplier: self.multiplier ?? 1.0, | |
constant: self.constant ?? 0.0) | |
} | |
} | |
extension NSLayoutConstraint { | |
// MARK: Properties | |
var constraint: LayoutConstraint { | |
return LayoutConstraint(relation: self.relation, | |
multiplier: self.multiplier, | |
constant: self.constant, | |
firstView: self.firstItem as? UIView, | |
firstAttribute: self.firstAttribute, | |
secondView: self.secondItem as? UIView, | |
secondAttribute: self.secondAttribute) | |
} | |
} | |
// MARK: Conversion | |
extension LayoutConstraint: FloatLiteralConvertible { | |
// MARK: Initializers | |
public init(floatLiteral value: FloatLiteralType) { | |
self.relation = nil | |
self.multiplier = nil | |
self.constant = CGFloat(value) | |
self.firstView = nil | |
self.firstAttribute = nil | |
self.secondView = nil | |
self.secondAttribute = .NotAnAttribute | |
} | |
} | |
// MARK: Operators | |
func *(lhs: CGFloat, rhs: LayoutConstraint) -> LayoutConstraint { | |
return LayoutConstraint(relation: rhs.relation, | |
multiplier: lhs, | |
constant: rhs.constant, | |
firstView: rhs.firstView, | |
firstAttribute: rhs.firstAttribute, | |
secondView: rhs.secondView, | |
secondAttribute: rhs.secondAttribute) | |
} | |
func +(lhs: LayoutConstraint, rhs: CGFloat) -> LayoutConstraint { | |
return LayoutConstraint(relation: lhs.relation, | |
multiplier: lhs.multiplier, | |
constant: rhs, | |
firstView: lhs.firstView, | |
firstAttribute: lhs.firstAttribute, | |
secondView: lhs.secondView, | |
secondAttribute: lhs.secondAttribute) | |
} | |
func -(lhs: LayoutConstraint, rhs: CGFloat) -> LayoutConstraint { | |
return LayoutConstraint(relation: lhs.relation, | |
multiplier: lhs.multiplier, | |
constant: -rhs, | |
firstView: lhs.firstView, | |
firstAttribute: lhs.firstAttribute, | |
secondView: lhs.secondView, | |
secondAttribute: lhs.secondAttribute) | |
} | |
prefix operator >= {} | |
prefix func >=(rhs: LayoutConstraint) -> LayoutConstraint { | |
return LayoutConstraint(relation: .GreaterThanOrEqual, | |
multiplier: rhs.multiplier, | |
constant: rhs.constant, | |
firstView: rhs.firstView, | |
firstAttribute: rhs.firstAttribute, | |
secondView: rhs.secondView, | |
secondAttribute: rhs.secondAttribute) | |
} | |
prefix operator <= {} | |
prefix func <=(rhs: LayoutConstraint) -> LayoutConstraint { | |
return LayoutConstraint(relation: .LessThanOrEqual, | |
multiplier: rhs.multiplier, | |
constant: rhs.constant, | |
firstView: rhs.firstView, | |
firstAttribute: rhs.firstAttribute, | |
secondView: rhs.secondView, | |
secondAttribute: rhs.secondAttribute) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UIView+LayoutConstraint.swift | |
// LayoutConstraints | |
// | |
// Created by PATRICK PERINI on 12/4/15. | |
// Copyright © 2015 atomic. All rights reserved. | |
// | |
import UIKit | |
extension UIView { | |
// MARK: Properties | |
// ... Center / Size | |
var centerX: LayoutConstraint { | |
get { return self.constraint(attribute: .CenterX) } | |
set { self.addConstraint(constraint: newValue, attribute: .CenterX) } | |
} | |
var centerY: LayoutConstraint { | |
get { return self.constraint(attribute: .CenterY) } | |
set { self.addConstraint(constraint: newValue, attribute: .CenterY) } | |
} | |
var width: LayoutConstraint { | |
get { return self.constraint(attribute: .Width) } | |
set { self.addConstraint(constraint: newValue, attribute: .Width) } | |
} | |
var height: LayoutConstraint { | |
get { return self.constraint(attribute: .Height) } | |
set { self.addConstraint(constraint: newValue, attribute: .Height) } | |
} | |
// ... Edges | |
var left: LayoutConstraint { | |
get { return self.constraint(attribute: .Left) } | |
set { self.addConstraint(constraint: newValue, attribute: .Left) } | |
} | |
var right: LayoutConstraint { | |
get { return self.constraint(attribute: .Right) } | |
set { self.addConstraint(constraint: newValue, attribute: .Right) } | |
} | |
var top: LayoutConstraint { | |
get { return self.constraint(attribute: .Top) } | |
set { self.addConstraint(constraint: newValue, attribute: .Top) } | |
} | |
var bottom: LayoutConstraint { | |
get { return self.constraint(attribute: .Bottom) } | |
set { self.addConstraint(constraint: newValue, attribute: .Bottom) } | |
} | |
} | |
extension UIView { | |
// MARK: Accessors | |
private func constraint(attribute attribute: NSLayoutAttribute) -> LayoutConstraint { | |
return LayoutConstraint(relation: nil, | |
multiplier: nil, | |
constant: nil, | |
firstView: self, | |
firstAttribute: attribute, | |
secondView: nil, | |
secondAttribute: nil) | |
} | |
private func layoutConstraintForAttribute(attribute: NSLayoutAttribute) -> NSLayoutConstraint? { | |
return (self.constraints + (self.superview?.constraints ?? [])).filter { (possibleConstraint: NSLayoutConstraint) in | |
return ((possibleConstraint.firstItem === self && possibleConstraint.firstAttribute == attribute) || | |
(possibleConstraint.secondItem === self && possibleConstraint.secondAttribute == attribute)) | |
}.first | |
} | |
// MARK: Mutators | |
private func addConstraint(constraint constraint: LayoutConstraint, attribute: NSLayoutAttribute) { | |
let targetView = constraint.firstView ?? self | |
targetView.removeConstraint(constraint: constraint, toView: self, attribute: attribute) | |
guard let layoutConstraint = LayoutConstraint(relation: constraint.relation, | |
multiplier: constraint.multiplier, | |
constant: constraint.constant, | |
firstView: self, | |
firstAttribute: attribute, | |
secondView: constraint.firstView, | |
secondAttribute: constraint.firstAttribute).layoutConstraint else { return } | |
targetView.addConstraint(layoutConstraint) | |
} | |
private func removeConstraint(constraint constraint: LayoutConstraint, toView view: UIView, attribute: NSLayoutAttribute) { | |
guard let layoutConstraint = self.constraints.filter({ (possibleConstraint: NSLayoutConstraint) in | |
return ((possibleConstraint.firstItem === view || possibleConstraint.secondItem === view) && | |
(possibleConstraint.firstAttribute == attribute) && | |
(possibleConstraint.secondAttribute == constraint.firstAttribute ?? NSLayoutAttribute(rawValue: 0))) | |
}).first else { return } | |
self.removeConstraint(layoutConstraint) | |
} | |
} | |
// MARK: Operators | |
func +=(lhs: LayoutConstraint, rhs: CGFloat) { | |
guard let layoutConstraint = lhs.firstView?.layoutConstraintForAttribute(lhs.firstAttribute ?? .NotAnAttribute) else { return } | |
layoutConstraint.constant += rhs | |
} | |
func -=(lhs: LayoutConstraint, rhs: CGFloat) { | |
guard let layoutConstraint = lhs.firstView?.layoutConstraintForAttribute(lhs.firstAttribute ?? .NotAnAttribute) else { return } | |
layoutConstraint.constant += rhs | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ViewController.swift | |
// LayoutConstraints | |
// | |
// Created by PATRICK PERINI on 12/4/15. | |
// Copyright © 2015 atomic. All rights reserved. | |
// | |
import UIKit | |
class ViewController: UIViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
let childView = UIView() | |
self.view.addSubview(childView) | |
childView.backgroundColor = UIColor.redColor() | |
self.view.translatesAutoresizingMaskIntoConstraints = false | |
childView.translatesAutoresizingMaskIntoConstraints = false | |
childView.height = 0.5 * self.view.height - 5.0 | |
childView.width = 100.5 | |
childView.left = self.view.left + 50.0 | |
self.view.layoutIfNeeded() | |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2) * Int64(NSEC_PER_SEC)), dispatch_get_main_queue()) { | |
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions(), animations: { | |
childView.left += 100.0 | |
childView.height = self.view.height - 50.0 | |
self.view.layoutIfNeeded() | |
}, completion: nil) | |
} | |
// Do any additional setup after loading the view, typically from a nib. | |
} | |
override func didReceiveMemoryWarning() { | |
super.didReceiveMemoryWarning() | |
// Dispose of any resources that can be recreated. | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment