Begin support for LayoutGuide constraint maker

This commit is contained in:
Robert Payne 2016-10-07 23:58:56 +13:00
parent 4018d4bd12
commit dc304472aa
11 changed files with 140 additions and 78 deletions

View File

@ -33,6 +33,7 @@
EE235FC31C5785DC00C08960 /* ConstraintLayoutSupportDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE235FBF1C5785DC00C08960 /* ConstraintLayoutSupportDSL.swift */; };
EE235FC81C5785E200C08960 /* ConstraintView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE235FC61C5785E200C08960 /* ConstraintView+Extensions.swift */; };
EE4910991B19A40200A54F1F /* SnapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEBCC9D819CC627D0083B827 /* SnapKit.framework */; };
EE6898CB1DA7B3A100D47F33 /* LayoutConstraintItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6898CA1DA7B3A100D47F33 /* LayoutConstraintItem.swift */; };
EECDB3741AC0C9B6006BBC11 /* SnapKit.h in Headers */ = {isa = PBXBuildFile; fileRef = EECDB3661AC0C95C006BBC11 /* SnapKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
EECDB3931AC0CB52006BBC11 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECDB36A1AC0C95C006BBC11 /* Tests.swift */; };
EEF68F9E1D78492400980C26 /* ConstraintLayoutGuideDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF68F9D1D78492400980C26 /* ConstraintLayoutGuideDSL.swift */; };
@ -70,6 +71,7 @@
EE235FBE1C5785DC00C08960 /* ConstraintViewDSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintViewDSL.swift; sourceTree = "<group>"; };
EE235FBF1C5785DC00C08960 /* ConstraintLayoutSupportDSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintLayoutSupportDSL.swift; sourceTree = "<group>"; };
EE235FC61C5785E200C08960 /* ConstraintView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConstraintView+Extensions.swift"; sourceTree = "<group>"; };
EE6898CA1DA7B3A100D47F33 /* LayoutConstraintItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutConstraintItem.swift; sourceTree = "<group>"; };
EE94F6081AC0F10A008767FF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
EE94F60A1AC0F10F008767FF /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; };
EEBCC9D819CC627D0083B827 /* SnapKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SnapKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -184,6 +186,7 @@
EE235F6A1C5785C600C08960 /* ConstraintAttributes.swift */,
EE235F6B1C5785C600C08960 /* ConstraintItem.swift */,
EE235F6C1C5785C600C08960 /* LayoutConstraint.swift */,
EE6898CA1DA7B3A100D47F33 /* LayoutConstraintItem.swift */,
);
name = Models;
sourceTree = "<group>";
@ -372,6 +375,7 @@
EE235F761C5785C600C08960 /* ConstraintConfig.swift in Sources */,
EE235F6D1C5785C600C08960 /* Constraint.swift in Sources */,
EE235F791C5785C600C08960 /* ConstraintView.swift in Sources */,
EE6898CB1DA7B3A100D47F33 /* LayoutConstraintItem.swift in Sources */,
EE235FB21C5785D400C08960 /* ConstraintMakerPriortizable.swift in Sources */,
EE235F8B1C5785C600C08960 /* LayoutConstraint.swift in Sources */,
EE235FA31C5785CE00C08960 /* ConstraintInsetTarget.swift in Sources */,

View File

@ -73,7 +73,7 @@ public class Constraint {
let layoutToAttributes = self.to.attributes.layoutAttributes
// get layout from
let layoutFrom: ConstraintView = self.from.view!
let layoutFrom = self.from.layoutConstraintItem!
// get relation
let layoutRelation = self.relation.layoutRelation
@ -247,12 +247,12 @@ public class Constraint {
}
internal func activateIfNeeded(updatingExisting: Bool = false) {
guard let view = self.from.view else {
print("WARNING: SnapKit failed to get from view from constraint. Activate will be a no-op.")
guard let item = self.from.layoutConstraintItem else {
print("WARNING: SnapKit failed to get from item from constraint. Activate will be a no-op.")
return
}
let layoutConstraints = self.layoutConstraints
let existingLayoutConstraints = view.snp.constraints.map({ $0.layoutConstraints }).reduce([]) { $0 + $1 }
let existingLayoutConstraints = item.constraints.map({ $0.layoutConstraints }).reduce([]) { $0 + $1 }
if updatingExisting {
for layoutConstraint in layoutConstraints {
@ -266,17 +266,17 @@ public class Constraint {
}
} else {
NSLayoutConstraint.activate(layoutConstraints)
view.snp.add(constraints: [self])
item.add(constraints: [self])
}
}
internal func deactivateIfNeeded() {
guard let view = self.from.view else {
print("WARNING: SnapKit failed to get from view from constraint. Deactivate will be a no-op.")
guard let item = self.from.layoutConstraintItem else {
print("WARNING: SnapKit failed to get from item from constraint. Deactivate will be a no-op.")
return
}
let layoutConstraints = self.layoutConstraints
NSLayoutConstraint.deactivate(layoutConstraints)
view.snp.remove(constraints: [self])
item.remove(constraints: [self])
}
}

View File

@ -28,7 +28,7 @@
#endif
internal struct ConstraintAttributes: OptionSet {
internal struct ConstraintAttributes : OptionSet {
internal init(rawValue: UInt) {
self.rawValue = rawValue

View File

@ -30,7 +30,7 @@
public class ConstraintDescription {
internal let view: ConstraintView
internal let item: LayoutConstraintItem
internal var attributes: ConstraintAttributes
internal var relation: ConstraintRelation? = nil
internal var sourceLocation: (String, UInt)? = nil
@ -45,7 +45,7 @@ public class ConstraintDescription {
let sourceLocation = self.sourceLocation else {
return nil
}
let from = ConstraintItem(target: self.view, attributes: self.attributes)
let from = ConstraintItem(target: self.item as AnyObject, attributes: self.attributes)
return Constraint(
from: from,
@ -61,8 +61,8 @@ public class ConstraintDescription {
// MARK: Initialization
internal init(view: ConstraintView, attributes: ConstraintAttributes) {
self.view = view
internal init(item: LayoutConstraintItem, attributes: ConstraintAttributes) {
self.item = item
self.attributes = attributes
}

View File

@ -28,7 +28,7 @@
#endif
public class ConstraintItem: Equatable {
public class ConstraintItem : Equatable {
internal weak var target: AnyObject?
internal let attributes: ConstraintAttributes
@ -38,8 +38,8 @@ public class ConstraintItem: Equatable {
self.attributes = attributes
}
internal var view: ConstraintView? {
return self.target as? ConstraintView
internal var layoutConstraintItem: LayoutConstraintItem? {
return self.target as? LayoutConstraintItem
}
}

View File

@ -143,22 +143,22 @@ public class ConstraintMaker {
return self.makeExtendableWithAttributes(.centerWithinMargins)
}
private let view: ConstraintView
private let item: LayoutConstraintItem
private var descriptions = [ConstraintDescription]()
internal init(view: ConstraintView) {
self.view = view
self.view.translatesAutoresizingMaskIntoConstraints = false
internal init(item: LayoutConstraintItem) {
self.item = item
self.item.prepare()
}
internal func makeExtendableWithAttributes(_ attributes: ConstraintAttributes) -> ConstraintMakerExtendable {
let description = ConstraintDescription(view: self.view, attributes: attributes)
let description = ConstraintDescription(item: self.item, attributes: attributes)
self.descriptions.append(description)
return ConstraintMakerExtendable(description)
}
internal static func prepareConstraints(view: ConstraintView, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
let maker = ConstraintMaker(view: view)
internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
let maker = ConstraintMaker(item: item)
closure(maker)
let constraints = maker.descriptions
.map { $0.constraint }
@ -167,8 +167,8 @@ public class ConstraintMaker {
return constraints
}
internal static func makeConstraints(view: ConstraintView, closure: (_ make: ConstraintMaker) -> Void) {
let maker = ConstraintMaker(view: view)
internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
let maker = ConstraintMaker(item: item)
closure(maker)
let constraints = maker.descriptions
.map { $0.constraint }
@ -179,18 +179,18 @@ public class ConstraintMaker {
}
}
internal static func remakeConstraints(view: ConstraintView, closure: (_ make: ConstraintMaker) -> Void) {
self.removeConstraints(view: view)
self.makeConstraints(view: view, closure: closure)
internal static func remakeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
self.removeConstraints(item: item)
self.makeConstraints(item: item, closure: closure)
}
internal static func updateConstraints(view: ConstraintView, closure: (_ make: ConstraintMaker) -> Void) {
guard view.snp.constraints.count > 0 else {
self.makeConstraints(view: view, closure: closure)
internal static func updateConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
guard item.constraints.count > 0 else {
self.makeConstraints(item: item, closure: closure)
return
}
let maker = ConstraintMaker(view: view)
let maker = ConstraintMaker(item: item)
closure(maker)
let constraints = maker.descriptions
.map { $0.constraint }
@ -201,8 +201,8 @@ public class ConstraintMaker {
}
}
internal static func removeConstraints(view: ConstraintView) {
let constraints = view.snp.constraints
internal static func removeConstraints(item: LayoutConstraintItem) {
let constraints = item.constraints
for constraint in constraints {
constraint.deactivateIfNeeded()
}

View File

@ -76,7 +76,7 @@ public class ConstraintMakerRelatable {
@discardableResult
public func equalToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.view.superview else {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.")
}
return self.relatedTo(other, relation: .equal, file: file, line: line)
@ -89,7 +89,7 @@ public class ConstraintMakerRelatable {
@discardableResult
public func lessThanOrEqualToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.view.superview else {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.")
}
return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)
@ -102,7 +102,7 @@ public class ConstraintMakerRelatable {
@discardableResult
public func greaterThanOrEqualToSuperview(_ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.view.superview else {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.")
}
return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)

View File

@ -28,7 +28,7 @@
#endif
internal enum ConstraintRelation: Int {
internal enum ConstraintRelation : Int {
case equal = 1
case lessThanOrEqual
case greaterThanOrEqual

View File

@ -32,27 +32,25 @@ public struct ConstraintViewDSL: ConstraintAttributesDSL {
@discardableResult
public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
return ConstraintMaker.prepareConstraints(view: self.view, closure: closure)
return ConstraintMaker.prepareConstraints(item: self.view, closure: closure)
}
public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.makeConstraints(view: self.view, closure: closure)
ConstraintMaker.makeConstraints(item: self.view, closure: closure)
}
public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.remakeConstraints(view: self.view, closure: closure)
ConstraintMaker.remakeConstraints(item: self.view, closure: closure)
}
public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.updateConstraints(view: self.view, closure: closure)
ConstraintMaker.updateConstraints(item: self.view, closure: closure)
}
public func removeConstraints() {
ConstraintMaker.removeConstraints(view: self.view)
ConstraintMaker.removeConstraints(item: self.view)
}
public var contentHuggingHorizontalPriority: Float {
get {
return self.view.contentHuggingPriority(for: .horizontal)
@ -100,36 +98,4 @@ public struct ConstraintViewDSL: ConstraintAttributesDSL {
}
internal var constraints: [Constraint] {
return self.constraintsHashTable.allObjects
}
internal func add(constraints: [Constraint]) {
let hashTable = self.constraintsHashTable
for constraint in constraints {
hashTable.add(constraint)
}
}
internal func remove(constraints: [Constraint]) {
let hashTable = self.constraintsHashTable
for constraint in constraints {
hashTable.remove(constraint)
}
}
private var constraintsHashTable: NSHashTable<Constraint> {
let constraints: NSHashTable<Constraint>
if let existing = objc_getAssociatedObject(self.view, &constraintsKey) as? NSHashTable<Constraint> {
constraints = existing
} else {
constraints = NSHashTable<Constraint>()
objc_setAssociatedObject(self.view, &constraintsKey, constraints, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return constraints
}
}
private var constraintsKey: UInt8 = 0

View File

@ -28,7 +28,7 @@
#endif
public class LayoutConstraint: NSLayoutConstraint {
public class LayoutConstraint : NSLayoutConstraint {
public var label: String? {
get {

View File

@ -0,0 +1,92 @@
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol LayoutConstraintItem: class {
}
extension ConstraintLayoutGuide : LayoutConstraintItem {
}
extension ConstraintView : LayoutConstraintItem {
}
extension LayoutConstraintItem {
internal func prepare() {
if let view = self as? ConstraintView {
view.translatesAutoresizingMaskIntoConstraints = false
}
}
internal var superview: ConstraintView? {
if let view = self as? ConstraintView {
return view.superview
}
if #available(iOS 9.0, *), let guide = self as? ConstraintLayoutGuide {
return guide.owningView
}
return nil
}
internal var constraints: [Constraint] {
return self.constraintsHashTable.allObjects
}
internal func add(constraints: [Constraint]) {
let hashTable = self.constraintsHashTable
for constraint in constraints {
hashTable.add(constraint)
}
}
internal func remove(constraints: [Constraint]) {
let hashTable = self.constraintsHashTable
for constraint in constraints {
hashTable.remove(constraint)
}
}
private var constraintsHashTable: NSHashTable<Constraint> {
let constraints: NSHashTable<Constraint>
if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSHashTable<Constraint> {
constraints = existing
} else {
constraints = NSHashTable<Constraint>()
objc_setAssociatedObject(self, &constraintsKey, constraints, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return constraints
}
}
private var constraintsKey: UInt8 = 0