//
|
// QLView+QuickLayout.swift
|
// QuickLayout
|
//
|
// Created by Daniel Huri on 11/19/17.
|
//
|
|
import Foundation
|
#if os(OSX)
|
import AppKit
|
#else
|
import UIKit
|
#endif
|
|
public extension QLView {
|
|
/**
|
Set constant value of an edge.
|
Should be used with *width* or *height*
|
- parameter edge: Edge type.
|
- parameter value: Edge size.
|
- parameter relation: Relation to the given constant value (default is *.equal*).
|
- parameter ratio: Ratio of the cconstant constraint to actual given value (default is *1*)
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: The applied constraint (discardable).
|
*/
|
@discardableResult
|
func set(_ edge: QLAttribute, of value: CGFloat, relation: QLRelation = .equal,
|
ratio: CGFloat = 1.0, priority: QLPriority = .required) -> NSLayoutConstraint {
|
if translatesAutoresizingMaskIntoConstraints {
|
translatesAutoresizingMaskIntoConstraints = false
|
}
|
let constraint = NSLayoutConstraint(item: self, attribute: edge, relatedBy: relation, toItem: nil, attribute: .notAnAttribute, multiplier: ratio, constant: value)
|
constraint.priority = priority
|
addConstraint(constraint)
|
return constraint
|
}
|
|
/**
|
Set constant value for multiple edges simultaniously, using variadic parameter.
|
Should be used with *width* or *height*
|
- parameter edges: Edge types.
|
- parameter value: Edges size.
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: The applied constraints in QLMultipleConstraints - see definition (discardable).
|
*/
|
@discardableResult
|
func set(_ edges: QLAttribute..., of value: CGFloat, relation: QLRelation = .equal,
|
ratio: CGFloat = 1.0, priority: QLPriority = .required) -> QLMultipleConstraints {
|
return set(edges, to: value, relation: relation, ratio: ratio, priority: priority)
|
}
|
|
/** **PRIVATELY USED** AS A REPLACEMENT for the variadic version for the method*/
|
@discardableResult
|
func set(_ edges: [QLAttribute], to value: CGFloat, relation: QLRelation = .equal,
|
ratio: CGFloat = 1.0, priority: QLPriority = .required) -> QLMultipleConstraints {
|
var constraints: QLMultipleConstraints = [:]
|
let uniqueEdges = Set(edges)
|
for edge in uniqueEdges {
|
let constraint = set(edge, of: value, priority: priority)
|
constraints[edge] = constraint
|
}
|
return constraints
|
}
|
|
/**
|
Layout edge to another view's edge.
|
- You can optionally define relation, ratio, constant and priority (each gets a default value)
|
- For example - Can be used to align self *left* edge to the *right* of another view.
|
- *self* and *view* must be directly connected (siblings / child-parent) in the view hierarchy.
|
- *superview* must not be *nil*.
|
- parameter edge: The edge of the first view. If not sent or *nil* - The function automatically assumes *edge* to be *otherEdge*
|
- parameter otherEdge: The edge of the second view.
|
- parameter view: The second view that self must be aligned with.
|
- parameter relation: The relation of the first edge to the second edge (default is .equal)
|
- parameter ratio: The ratio of the edge in relative to the superview edge (default is 1).
|
- parameter offset: Additional offset which is applied to the constraint (default is 0).
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: The instance of the constraint that was applied (discardable). nil if method failed to apply the constraint.
|
*/
|
@discardableResult
|
func layout(_ edge: QLAttribute? = nil, to otherEdge: QLAttribute, of view: QLView,
|
relation: QLRelation = .equal, ratio: CGFloat = 1.0, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> NSLayoutConstraint? {
|
guard isValidForQuickLayout else {
|
print("\(String(describing: self)) Error in func: \(#function)")
|
return nil
|
}
|
let constraint = NSLayoutConstraint(item: self, attribute: edge ?? otherEdge, relatedBy: relation, toItem: view, attribute: otherEdge, multiplier: ratio, constant: offset)
|
constraint.priority = priority
|
superview!.addConstraint(constraint)
|
return constraint
|
}
|
|
/**
|
Layout multiple edges of the view to the corresonding edges of another given view.
|
- You can optionally define relation, ratio, constant and priority (each gets a default value)
|
- For example - Can be used to align self *left* and *right* edges the same edge of another given view.
|
- *self* and *view* must be directly connected (siblings / child-parent) in the view hierarchy.
|
- *superview* must not be *nil*.
|
- parameter edges: The view edges
|
- parameter view: Another view that self must be aligned with.
|
- parameter relation: The relation of the edges. Can be applied to *.width* or *height* for example. (default is *.equal*).
|
- parameter ratio: The ratio of the edges to the other view edges (default is 1).
|
- parameter offset: Additional offset which is applied to each of the constraints (default is 0).
|
- parameter priority: Constraints' priority (default is *.required*).
|
- returns: The instance of the constraint that was applied (discardable). *nil* if the method failed to apply the constraint.
|
*/
|
@discardableResult
|
func layout(_ edges: QLAttribute..., to view: QLView, relation: QLRelation = .equal,
|
ratio: CGFloat = 1.0, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> QLMultipleConstraints {
|
var constraints: QLMultipleConstraints = [:]
|
guard isValidForQuickLayout else {
|
print("\(String(describing: self)) Error in func: \(#function)")
|
return constraints
|
}
|
let uniqueEdges = Set(edges)
|
for edge in uniqueEdges {
|
let constraint = NSLayoutConstraint(item: self, attribute: edge, relatedBy: relation, toItem: view, attribute: edge, multiplier: ratio, constant: offset)
|
constraint.priority = priority
|
superview!.addConstraint(constraint)
|
constraints[edge] = constraint
|
}
|
return constraints
|
}
|
|
/**
|
Layout edge to the same edge of superview.
|
- Example of usage: *view.layoutToSuperview(.top)* makes *view* cling to the *top* of it's *superview*.
|
- You can optionally define ratio, constant and priority (each gets a default value)
|
- *superview* must not be *nil*.
|
- parameter edge: The edge (.width, .height, .left, .right, .leading, .trailing, etc...)
|
- parameter relation: The relation of the edge to the superview's corresponding edge (default is *.equal*)
|
- parameter ratio: The ratio of the edge in relative to the superview edge (default is 1).
|
- parameter offset: Additional offset from that can be applied to the constraint (default is 0).
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: The instance of the constraint that was applied (discardable). Nil if method failed to apply constraint.
|
*/
|
@discardableResult
|
func layoutToSuperview(_ edge: QLAttribute, relation: QLRelation = .equal,
|
ratio: CGFloat = 1, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> NSLayoutConstraint? {
|
guard isValidForQuickLayout else {
|
print("\(String(describing: self)) Error in func: \(#function)")
|
return nil
|
}
|
let constraint = NSLayoutConstraint(item: self, attribute: edge, relatedBy: relation, toItem: superview, attribute: edge, multiplier: ratio, constant: offset)
|
constraint.priority = priority
|
superview!.addConstraint(constraint)
|
return constraint
|
}
|
|
/**
|
Layout multiple edges to the same edges as superview, using variadic parameter.
|
Example for edges value:
|
- You can optionally define ratio, constant and priority (each gets a default value)
|
- *superview* must not be *nil*.
|
- parameter edges: The edges (.width, .height, .left, .right, .leading, .trailing, etc...)
|
- parameter relation: The relation of the edges to the superview's corresponding edges (default is *.equal*)
|
- parameter ratio: The ratio of the edges in relative to the superview edge (default is 1).
|
- parameter offset: Additional offset from that can be applied to the constraints (default is 0).
|
- parameter priority: Constraints' priority (default is *.required*).
|
- returns: The instance of QLMultipleConstraints - see type definition (discardable).
|
*/
|
@discardableResult
|
func layoutToSuperview(_ edges: QLAttribute..., relation: QLRelation = .equal,
|
ratio: CGFloat = 1, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> QLMultipleConstraints {
|
var constraints: QLMultipleConstraints = [:]
|
guard !edges.isEmpty && isValidForQuickLayout else {
|
return constraints
|
}
|
let uniqueEdges = Set(edges)
|
for edge in uniqueEdges {
|
let constraint = NSLayoutConstraint(item: self, attribute: edge, relatedBy: relation, toItem: superview, attribute: edge, multiplier: ratio, constant: offset)
|
constraint.priority = priority
|
superview!.addConstraint(constraint)
|
constraints[edge] = constraint
|
}
|
return constraints
|
}
|
|
/**
|
Layout to one of the superview's axes.
|
- You can optionally define ratio, constant and priority (each gets a default value)
|
- *superview* must not be *nil*.
|
- parameter axis: The axis to which the view must be stretched (horizontally or vertically)
|
- parameter offset: Represents an additional edge offset from that can be applied to the constraints (default is 0)
|
- parameter priority: Represents constraint's priority (default is *.required*)
|
- returns: The instance of the constraint that was applied (discardable).
|
*/
|
@discardableResult
|
func layoutToSuperview(axis: QLAxis, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> QLAxisConstraints? {
|
let attributes = axis.attributes
|
guard let first = layoutToSuperview(attributes.first, offset: offset, priority: priority) else {
|
return nil
|
}
|
guard let second = layoutToSuperview(attributes.second, offset: -offset, priority: priority) else {
|
return nil
|
}
|
return QLAxisConstraints(first: first, second: second)
|
}
|
|
/**
|
Size to superview with a given ratio and constant
|
- *superview* must not be *nil*.
|
- parameter ratio: The ratio of view to the size of superview.
|
- parameter offset: Represents an additional edge offset from that can be applied to the size (default is 0)
|
- parameter priority: Represents constraint's priority (default is *.required*)
|
- returns: The instance of QLSizeConstraints - see definition (discardable).
|
*/
|
@discardableResult
|
func sizeToSuperview(withRatio ratio: CGFloat = 1, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> QLSizeConstraints? {
|
let size = layoutToSuperview(.width, .height, ratio: ratio, offset: offset, priority: priority)
|
guard !size.isEmpty else {
|
return nil
|
}
|
return QLSizeConstraints(width: size[.width]!, height: size[.height]!)
|
}
|
|
/**
|
Center in superview with an optional offset
|
- *superview* must not be *nil*.
|
- parameter offset: Represents an additional offset from the center (default is 0)
|
- parameter priority: Represents constraint's priority (default is *.required*)
|
- returns: The instance of QLCenterConstraints - see definition (discardable).
|
*/
|
@discardableResult
|
func centerInSuperview(offset: CGFloat = 0, priority: QLPriority = .required) -> QLCenterConstraints? {
|
let center = layoutToSuperview(.centerX, .centerY, offset: offset)
|
guard !center.isEmpty else {
|
return nil
|
}
|
return QLCenterConstraints(x: center[.centerX]!, y: center[.centerY]!)
|
}
|
|
/**
|
Fill superview totally (center and size to superview)
|
- *superview* must not be *nil*.
|
- parameter ratio: Ratio to the superview's size (default is 1)
|
- parameter offset: Offset from center (default is 0)
|
- parameter priority: Represents constraint's priority (default is *.required*)
|
- returns: The instance of QLFillConstraints - see definition (discardable).
|
*/
|
@discardableResult
|
func fillSuperview(withSizeRatio ratio: CGFloat = 1, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> QLFillConstraints? {
|
guard let center = centerInSuperview(priority: priority) else {
|
return nil
|
}
|
guard let size = sizeToSuperview(withRatio: ratio, offset: offset, priority: priority) else {
|
return nil
|
}
|
return QLFillConstraints(center: center, size: size)
|
}
|
|
/** **PRIVATELY USED** to test for validation*/
|
var isValidForQuickLayout: Bool {
|
guard superview != nil else {
|
print("\(String(describing: self)):\(#function) - superview is unexpectedly nullified")
|
return false
|
}
|
if translatesAutoresizingMaskIntoConstraints {
|
translatesAutoresizingMaskIntoConstraints = false
|
}
|
return true
|
}
|
}
|