diff --git a/Sources/Spatial/ConstraintKind/ConstraintKind+Access.swift b/Sources/Spatial/ConstraintKind/ConstraintKind+Access.swift index 904ff1b..9688efc 100644 --- a/Sources/Spatial/ConstraintKind/ConstraintKind+Access.swift +++ b/Sources/Spatial/ConstraintKind/ConstraintKind+Access.swift @@ -6,64 +6,72 @@ import QuartzCore */ extension ConstraintKind where Self: View { /** - * One-liner for `applyAnchorAndSize` + * Applies anchor and size constraints to the view, with optional parameters for customization. + * - Remark: This is a one-liner for `applyAnchorAndSize`, which is a more customizable method. * ## Examples: * view.applyAnchorAndSize(to: self, height: 100, align: .centerCenter, alignTo: .centerCenter) * - Parameters: - * - to: The instance to apply to - * - sizeTo: Provide this if you need to base the size on another view - * - width: The width to apply to instance - * - height: The height to apply to instance - * - align: Alignment for the `to` view - * - alignTo: Alignment for the `sizeTo` view, if one was provided - * - multiplier: Multiplies the `size` or `sizeTo` - * - offset: Offset for the `to` parameter - * - sizeOffset: Offset for the `sizeTo` parameter (use negative values for inset) - * - useMargin: Aligns to AutoLayout margins or not + * - to: The instance to apply the constraints to. + * - sizeTo: The view to base the size on, if any. + * - width: The width to apply to the view. + * - height: The height to apply to the view. + * - align: The alignment for the `to` view. + * - alignTo: The alignment for the `sizeTo` view, if one was provided. + * - multiplier: The multiplier for the size constraints. + * - offset: The offset for the `to` parameter. + * - sizeOffset: The offset for the `sizeTo` parameter (use negative values for inset). + * - useMargin: Whether to align to AutoLayout margins or not. */ public func applyAnchorAndSize(to: View, sizeTo: View? = nil, width: CGFloat? = nil, height: CGFloat? = nil, align: Alignment = .topLeft, alignTo: Alignment = .topLeft, multiplier: CGSize = .init(width: 1, height: 1), offset: CGPoint = .zero, sizeOffset: CGSize = .zero, useMargin: Bool = false) { + // Call the more customizable `applyAnchorAndSize` method with a closure that defines the anchor and size constraints self.applyAnchorAndSize { _ in - let anchor: AnchorConstraint = Constraint.anchor(self, to: to, align: align, alignTo: alignTo, offset: offset, useMargin: useMargin) + let anchor: AnchorConstraint = Constraint.anchor(self, to: to, align: align, alignTo: alignTo, offset: offset, useMargin: useMargin) // Create an anchor constraint for the view let size: SizeConstraint = { - if let width = width, let height = height { // This method exists when you have size, but don't want to set size based on another view, which is the case if you have defined both width and height params + if let width = width, let height = height { // Check if both width and height are defined + // If both width and height are defined, create a size constraint with the specified width and height return Constraint.size(self, size: .init(width: width, height: height), multiplier: multiplier) } else { + // If either width or height is not defined, create a size constraint based on the size of another view or the view itself return Constraint.size(self, to: sizeTo ?? to, width: width, height: height, offset: sizeOffset, multiplier: multiplier) } - }() - return (anchor, size) + }() // Create a size constraint for the view, based on the width, height, sizeTo, and sizeOffset parameters + return (anchor, size) // Return a tuple containing the anchor and size constraints for the view } } /** - * One-liner for `applyAnchor` + * Applies an anchor constraint to the view, with optional parameters for customization. * ## Examples: * view.applyAnchor(to: self, align: .center, alignTo: .center) + * - Remark: This is a one-liner for `applyAnchor`, which is a more customizable method. * - Parameters: - * - to: The instance to apply to - * - align: Alignment for the `to` view - * - alignTo: Alignment for the `sizeTo` view, if one was provided - * - offset: Offset for the `to` parameter - * - useMargin: Aligns to AutoLayout margins or not + * - to: The instance to apply the constraint to. + * - align: The alignment for the `to` view. + * - alignTo: The alignment for the `sizeTo` view, if one was provided. + * - offset: The offset for the `to` parameter. + * - useMargin: Whether to align to AutoLayout margins or not. */ public func applyAnchor(to: View, align: Alignment = .topLeft, alignTo: Alignment = .topLeft, offset: CGPoint = .zero, useMargin: Bool = false) { - self.applyAnchor { _ in - Constraint.anchor(self, to: to, align: align, alignTo: alignTo, offset: offset, useMargin: useMargin) + // Call the more customizable `applyAnchor` method with a closure that defines the anchor constraint + self.applyAnchor { _ in // Call the `applyAnchor` method with a closure that defines the anchor constraint + Constraint.anchor(self, to: to, align: align, alignTo: alignTo, offset: offset, useMargin: useMargin) // Create an anchor constraint for the view } } /** - * One-liner method for the long-hand method self.applySize + * Applies a size constraint to the view, with optional parameters for customization. + * - Remark: This is a one-liner for `applySize`, which is a more customizable method. * ## Examples: * view.applySize(to:self) // multiplier,offset * - Parameters: - * - to: The instance to apply to - * - width: the width to apply to instance - * - height: the height to apply to instance - * - multiplier: multiplies the `size` or `sizeTo` default is (width:1,height:1) - * - offset: offset for the `to` parameter + * - to: The instance to apply the constraint to. + * - width: The width to apply to the view. + * - height: The height to apply to the view. + * - multiplier: The multiplier for the size constraints. + * - offset: The offset for the `to` parameter. */ public func applySize(to: View, width: CGFloat? = nil, height: CGFloat? = nil, offset: CGSize = .zero, multiplier: CGSize = .init(width: 1, height: 1)) { - self.applySize { _ in - Constraint.size(self, to: to, width: width, height: height, offset: offset, multiplier: multiplier) + // Call the more customizable `applySize` method with a closure that defines the size constraint + self.applySize { _ in // Call the `applySize` method with a closure that defines the size constraint + Constraint.size(self, to: to, width: width, height: height, offset: offset, multiplier: multiplier) // Create a size constraint for the view } } } diff --git a/Sources/Spatial/ConstraintKind/ConstraintKind+Apply.swift b/Sources/Spatial/ConstraintKind/ConstraintKind+Apply.swift index 6bd4233..bf24926 100755 --- a/Sources/Spatial/ConstraintKind/ConstraintKind+Apply.swift +++ b/Sources/Spatial/ConstraintKind/ConstraintKind+Apply.swift @@ -5,59 +5,63 @@ import UIKit import Cocoa #endif /** - * Update constraints (For items that are of type `ConstraintKind`) - * - Remark: adding a method called `activateConstraints` doesn't make any sense because you have only anchor and size or either + * Extension for updating constraints on items that are of type `ConstraintKind` and `View`. + * - Remark: Adding a method called `activateConstraints` doesn't make sense because you can only have anchor and size constraints, or either. */ extension ConstraintKind where Self: View { /** - * Activates and sets size and anchor to a `ConstraintKind` - * - Important: ⚠️️ Remember to deactive constraints before calling this method - * - Remark: Same as UIView().activateConstraint... but also sets size and anchor constraints (ConstraintKind) (For animation etc) + * Activates and sets the anchor and size constraints for a `ConstraintKind`. + * - Important: ⚠️️ Remember to deactivate constraints before calling this method. + * - Remark: This method is similar to `UIView().activateConstraint...`, but also sets the size and anchor constraints for animation purposes. + * - Parameters: + * - closure: A closure that returns the anchor and size constraints for the view. * ## Examples: * sliderBar.applyAnchorAndSize { view in * let anchor = Constraint.anchor(view, to: self, align: .topLeft, alignTo: .topLeft) * let size = Constraint.size(view, size: size) * return (anchor: anchor, size: size) // (anchor, size) also works * } - * - Parameter closure: The constraints is returned from the closure */ public func applyAnchorAndSize(closure: AnchorAndSizeClosure) { - self.translatesAutoresizingMaskIntoConstraints = false - let constraints: AnchorAndSize = closure(self) - setConstraint(anchor: constraints.anchor, size: constraints.size) - NSLayoutConstraint.activate([constraints.anchor.x, constraints.anchor.y, constraints.size.w, constraints.size.h]) + self.translatesAutoresizingMaskIntoConstraints = false // Disable the view's translation of autoresizing mask into constraints + let constraints: AnchorAndSize = closure(self) // Call the closure to get the anchor and size constraints for the view + setConstraint(anchor: constraints.anchor, size: constraints.size) // Set the anchor and size constraints for the view + NSLayoutConstraint.activate([constraints.anchor.x, constraints.anchor.y, constraints.size.w, constraints.size.h]) // Activate the anchor and size constraints for the view } /** - * Activates and sets anchor to a `ConstraintKind` - * - Important: ⚠️️ Remember to deactive constraints before calling this method - * - Parameter closure: The constraints is returned from the closure + * Applies an anchor constraint to the view, with optional parameters for customization. + * - Remark: This is a one-liner for `applyAnchorAndSize`, which also sets the size constraints for animation purposes. + * - Parameters: + * - closure: A closure that returns the anchor constraint for the view. + * - Important: ⚠️️ Remember to deactivate constraints before calling this method. */ public func applyAnchor(closure: AnchorClosure) { - self.translatesAutoresizingMaskIntoConstraints = false - let anchorConstraint: AnchorConstraint = closure(self) - let constraints: [NSLayoutConstraint] = [anchorConstraint.x, anchorConstraint.y] - self.anchor = anchorConstraint - NSLayoutConstraint.activate(constraints) + self.translatesAutoresizingMaskIntoConstraints = false // Disable the view's translation of autoresizing mask into constraints + let anchorConstraint: AnchorConstraint = closure(self) // Call the closure to get the anchor constraint for the view + let constraints: [NSLayoutConstraint] = [anchorConstraint.x, anchorConstraint.y] // Create an array of constraints for the view + self.anchor = anchorConstraint // Set the anchor constraint for the view + NSLayoutConstraint.activate(constraints) // Activate the anchor constraints for the view } /** - * Activates and sets size to a `ConstraintKind` - * - Important: ⚠️️ Remember to deactive constraints before calling this method - * - Parameter closure: The constraints is returned from the closure + * Applies a size constraint to the view, with optional parameters for customization. + * - Important: ⚠️️ Remember to deactivate constraints before calling this method. + * - Parameters: + * - closure: A closure that returns the size constraint for the view. */ public func applySize(closure: SizeClosure) { - self.translatesAutoresizingMaskIntoConstraints = false - let sizeConstraint: SizeConstraint = closure(self) - let constraints: [NSLayoutConstraint] = [sizeConstraint.w, sizeConstraint.h] - self.size = sizeConstraint - NSLayoutConstraint.activate(constraints) + self.translatesAutoresizingMaskIntoConstraints = false // Disable the view's translation of autoresizing mask into constraints + let sizeConstraint: SizeConstraint = closure(self) // Call the closure to get the size constraint for the view + let constraints: [NSLayoutConstraint] = [sizeConstraint.w, sizeConstraint.h] // Create an array of constraints for the view + self.size = sizeConstraint // Set the size constraint for the view + NSLayoutConstraint.activate(constraints) // Activate the size constraints for the view } /** - * Sets both anchor and size to a ConstraintKind + * Sets both anchor and size constraints for a `ConstraintKind`. * - Parameters: - * - anchor: constraint anchor - * - size: constraint size + * - anchor: The anchor constraint to set. + * - size: The size constraint to set. */ public func setConstraint(anchor: AnchorConstraint, size: SizeConstraint) { - self.anchorAndSize = (anchor, size) + self.anchorAndSize = (anchor, size) // Set the anchor and size constraints for the view } } diff --git a/Sources/Spatial/ConstraintKind/ConstraintKind+Bulk.swift b/Sources/Spatial/ConstraintKind/ConstraintKind+Bulk.swift index fa56524..bb452fa 100644 --- a/Sources/Spatial/ConstraintKind/ConstraintKind+Bulk.swift +++ b/Sources/Spatial/ConstraintKind/ConstraintKind+Bulk.swift @@ -9,80 +9,82 @@ import Cocoa */ extension Array where Element: ConstraintKind.ViewConstraintKind { /** - * Apply constraints on an array of UIViewConstraintKind - * - Remark: Alternativly you can do: views.enumerated().map{Constraint.anchor($0.1, to: self, align: .topLeft, alignTo:.topLeft,offset:CGPoint(x:0,y:48 * $0.0))} etc - * - Remark: If you want to apply only anchors or only sizes then just pass an empty array for either + * Applies anchor and size constraints to an array of `UIViewConstraintKind`. + * - Remark: If you want to apply only anchors or only sizes then just pass an empty array for either. + * - Parameters: + * - closure: A closure that returns the anchor and size constraints for the views. * ## Examples: * [label1, label2, label3].applyAnchorsAndSizes { views in * let anchors = [] // Use Constraint.distribute * let sizes = [] // Use views.map { Constraint.size } * return (anchors, sizes) * } - * - Parameter closure: The constraints is returned from the closure */ public func applyAnchorsAndSizes(closure: AnchorAndSizeClosure) { - self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } - let constraints: AnchorConstraintsAndSizeConstraints = closure(self) - self.enumerated().forEach { - let anchor: AnchorConstraint = constraints.anchorConstraints[$0.offset] - let size: SizeConstraint = constraints.sizeConstraints[$0.offset] - $0.element.setConstraint(anchor: anchor, size: size) + self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } // Disable the translation of autoresizing mask into constraints for each view in the array + let constraints: AnchorConstraintsAndSizeConstraints = closure(self) // Call the closure to get the anchor and size constraints for the views + self.enumerated().forEach { // Loop through each view in the array, along with its index + let anchor: AnchorConstraint = constraints.anchorConstraints[$0.offset] // Get the anchor constraint for the view at the current index + let size: SizeConstraint = constraints.sizeConstraints[$0.offset] // Get the size constraint for the view at the current index + $0.element.setConstraint(anchor: anchor, size: size) // Set the anchor and size constraints for the view at the current index } - let layoutConstraints: [NSLayoutConstraint] = { - let anchors: [NSLayoutConstraint] = constraints.anchorConstraints.reduce([]) { $0 + [$1.x, $1.y] } - let sizes: [NSLayoutConstraint] = constraints.sizeConstraints.reduce([]) { $0 + [$1.w, $1.h] } - return anchors + sizes + let layoutConstraints: [NSLayoutConstraint] = { // Create an array of layout constraints + let anchors: [NSLayoutConstraint] = constraints.anchorConstraints.reduce([]) { $0 + [$1.x, $1.y] } // Create an array of anchor constraints + let sizes: [NSLayoutConstraint] = constraints.sizeConstraints.reduce([]) { $0 + [$1.w, $1.h] } // Create an array of size constraints + return anchors + sizes // Concatenate the arrays of anchor and size constraints }() - NSLayoutConstraint.activate(layoutConstraints) + NSLayoutConstraint.activate(layoutConstraints) // Activate the layout constraints for the views in the array } /** - * Apply sizes - * - Description: Same as `applyAnchorsAndSizes` but just for sizes - * - Parameter closure: The constraints is returned from the closure + * Applies size constraints to an array of `UIViewConstraintKind`. + * - Description: Same as `applyAnchorsAndSizes` but just for sizes. + * - Parameters: + * - closure: A closure that returns the size constraints for the views. */ public func applySizes(closure: SizesClosure) { - self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } - let constraints: [SizeConstraint] = closure(self) - self.enumerated().forEach { - let size: SizeConstraint = constraints[$0.offset] - $0.element.size = size + self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } // Disable the translation of autoresizing mask into constraints for each view in the array + let constraints: [SizeConstraint] = closure(self) // Call the closure to get the size constraints for the views + self.enumerated().forEach { // Loop through each view in the array, along with its index + let size: SizeConstraint = constraints[$0.offset] // Get the size constraint for the view at the current index + $0.element.size = size // Set the size constraint for the view at the current index } - let layoutConstraints: [NSLayoutConstraint] = constraints.reduce([]) { $0 + [$1.w, $1.h] } - NSLayoutConstraint.activate(layoutConstraints) + let layoutConstraints: [NSLayoutConstraint] = constraints.reduce([]) { $0 + [$1.w, $1.h] } // Create an array of layout constraints + NSLayoutConstraint.activate(layoutConstraints) // Activate the layout constraints for the views in the array } /** - * Apply anchors - * - Description: Same as `applyAnchorsAndSizes` but just for anchors - * - Parameter closure: The constraints is returned from the closure + * Applies anchor constraints to an array of `UIViewConstraintKind`. + * - Description: Same as `applyAnchorsAndSizes` but just for anchors. + * - Parameters: + * - closure: A closure that returns the anchor constraints for the views. */ public func applyAnchors(closure: AnchorClosure) { - self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } - let constraints: [AnchorConstraint] = closure(self) - self.enumerated().forEach { - let anchor: AnchorConstraint = constraints[$0.offset] - $0.element.anchor = anchor + self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } // Disable the translation of autoresizing mask into constraints for each view in the array + let constraints: [AnchorConstraint] = closure(self) // Call the closure to get the anchor constraints for the views + self.enumerated().forEach { // Loop through each view in the array, along with its index + let anchor: AnchorConstraint = constraints[$0.offset] // Get the anchor constraint for the view at the current index + $0.element.anchor = anchor // Set the anchor constraint for the view at the current index } - let layoutConstraints: [NSLayoutConstraint] = constraints.reduce([]) { $0 + [$1.x, $1.y] } - NSLayoutConstraint.activate(layoutConstraints) + let layoutConstraints: [NSLayoutConstraint] = constraints.reduce([]) { $0 + [$1.x, $1.y] } // Create an array of layout constraints + NSLayoutConstraint.activate(layoutConstraints) // Activate the layout constraints for the views in the array } /** - * Apply anchors (axis) - * - Description: Same as `applyAnchorsAndSizes` but just for horizontal or vertical anchor + * Applies horizontal or vertical anchor constraints to an array of `UIViewConstraintKind`. + * - Description: Same as `applyAnchorsAndSizes` but just for horizontal or vertical anchor. * - Parameters: - * - axis: hor or ver - * - closure: The constraints is returned from the closure + * - axis: The axis to apply the anchor constraints to (`hor` for horizontal, `ver` for vertical). + * - closure: A closure that returns the anchor constraints for the views. */ public func applyAnchors(axis: Axis, closure: AxisClosure) { - self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } - let constraints: [NSLayoutConstraint] = closure(self) - self.enumerated().forEach { - let anchor: NSLayoutConstraint = constraints[$0.offset] + self.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } // Disable the translation of autoresizing mask into constraints for each view in the array + let constraints: [NSLayoutConstraint] = closure(self) // Call the closure to get the anchor constraints for the views + self.enumerated().forEach { // Loop through each view in the array, along with its index + let anchor: NSLayoutConstraint = constraints[$0.offset] // Get the anchor constraint for the view at the current index switch axis { - case .hor: $0.element.anchor?.x = anchor - case .ver: $0.element.anchor?.y = anchor + case .hor: $0.element.anchor?.x = anchor // Set the horizontal anchor constraint for the view at the current index + case .ver: $0.element.anchor?.y = anchor // Set the vertical anchor constraint for the view at the current index } } - let layoutConstraints: [NSLayoutConstraint] = constraints.reduce([]) { $0 + [$1] } - NSLayoutConstraint.activate(layoutConstraints) + let layoutConstraints: [NSLayoutConstraint] = constraints.reduce([]) { $0 + [$1] } // Create an array of layout constraints + NSLayoutConstraint.activate(layoutConstraints) // Activate the layout constraints for the views in the array } } diff --git a/Sources/Spatial/ConstraintKind/ConstraintKind.swift b/Sources/Spatial/ConstraintKind/ConstraintKind.swift index 9d86fb7..afec542 100644 --- a/Sources/Spatial/ConstraintKind/ConstraintKind.swift +++ b/Sources/Spatial/ConstraintKind/ConstraintKind.swift @@ -1,8 +1,8 @@ import Foundation /** - * `UIView` and `NSView` classes that implement this protocol are able to store the anchor and size constraints - * - Remark: Use `anchorAndSize` as a variable, anchor and size is part of legacy API, and will be deprecated - * - Remark: Storing Constraints is a must if you want to change the constraints at a later point in time, for isntance for animation + * `UIView` and `NSView` classes that implement this protocol are able to store the anchor and size constraints. + * - Remark: Use `anchorAndSize` as a variable, anchor and size are part of the legacy API and will be deprecated. + * - Remark: Storing constraints is necessary if you want to change the constraints at a later point in time, for instance for animation. */ public protocol ConstraintKind: AnyObject { // @available(*, deprecated, renamed: "anchorAndSize") diff --git a/Sources/Spatial/ConstraintKind/ConstraintView/ConstraintView.swift b/Sources/Spatial/ConstraintKind/ConstraintView/ConstraintView.swift index 433b5d8..5d27ab8 100644 --- a/Sources/Spatial/ConstraintKind/ConstraintView/ConstraintView.swift +++ b/Sources/Spatial/ConstraintKind/ConstraintView/ConstraintView.swift @@ -1,7 +1,8 @@ import Foundation /** - * - Remark: Convenient `UIView so you don't have to add anchor and size your self + * A convenient `UIView` subclass that automatically adds anchor and size constraints. + * - Note: To use this class, the view must implement the `ConstraintKind` protocol and set the `anchorAndSize` property. */ open class ConstraintView: View, ConstraintKind { - public var anchorAndSize: AnchorAndSize? + public var anchorAndSize: AnchorAndSize? // The anchor and size constraints for the view }