vds_ios/VDS/Protocols/LayoutConstraintable.swift
Matt Bruce 8dfcb41691 refactor for layoutguide
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-27 12:52:52 -05:00

832 lines
40 KiB
Swift

//
// LayoutConstraintable.swift
// VDS
//
// Created by Matt Bruce on 8/22/23.
//
import Foundation
import UIKit
import VDSCoreTokens
public protocol LayoutConstraintable {
var superview: UIView? { get }
var leadingAnchor: NSLayoutXAxisAnchor { get }
var trailingAnchor: NSLayoutXAxisAnchor { get }
var topAnchor: NSLayoutYAxisAnchor { get }
var bottomAnchor: NSLayoutYAxisAnchor { get }
var widthAnchor: NSLayoutDimension { get }
var heightAnchor: NSLayoutDimension { get }
var centerXAnchor: NSLayoutXAxisAnchor { get }
var centerYAnchor: NSLayoutYAxisAnchor { get }
}
//--------------------------------------------------
// MARK: - Pinning
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Pins each to the all 4 anchor points to a view.
/// - Parameters:
/// - layoutConstrainable: LayoutConstrainable that you will be pinned within.
/// - edges: Insets for each side.
/// - Returns: Yourself.
public func pin(_ layoutConstrainable: LayoutConstraintable, with edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self {
pinLeading(layoutConstrainable.leadingAnchor, edges.left)
pinTrailing(layoutConstrainable.trailingAnchor, edges.right)
pinTop(layoutConstrainable.topAnchor, edges.top)
pinBottom(layoutConstrainable.bottomAnchor, edges.bottom)
return self
}
@discardableResult
/// Pins each to the all 4 anchor points to the view you are set within.
/// - Parameter edges: Insets for each side.
/// - Returns: Yourself.
public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self {
if let superview {
pin(superview, with: edges)
}
return self
}
}
//--------------------------------------------------
// MARK: - HeightAnchor
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a heightAnchor.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func height(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self {
height(constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a heightAnchor where the height constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func heightGreaterThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self {
heightGreaterThanEqualTo(constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a heightAnchor where the height constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func heightLessThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self {
heightLessThanEqualTo(constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a heightAnchor for the constant passed into the method.
/// - Parameter constant: Constant size.
/// - Returns: The Constraint that was created.
public func height(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
heightAnchor.constraint(equalToConstant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a heightAnchor where the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: The Constraint that was created.
public func heightGreaterThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
heightAnchor.constraint(greaterThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a heightAnchor where the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: The Constraint that was created.
public func heightLessThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
heightAnchor.constraint(lessThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true }
}
}
//--------------------------------------------------
// MARK: - WidthAnchor
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a widthAnchor.
/// - Parameter constant: Width Constant size.
/// - Returns: Yourself.
public func width(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self {
width(constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a widthAnchor where the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func widthGreaterThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self {
widthGreaterThanEqualTo(constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a widthAnchor where the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func widthLessThanEqualTo(_ constant: CGFloat, _ priority: UILayoutPriority = .required) -> Self {
widthLessThanEqualTo(constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a widthAnchor for the constant passed into the method.
/// - Parameter constant: Constant size.
/// - Returns: The Constraint that was created.
public func width(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
widthAnchor.constraint(equalToConstant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a widthAnchor with the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: The Constraint that was created.
public func widthGreaterThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
widthAnchor.constraint(greaterThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a widthAnchor with the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter constant: Constant size.
/// - Returns: The Constraint that was created.
public func widthLessThanEqualTo(constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
widthAnchor.constraint(lessThanOrEqualToConstant: constant).with { $0.priority = priority; $0.isActive = true }
}
}
//--------------------------------------------------
// MARK: - TopAnchor
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a topAnchor.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func pinTop(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
return pinTop(nil, constant, priority)
}
@discardableResult
/// Adds a topAnchor to a specific YAxisAnchor.
/// - Parameter anchor:The anchor in which to attach the topAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinTop(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a topAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the topAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinTopLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinTopLessThanOrEqualTo(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a topAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the topAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinTopGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinTopGreaterThanOrEqualTo(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a topAnchor for the constant passed into the method.
/// - Parameter anchor:The anchor in which to attach the topAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinTop(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor
guard let found else { return nil }
return topAnchor.constraint(equalTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a topAnchor with the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the topAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinTopLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor
guard let found else { return nil }
return topAnchor.constraint(lessThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a topAnchor with the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the topAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinTopGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor
guard let found else { return nil }
return topAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true }
}
}
//--------------------------------------------------
// MARK: - BottomAnchor
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a bottomAnchor.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func pinBottom(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
return pinBottom(nil, constant, priority)
}
@discardableResult
/// Adds a bottomAnchor to a specific YAxisAnchor.
/// - Parameter anchor:The anchor in which to attach the bottomAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinBottom(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a bottomAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the bottomAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinBottomLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinBottomLessThanOrEqualTo(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a bottomAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the bottomAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinBottomGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinBottomGreaterThanOrEqualTo(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a bottomAnchor for the constant passed into the method.
/// - Parameter anchor:The anchor in which to attach the bottomAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinBottom(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor
guard let found else { return nil }
return bottomAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a bottomAnchor with the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the bottomAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinBottomLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor
guard let found else { return nil }
return bottomAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a bottomAnchor with the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the bottomAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinBottomGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor
guard let found else { return nil }
return bottomAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
}
//--------------------------------------------------
// MARK: - LeadingAnchor
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a leadingAnchor.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func pinLeading(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
return pinLeading(nil, constant, priority)
}
@discardableResult
/// Adds a leadingAnchor to a specific XAxisAnchor.
/// - Parameter anchor:The anchor in which to attach the leadingAnchor.
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinLeading(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a leadingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the leadingAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinLeadingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinLeadingLessThanOrEqualTo(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a leadingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the leadingAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinLeadingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinLeadingGreaterThanOrEqualTo(anchor: anchor, constant: constant, priority: priority)
return self
}
@discardableResult
/// Adds a leadingAnchor for the constant passed into the method.
/// - Parameter anchor:The anchor in which to attach the leadingAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinLeading(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor
guard let found else { return nil }
return leadingAnchor.constraint(equalTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a leadingAnchor with the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the leadingAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinLeadingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor
guard let found else { return nil }
return leadingAnchor.constraint(lessThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a leadingAnchor with the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the leadingAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinLeadingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor
guard let found else { return nil }
return leadingAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).with { $0.priority = priority; $0.isActive = true }
}
}
//--------------------------------------------------
// MARK: - TrailingAnchor
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a trailingAnchor.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func pinTrailing(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinTrailing(nil, constant)
}
@discardableResult
/// Adds a trailingAnchor to a specific XAxisAnchor.
/// - Parameter anchor:The anchor in which to attach the trailingAnchor.
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinTrailing(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a trailingAnchor to a specific XAxisAnchor passed in using a lessThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the trailingAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinTrailingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinTrailingLessThanOrEqualTo(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a trailingAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the trailingAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinTrailingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
pinTrailingGreaterThanOrEqualTo(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a trailingAnchor for the constant passed into the method.
/// - Parameter anchor:The anchor in which to attach the trailingAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinTrailing(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor
guard let found else { return nil }
return trailingAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a trailingAnchor with the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the trailingAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinTrailingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor
guard let found else { return nil }
return trailingAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a trailingAnchor with the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the trailingAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor
guard let found else { return nil }
return trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
}
//--------------------------------------------------
// MARK: - Center X Constraints
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a centerXAnchor.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func pinCenterX(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinCenterX(nil, constant)
}
@discardableResult
/// Adds a centerXAnchor to a specific XAxisAnchor.
/// - Parameter anchor:The anchor in which to attach the centerXAnchor.
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinCenterX(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinCenterX(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a centerXAnchor to a specific XAxisAnchor passed in using a lessThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the centerXAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinCenterXLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinCenterXLessThanOrEqualTo(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a centerXAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the centerXAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinCenterXGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
pinCenterXGreaterThanOrEqualTo(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a centerXAnchor for the constant passed into the method.
/// - Parameter anchor:The anchor in which to attach the centerXAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinCenterX(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.centerXAnchor
guard let found else { return nil }
return centerXAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a centerXAnchor with the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the centerXAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinCenterXLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.centerXAnchor
guard let found else { return nil }
return centerXAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a centerXAnchor with the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the centerXAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinCenterXGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutXAxisAnchor? = anchor ?? superview?.centerXAnchor
guard let found else { return nil }
return centerXAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
}
//--------------------------------------------------
// MARK: - Center Y Constraints
//--------------------------------------------------
extension LayoutConstraintable {
@discardableResult
/// Adds a centerYAnchor.
/// - Parameter constant: Constant size.
/// - Returns: Yourself.
public func pinCenterY(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinCenterY(nil, constant)
}
@discardableResult
/// Adds a centerYAnchor to a specific YAxisAnchor.
/// - Parameter anchor:The anchor in which to attach the centerYAnchor.
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinCenterY(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinCenterY(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a centerYAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the centerYAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinCenterYLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self {
pinCenterYLessThanOrEqualTo(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a centerYAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint
/// - Parameter anchor:The anchor in which to attach the centerYAnchor
/// - constant: Constant size.
/// - Returns: Yourself.
public func pinCenterYGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self {
pinCenterXGreaterThanOrEqualTo(anchor: anchor, constant: constant)
return self
}
@discardableResult
/// Adds a centerYAnchor for the constant passed into the method.
/// - Parameter anchor:The anchor in which to attach the centerYAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinCenterY(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.centerYAnchor
guard let found else { return nil }
return centerYAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a centerYAnchor with the constant passed in using a lessThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the centerYAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinCenterYLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.centerYAnchor
guard let found else { return nil }
return centerYAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
@discardableResult
/// Adds a centerYAnchor with the constant passed in using a greaterThanOrEqualTo Constraint.
/// - Parameter anchor:The anchor in which to attach the centerYAnchor
/// - constant: Constant size.
/// - Returns: The Constraint that was created.
public func pinCenterYGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? {
let found: NSLayoutYAxisAnchor? = anchor ?? superview?.centerYAnchor
guard let found else { return nil }
return centerYAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true }
}
}
// alignment
public enum LayoutAlignment: String, CaseIterable {
case fill
case leading
case top
case center
case trailing
case bottom
}
public enum LayoutDistribution: String, CaseIterable {
case fill
case fillProportionally
}
extension LayoutConstraintable {
public func removeConstraints() {
guard let view = self as? UIView, let superview = view.superview else { return }
// Remove all existing constraints on the containerView
let superviewConstraints = superview.constraints
for constraint in superviewConstraints {
if constraint.firstItem as? UIView == view
|| constraint.secondItem as? UIView == view {
superview.removeConstraint(constraint)
}
}
}
public func applyAlignment(_ alignment: LayoutAlignment, edges: UIEdgeInsets = UIEdgeInsets.zero) {
guard let superview = superview else { return }
removeConstraints()
switch alignment {
case .fill:
pinToSuperView(edges)
case .leading:
pinTop(edges.top)
pinLeading(edges.left)
pinTrailingLessThanOrEqualTo(anchor: superview.trailingAnchor, constant: edges.right)
pinBottom(edges.bottom)
case .trailing:
pinTop(edges.top)
pinLeadingGreaterThanOrEqualTo(anchor: superview.leadingAnchor, constant: edges.left)
pinTrailing(edges.right)
pinBottom(edges.bottom)
case .top:
pinTop(edges.top)
pinLeadingGreaterThanOrEqualTo(anchor: superview.leadingAnchor, constant: edges.left)
pinTrailingLessThanOrEqualTo(anchor: superview.trailingAnchor, constant: edges.right)
pinBottomLessThanOrEqualTo(anchor: superview.bottomAnchor, constant: edges.bottom)
case .bottom:
pinTopGreaterThanOrEqualTo(anchor: superview.topAnchor, constant: edges.top)
pinLeadingGreaterThanOrEqualTo(anchor: superview.leadingAnchor, constant: edges.left)
pinTrailingLessThanOrEqualTo(anchor: superview.trailingAnchor, constant: edges.right)
pinBottom(edges.bottom)
case .center:
pinCenterX()
pinTop(edges.top)
pinLeadingGreaterThanOrEqualTo(anchor: superview.leadingAnchor, constant: edges.left)
pinTrailingLessThanOrEqualTo(anchor: superview.trailingAnchor, constant: edges.right)
pinBottom(edges.bottom)
}
}
// Method to check if the view is pinned to its superview
public func isPinnedToSuperview() -> Bool {
isPinnedVerticallyToSuperview() && isPinnedHorizontallyToSuperview()
}
public func horizontalPinnedSize() -> CGSize? {
guard let view = self as? UIView, let superview = view.superview else { return nil }
let constraints = superview.constraints
var leadingPinnedObject: AnyObject?
var trailingPinnedObject: AnyObject?
for constraint in constraints {
if (constraint.firstItem === view && (constraint.firstAttribute == .leading || constraint.firstAttribute == .left)) {
leadingPinnedObject = constraint.secondItem as AnyObject?
} else if (constraint.secondItem === view && (constraint.secondAttribute == .leading || constraint.secondAttribute == .left)) {
leadingPinnedObject = constraint.firstItem as AnyObject?
} else if (constraint.firstItem === view && (constraint.firstAttribute == .trailing || constraint.firstAttribute == .right)) {
trailingPinnedObject = constraint.secondItem as AnyObject?
} else if (constraint.secondItem === view && (constraint.secondAttribute == .trailing || constraint.secondAttribute == .right)) {
trailingPinnedObject = constraint.firstItem as AnyObject?
}
}
// Ensure both leading and trailing pinned objects are identified
if let leadingObject = leadingPinnedObject, let trailingObject = trailingPinnedObject {
// Calculate the size based on the pinned objects
if let leadingView = leadingObject as? UIView, let trailingView = trailingObject as? UIView {
let leadingPosition = leadingView.convert(leadingView.bounds.origin, to: superview).x
let trailingPosition = trailingView.convert(trailingView.bounds.origin, to: superview).x + trailingView.bounds.width
return CGSize(width: trailingPosition - leadingPosition, height: view.bounds.size.height)
} else if let leadingGuide = leadingObject as? UILayoutGuide, let trailingGuide = trailingObject as? UILayoutGuide {
let leadingPosition = leadingGuide.layoutFrame.minX
let trailingPosition = trailingGuide.layoutFrame.maxX
return CGSize(width: trailingPosition - leadingPosition, height: view.bounds.size.height)
} else if let leadingView = leadingObject as? UIView, let trailingGuide = trailingObject as? UILayoutGuide {
let leadingPosition = leadingView.convert(leadingView.bounds.origin, to: superview).x
let trailingPosition = trailingGuide.layoutFrame.maxX
return CGSize(width: trailingPosition - leadingPosition, height: view.bounds.size.height)
} else if let leadingGuide = leadingObject as? UILayoutGuide, let trailingView = trailingObject as? UIView {
let leadingPosition = leadingGuide.layoutFrame.minX
let trailingPosition = trailingView.convert(trailingView.bounds.origin, to: superview).x + trailingView.bounds.width
return CGSize(width: trailingPosition - leadingPosition, height: view.bounds.size.height)
}
} else if let pinnedObject = leadingPinnedObject {
if let view = pinnedObject as? UIView {
return view.bounds.size
} else if let layoutGuide = pinnedObject as? UILayoutGuide {
return layoutGuide.layoutFrame.size
}
} else if let pinnedObject = trailingPinnedObject {
if let view = pinnedObject as? UIView {
return view.bounds.size
} else if let layoutGuide = pinnedObject as? UILayoutGuide {
return layoutGuide.layoutFrame.size
}
}
return nil
}
public func isPinnedHorizontallyToSuperview() -> Bool {
guard let view = self as? UIView, let superview = view.superview else { return false }
let constraints = superview.constraints
var leadingPinned = false
var trailingPinned = false
for constraint in constraints {
if (constraint.firstItem as? UIView == view && constraint.firstAttribute == .leading && constraint.relation == .equal) ||
(constraint.secondItem as? UIView == view && constraint.secondAttribute == .leading && constraint.relation == .equal) ||
(constraint.firstItem as? UIView == view && constraint.firstAttribute == .left && constraint.relation == .equal) ||
(constraint.secondItem as? UIView == view && constraint.secondAttribute == .left && constraint.relation == .equal) {
leadingPinned = true
}
if (constraint.firstItem as? UIView == view && constraint.firstAttribute == .trailing && constraint.relation == .equal) ||
(constraint.secondItem as? UIView == view && constraint.secondAttribute == .trailing && constraint.relation == .equal) ||
(constraint.firstItem as? UIView == view && constraint.firstAttribute == .right && constraint.relation == .equal) ||
(constraint.secondItem as? UIView == view && constraint.secondAttribute == .right && constraint.relation == .equal) {
trailingPinned = true
}
}
return leadingPinned && trailingPinned
}
public func isPinnedVerticallyToSuperview() -> Bool {
guard let view = self as? UIView, let superview = view.superview else { return false }
let constraints = superview.constraints
var topPinned = false
var bottomPinned = false
for constraint in constraints {
if (constraint.firstItem as? UIView == view && constraint.firstAttribute == .top && constraint.relation == .equal) ||
(constraint.secondItem as? UIView == view && constraint.secondAttribute == .top && constraint.relation == .equal) {
topPinned = true
}
if (constraint.firstItem as? UIView == view && constraint.firstAttribute == .bottom && constraint.relation == .equal) ||
(constraint.secondItem as? UIView == view && constraint.secondAttribute == .bottom && constraint.relation == .equal) {
bottomPinned = true
}
}
return topPinned && bottomPinned
}
}
//--------------------------------------------------
// MARK: - Implementations
//--------------------------------------------------
extension UIView: LayoutConstraintable {}
extension UILayoutGuide: LayoutConstraintable {
public var superview: UIView? {
owningView
}
}