//
|
// QLViewArray+QuickLayout.swift
|
// QuickLayout
|
//
|
// Created by Daniel Huri on 11/20/17.
|
//
|
|
import Foundation
|
#if os(OSX)
|
import AppKit
|
#else
|
import UIKit
|
#endif
|
|
// MARK: Multiple Views in Array
|
public extension Array where Element: QLView {
|
|
/**
|
All elements in the collection recieve constant value for the given edge.
|
- parameter edge: Should be used with *.width* or *.height*.
|
- parameter value: The size of the edge.
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: The instance of the constraint that was applied (discardable).
|
*/
|
@discardableResult
|
func set(_ edge: QLAttribute, of value: CGFloat,
|
priority: QLPriority = .required) -> [NSLayoutConstraint] {
|
var constraints: [NSLayoutConstraint] = []
|
for view in self {
|
let constraint = view.set(edge, of: value)
|
constraints.append(constraint)
|
}
|
return constraints
|
}
|
|
/**
|
All elements in the collection recieve constant value for the given edges, using variadic parameter.
|
- parameter edges: Should be used with *.width* or *.height*.
|
- parameter value: The size of the edge.
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: The instance of the constraint that was applied (discardable).
|
*/
|
@discardableResult
|
func set(_ edges: QLAttribute..., of value: CGFloat,
|
priority: QLPriority = .required) -> [QLMultipleConstraints] {
|
var constraintsArray: [QLMultipleConstraints] = []
|
for view in self {
|
let constraints = view.set(edges, to: value, priority: priority)
|
constraintsArray.append(constraints)
|
}
|
return constraintsArray
|
}
|
|
/**
|
Spread elements consecutively according to the given axis.
|
- parameter axis: The axis: *.vertically*, *horizontally*
|
- parameter stretchEdgesToSuperview: Decides whether the first and last items in the array must be clipped to their parent edges.
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: Array of constraints that were applied (discardable)
|
*/
|
@discardableResult
|
func spread(_ axis: QLAxis, stretchEdgesToSuperview: Bool = false, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> [NSLayoutConstraint] {
|
guard isValidForQuickLayout else {
|
return []
|
}
|
let attributes = axis.attributes
|
var constraints: [NSLayoutConstraint] = []
|
|
if stretchEdgesToSuperview {
|
let constraint = first!.layoutToSuperview(attributes.first, offset: offset)!
|
constraints.append(constraint)
|
}
|
|
for (index, view) in enumerated() {
|
guard index > 0 else {
|
continue
|
}
|
let previousView = self[index - 1]
|
let constraint = view.layout(attributes.first, to: attributes.second, of: previousView, offset: offset, priority: priority)!
|
constraints.append(constraint)
|
}
|
|
if stretchEdgesToSuperview {
|
let constraint = last!.layoutToSuperview(attributes.second, offset: -offset)!
|
constraints.append(constraint)
|
}
|
|
return constraints
|
}
|
|
/**
|
Layout elements to superview's axis
|
- parameter axis: The axis: *.vertically*, *horizontally*
|
- parameter offset: Additional side offset that must be applied (identical spacing from each side)
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: Array of QLAxisConstraints - see definition (discardable)
|
*/
|
@discardableResult
|
func layoutToSuperview(axis: QLAxis, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> [QLAxisConstraints] {
|
|
let attributes = axis.attributes
|
|
let firstConstraints = layoutToSuperview(attributes.first, offset: offset, priority: priority)
|
guard !firstConstraints.isEmpty else {
|
return []
|
}
|
|
let secondConstraints = layoutToSuperview(attributes.second, offset: -offset, priority: priority)
|
guard !secondConstraints.isEmpty else {
|
return []
|
}
|
|
var constraints: [QLAxisConstraints] = []
|
for (first, second) in zip(firstConstraints, secondConstraints) {
|
constraints.append(QLAxisConstraints(first: first, second: second))
|
}
|
|
return constraints
|
}
|
|
/**
|
Layout elements' edges to superview's edge (The same edge - top to top, bottom to bottom, etc...)
|
- parameter edge: The edge of the view / superview
|
- parameter ratio: The ratio of the edge in relation to the superview's (default is 1).
|
- parameter offset: Additional offset from that must be applied to the constraint (default is 0).
|
- parameter priority: Constraint's priority (default is *.required*).
|
- returns: Array of applied constraints - see definition (discardable)
|
*/
|
@discardableResult
|
func layoutToSuperview(_ edge: QLAttribute, ratio: CGFloat = 1, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> [NSLayoutConstraint] {
|
guard isValidForQuickLayout else {
|
return []
|
}
|
return layout(to: edge, of: first!.superview!, ratio: ratio, offset: offset, priority: priority)
|
}
|
|
/**
|
Layout elements' edges to to anchorView edge
|
- parameter firstEdge: The edge of the elements in the array
|
- parameter anchorEdge: The edge of the anchor view
|
- parameter anchorView: The anchor view
|
- 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 constraints (default is 0).
|
- parameter priority: Constraints' priority (default is *.required*).
|
- returns: Array of applied constraints - see definition (discardable)
|
*/
|
@discardableResult
|
func layout(_ firstEdge: QLAttribute? = nil, to anchorEdge: QLAttribute,
|
of anchorView: QLView, ratio: CGFloat = 1, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> [NSLayoutConstraint] {
|
guard isValidForQuickLayout else {
|
return []
|
}
|
|
let edge: QLAttribute
|
if let firstEdge = firstEdge {
|
edge = firstEdge
|
} else {
|
edge = anchorEdge
|
}
|
|
var result: [NSLayoutConstraint] = []
|
for view in self {
|
let constraint = view.layout(edge, to: anchorEdge, of: anchorView, ratio: ratio, offset: offset, priority: priority)!
|
result.append(constraint)
|
}
|
return result
|
}
|
|
/**
|
Layout elements' multiple edges to to anchorView's same edges (top to top, bottom to bottom, etc...)
|
- parameter edges: The edges of the view - variadic parameter
|
- parameter anchorView: The anchor view
|
- 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 constraints (default is 0).
|
- parameter priority: Constraints' priority (default is *.required*).
|
- returns: Array of applied constraints, each element is of type QLMultipleConstraints - see definition (discardable)
|
*/
|
@discardableResult
|
func layout(_ edges: QLAttribute..., to anchorView: QLView,
|
ratio: CGFloat = 1, offset: CGFloat = 0,
|
priority: QLPriority = .required) -> [QLMultipleConstraints] {
|
guard !edges.isEmpty && isValidForQuickLayout else {
|
return []
|
}
|
// Avoid duplicities
|
let uniqueEdges = Set(edges)
|
var result: [QLMultipleConstraints] = []
|
for view in self {
|
var multipleConstraints: QLMultipleConstraints = [:]
|
for edge in uniqueEdges {
|
let constraint = view.layout(to: edge, of: anchorView, ratio: ratio, offset: offset, priority: priority)!
|
multipleConstraints[edge] = constraint
|
}
|
result.append(multipleConstraints)
|
}
|
return result
|
}
|
|
/** **PRIVATELY USED** to test for validation*/
|
var isValidForQuickLayout: Bool {
|
guard !isEmpty else {
|
print("\(String(describing: self)) Error in func: \(#function), Views collection is empty!")
|
return false
|
}
|
|
for view in self {
|
guard view.isValidForQuickLayout else {
|
print("\(String(describing: self)) Error in func: \(#function)")
|
return false
|
}
|
}
|
return true
|
}
|
}
|