Commit f1a9a86f authored by Aral Balkan's avatar Aral Balkan

Added the Cartography auto layout library. Cleaned up the Preloader View...

Added the Cartography auto layout library. Cleaned up the Preloader View Controller and implemented our new constraint workflow.
parent 41e527bc
This diff is collapsed.
//
// Align.swift
// Cartography
//
// Created by Robert Böhnke on 17/02/15.
// Copyright (c) 2015 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
private func makeEqual<P: RelativeEquality>(attribute: LayoutProxy -> P, first: LayoutProxy, rest: [LayoutProxy]) -> [NSLayoutConstraint] {
return reduce(rest, []) { acc, current in
current.view.car_translatesAutoresizingMaskIntoConstraints = false
return acc + [ attribute(first) == attribute(current) ]
}
}
/// Aligns multiple views by their top edge.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(top first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.top }, first, rest)
}
/// Aligns multiple views by their right edge.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(right first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.right }, first, rest)
}
/// Aligns multiple views by their bottom edge.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(bottom first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.bottom }, first, rest)
}
/// Aligns multiple views by their left edge.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(left first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.left }, first, rest)
}
/// Aligns multiple views by their leading edge.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(leading first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.leading }, first, rest)
}
/// Aligns multiple vies by their trailing edge.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(trailing first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.trailing }, first, rest)
}
/// Aligns multiple views by their horizontal center.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(centerX first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.centerX }, first, rest)
}
/// Aligns multiple views by their vertical center.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(centerY first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.centerY }, first, rest)
}
/// Aligns multiple views by their baseline.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func align(baseline first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return makeEqual({ $0.baseline }, first, rest)
}
......@@ -2006,11 +2006,11 @@ DQ
<scene sceneID="Jkk-vZ-1R0">
<objects>
<viewController id="bSS-56-VyP" customClass="PreloaderViewController" customModule="Heartbeat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="vzj-Mr-Umj">
<view key="view" identifier="PreloaderView" id="vzj-Mr-Umj">
<rect key="frame" x="0.0" y="0.0" width="512" height="512"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KDX-tU-frE">
<imageView identifier="BalloonImageView" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KDX-tU-frE">
<rect key="frame" x="0.0" y="0.0" width="512" height="512"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="balloon_512x512" id="nZK-wB-TTL">
<accessibility description="Load complete"/>
......@@ -2019,6 +2019,7 @@ DQ
</subviews>
</view>
<connections>
<outlet property="balloonImageView" destination="KDX-tU-frE" id="MY3-8c-PgH"/>
<outlet property="balloonView" destination="KDX-tU-frE" id="L1y-0P-hwd"/>
</connections>
</viewController>
......
//
// Cartography.h
// Cartography
//
// Created by Robert Böhnke on 17/06/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
#import <TargetConditionals.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif
//! Project version number for Cartography.
FOUNDATION_EXPORT double CartographyVersionNumber;
//! Project version string for Cartography.
FOUNDATION_EXPORT const unsigned char CartographyVersionString[];
//
// Coefficients.swift
// Cartography
//
// Created by Robert Böhnke on 17/06/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
import Foundation
public struct Coefficients {
var multiplier: Double = 1
var constant: Double = 0
init() { }
init(_ multiplier: Double, _ constant: Double) {
self.constant = constant
self.multiplier = multiplier
}
init(_ multiplier: Number, _ constant: Number) {
self.constant = constant.doubleValue
self.multiplier = multiplier.doubleValue
}
}
// MARK: Addition
public func + (c: Number, rhs: Coefficients) -> Coefficients {
return Coefficients(rhs.multiplier, rhs.constant + c.doubleValue)
}
public func + (lhs: Coefficients, rhs: Number) -> Coefficients {
return rhs + lhs
}
// MARK: Subtraction
public func - (c: Number, rhs: Coefficients) -> Coefficients {
return Coefficients(rhs.multiplier, rhs.constant - c.doubleValue)
}
public func - (lhs: Coefficients, rhs: Number) -> Coefficients {
return rhs - lhs
}
// MARK: Multiplication
public func * (m: Number, rhs: Coefficients) -> Coefficients {
return Coefficients(rhs.multiplier * m.doubleValue, rhs.constant * m.doubleValue)
}
public func * (lhs: Coefficients, rhs: Number) -> Coefficients {
return rhs * lhs
}
// MARK: Division
public func / (m: Number, rhs: Coefficients) -> Coefficients {
return Coefficients(rhs.multiplier / m.doubleValue, rhs.constant / m.doubleValue)
}
public func / (lhs: Coefficients, rhs: Number) -> Coefficients {
return rhs / lhs
}
//
// Compound.swift
// Cartography
//
// Created by Robert Böhnke on 18/06/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
public protocol Compound {
var context: Context { get }
var properties: [Property] { get }
}
/// Compound properties conforming to this protocol can use the `==` operator
/// with other compound properties of the same type.
public protocol RelativeCompoundEquality : Compound { }
/// Declares a property equal to a the result of an expression.
///
/// :param: lhs The affected property. The associated view will have
/// `translatesAutoresizingMaskIntoConstraints` set to `false`.
/// :param: rhs The expression.
///
/// :returns: An `NSLayoutConstraint`.
///
public func == <P: RelativeCompoundEquality>(lhs: P, rhs: Expression<P>) -> [NSLayoutConstraint] {
return lhs.context.addConstraint(lhs, coefficients: rhs.coefficients, to: rhs.value)
}
/// Declares a property equal to another compound property.
///
/// :param: lhs The affected property. The associated view will have
/// `translatesAutoresizingMaskIntoConstraints` set to `false`.
/// :param: rhs The other property.
///
public func == <P: RelativeCompoundEquality>(lhs: P, rhs: P) -> [NSLayoutConstraint] {
return lhs.context.addConstraint(lhs, to: rhs)
}
/// Compound properties conforming to this protocol can use the `<=` and `>=`
/// operators with other compound properties of the same type.
public protocol RelativeCompoundInequality : Compound { }
/// Declares a property less than or equal to another compound property.
///
/// :param: lhs The affected property. The associated view will have
/// `translatesAutoresizingMaskIntoConstraints` set to `false`.
/// :param: rhs The other property.
///
/// :returns: An `NSLayoutConstraint`.
///
public func <= <P: RelativeCompoundInequality>(lhs: P, rhs: P) -> [NSLayoutConstraint] {
return lhs.context.addConstraint(lhs, to: rhs, relation: NSLayoutRelation.LessThanOrEqual)
}
/// Declares a property greater than or equal to another compound property.
///
/// :param: lhs The affected property. The associated view will have
/// `translatesAutoresizingMaskIntoConstraints` set to `false`.
/// :param: rhs The other property.
///
/// :returns: An `NSLayoutConstraint`.
///
public func >= <P: RelativeCompoundInequality>(lhs: P, rhs: P) -> [NSLayoutConstraint] {
return lhs.context.addConstraint(lhs, to: rhs, relation: NSLayoutRelation.GreaterThanOrEqual)
}
/// Declares a property less than or equal to the result of an expression.
///
/// :param: lhs The affected property. The associated view will have
/// `translatesAutoresizingMaskIntoConstraints` set to `false`.
/// :param: rhs The other property.
///
/// :returns: An `NSLayoutConstraint`.
///
public func <= <P: RelativeCompoundInequality>(lhs: P, rhs: Expression<P>) -> [NSLayoutConstraint] {
return lhs.context.addConstraint(lhs, coefficients: rhs.coefficients, to: rhs.value, relation: NSLayoutRelation.LessThanOrEqual)
}
/// Declares a property greater than or equal to the result of an expression.
///
/// :param: lhs The affected property. The associated view will have
/// `translatesAutoresizingMaskIntoConstraints` set to `false`.
/// :param: rhs The other property.
///
/// :returns: An `NSLayoutConstraint`.
///
public func >= <P: RelativeCompoundInequality>(lhs: P, rhs: Expression<P>) -> [NSLayoutConstraint] {
return lhs.context.addConstraint(lhs, coefficients: rhs.coefficients, to: rhs.value, relation: NSLayoutRelation.GreaterThanOrEqual)
}
//
// Constraint.swift
// Cartography
//
// Created by Robert Böhnke on 06/10/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
@objc
internal class Constraint {
// Set to weak to avoid a retain cycle on the associated view.
weak var view: View?
let layoutConstraint: NSLayoutConstraint
func install() {
view?.addConstraint(layoutConstraint)
}
func uninstall() {
view?.removeConstraint(layoutConstraint)
}
init(view: View, layoutConstraint: NSLayoutConstraint) {
self.view = view
self.layoutConstraint = layoutConstraint
}
}
//
// ConstraintGroup.swift
// Cartography
//
// Created by Robert Böhnke on 22/01/15.
// Copyright (c) 2015 Robert Böhnke. All rights reserved.
//
import Foundation
public class ConstraintGroup {
private var constraints: [Constraint] = []
@availability(OSX, introduced=10.10)
@availability(iOS, introduced=8.0)
public var active: Bool {
get {
return constraints.map({ $0.layoutConstraint.active }).reduce(true) { $0 && $1 }
}
set {
for constraint in constraints {
constraint.layoutConstraint.active = newValue
}
for constraint in constraints {
constraint.view?.car_updateLayout()
}
}
}
public init() {
}
internal func replaceConstraints(constraints: [Constraint], performLayout: Bool) {
for constraint in self.constraints {
constraint.uninstall()
if performLayout {
constraint.view?.car_updateLayout()
}
}
if performLayout {
for view in self.constraints.map({ $0.view }) {
view?.car_updateLayout()
}
}
self.constraints = constraints
for constraint in self.constraints {
constraint.install()
}
if performLayout {
for view in self.constraints.map({ $0.view }) {
view?.car_updateLayout()
}
}
}
}
//
// Context.swift
// Cartography
//
// Created by Robert Böhnke on 06/10/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
public class Context {
internal var constraints: [Constraint] = []
internal func addConstraint(from: Property, to: Property? = nil, coefficients: Coefficients = Coefficients(), relation: NSLayoutRelation = .Equal) -> NSLayoutConstraint {
from.view.car_translatesAutoresizingMaskIntoConstraints = false
let layoutConstraint = NSLayoutConstraint(item: from.view,
attribute: from.attribute,
relatedBy: relation,
toItem: to?.view,
attribute: to?.attribute ?? .NotAnAttribute,
multiplier: CGFloat(coefficients.multiplier),
constant: CGFloat(coefficients.constant))
if let to = to {
if let common = closestCommonAncestor(from.view, to.view ) {
constraints.append(Constraint(view: common, layoutConstraint: layoutConstraint))
} else {
fatalError("No common superview found between \(from.view) and \(to.view)")
}
} else {
constraints.append(Constraint(view: from.view, layoutConstraint: layoutConstraint))
}
return layoutConstraint
}
internal func addConstraint(from: Compound, coefficients: [Coefficients]? = nil, to: Compound? = nil, relation: NSLayoutRelation = NSLayoutRelation.Equal) -> [NSLayoutConstraint] {
var results: [NSLayoutConstraint] = []
for i in 0..<from.properties.count {
let n: Coefficients = coefficients?[i] ?? Coefficients()
results.append(addConstraint(from.properties[i], coefficients: n, to: to?.properties[i], relation: relation))
}
return results
}
}
//
// Dimension.swift
// Cartography
//
// Created by Robert Böhnke on 17/06/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
public struct Dimension : Property, NumericalEquality, RelativeEquality, NumericalInequality, RelativeInequality, Addition, Multiplication {
public let attribute: NSLayoutAttribute
public let context: Context
public let view: View
internal init(_ context: Context, _ view: View, _ attribute: NSLayoutAttribute) {
self.attribute = attribute
self.context = context
self.view = view
}
}
//
// Distribute.swift
// Cartography
//
// Created by Robert Böhnke on 17/02/15.
// Copyright (c) 2015 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
typealias Accumulator = ([NSLayoutConstraint], LayoutProxy)
private func reduce(first: LayoutProxy, rest: [LayoutProxy], combine: (LayoutProxy, LayoutProxy) -> NSLayoutConstraint) -> [NSLayoutConstraint] {
rest.last?.view.car_translatesAutoresizingMaskIntoConstraints = false
return reduce(rest, ([], first)) { (acc, current) -> Accumulator in
var (constraints, previous) = acc
return (constraints + [ combine(previous, current) ], current)
}.0
}
/// Distributes multiple views horizontally.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :param: amount The distance between the views.
/// :param: views The views to distribute.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func distribute(by amount: Double, horizontally first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return reduce(first, rest) { $0.trailing == $1.leading - amount }
}
/// Distributes multiple views horizontally from left to right.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :param: amount The distance between the views.
/// :param: views The views to distribute.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func distribute(by amount: Double, leftToRight first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return reduce(first, rest) { $0.right == $1.left - amount }
}
/// Distributes multiple views vertically.
///
/// All views passed to this function will have
/// their `translatesAutoresizingMaskIntoConstraints` properties set to `false`.
///
/// :param: amount The distance between the views.
/// :param: views The views to distribute.
///
/// :returns: An array of `NSLayoutConstraint` instances.
///
public func distribute(by amount: Double, vertically first: LayoutProxy, rest: LayoutProxy...) -> [NSLayoutConstraint] {
return reduce(first, rest) { $0.bottom == $1.top - amount }
}
//
// Edge.swift
// Cartography
//
// Created by Robert Böhnke on 17/06/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
public struct Edge : Property, RelativeEquality, RelativeInequality, Addition, Multiplication {
public let attribute: NSLayoutAttribute
public let context: Context
public let view: View
internal init(_ context: Context, _ view: View, _ attribute: NSLayoutAttribute) {
self.attribute = attribute
self.context = context
self.view = view
}
}
//
// Edges.swift
// Cartography
//
// Created by Robert Böhnke on 19/06/14.
// Copyright (c) 2014 Robert Böhnke. All rights reserved.
//
#if os(iOS)
import UIKit
#else
import AppKit
#endif
public struct Edges: Compound, RelativeCompoundEquality, RelativeCompoundInequality {
public let context: Context
public let properties: [Property]
internal init(_ context: Context, _ properties: [Property]) {
self.context = context
self.properties = properties
}
}
/// Insets all edges.
///
/// :param: edges The edges to inset.
/// :param: all The amount by which to inset all edges, in points.
///
/// :returns: A new expression with the inset edges.
///
public func inset(edges: Edges, all: Number) -> Expression<Edges> {
return inset(edges, all, all, all, all)
}
/// Insets the horizontal and vertical edges.
///