From 09f254c91fb9acd4904c6ce344eb57e1bb24dcef Mon Sep 17 00:00:00 2001 From: Dongkyu Kim Date: Tue, 16 May 2023 21:11:45 +0900 Subject: [PATCH 1/5] Add `isIncludedInPinLayoutSizeCalculation` property to `Layoutable` --- Sources/Extensions/CALayer+PinLayout.swift | 13 +++++++++++++ Sources/Extensions/NSView+PinLayout.swift | 13 +++++++++++++ Sources/Extensions/UIView+PinLayout.swift | 10 ++++++++++ Sources/Layoutable.swift | 13 +++++++++++++ 4 files changed, 49 insertions(+) diff --git a/Sources/Extensions/CALayer+PinLayout.swift b/Sources/Extensions/CALayer+PinLayout.swift index 7eb92be..698e610 100644 --- a/Sources/Extensions/CALayer+PinLayout.swift +++ b/Sources/Extensions/CALayer+PinLayout.swift @@ -20,6 +20,10 @@ import QuartzCore extension CALayer: Layoutable { + private struct pinlayoutAssociatedKeys { + static var pinlayoutIsIncludedInPinLayoutSizeCalculation = UnsafeMutablePointer.allocate(capacity: 1) + } + public typealias PinView = CALayer public var superview: CALayer? { @@ -38,6 +42,15 @@ extension CALayer: Layoutable { return PinLayout(view: self, keepTransform: false) } + public var isIncludedInPinLayoutSizeCalculation: Bool { + get { + return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation) as? Bool ?? true + } + set { + objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + public func getRect(keepTransform: Bool) -> CGRect { if keepTransform { /* diff --git a/Sources/Extensions/NSView+PinLayout.swift b/Sources/Extensions/NSView+PinLayout.swift index ee81f9a..0b55fe5 100644 --- a/Sources/Extensions/NSView+PinLayout.swift +++ b/Sources/Extensions/NSView+PinLayout.swift @@ -23,6 +23,10 @@ import Foundation import AppKit extension NSView: Layoutable { + private struct pinlayoutAssociatedKeys { + static var pinlayoutIsIncludedInPinLayoutSizeCalculation = UnsafeMutablePointer.allocate(capacity: 1) + } + public typealias PinView = NSView public var pin: PinLayout { @@ -37,6 +41,15 @@ extension NSView: Layoutable { return PinLayoutObjCImpl(view: self, keepTransform: true) } + public var isIncludedInPinLayoutSizeCalculation: Bool { + get { + return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation) as? Bool ?? true + } + set { + objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + public func getRect(keepTransform: Bool) -> CGRect { if let superview = superview, !superview.isFlipped { var flippedRect = frame diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift index 1a9c144..dbb8150 100644 --- a/Sources/Extensions/UIView+PinLayout.swift +++ b/Sources/Extensions/UIView+PinLayout.swift @@ -37,6 +37,15 @@ extension UIView: Layoutable, SizeCalculable { return PinLayoutObjCImpl(view: self, keepTransform: true) } + public var isIncludedInPinLayoutSizeCalculation: Bool { + get { + return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation) as? Bool ?? true + } + set { + objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + public func getRect(keepTransform: Bool) -> CGRect { guard !Pin.autoSizingInProgress || autoSizingRect == nil else { return autoSizingRect ?? CGRect.zero } @@ -95,6 +104,7 @@ extension UIView: Layoutable, SizeCalculable { extension UIView: AutoSizeCalculable { private struct pinlayoutAssociatedKeys { + static var pinlayoutIsIncludedInPinLayoutSizeCalculation = UnsafeMutablePointer.allocate(capacity: 1) static var pinlayoutAutoSizingRect = UnsafeMutablePointer.allocate(capacity: 1) static var pinlayoutAutoSizingRectWithMargins = UnsafeMutablePointer.allocate(capacity: 1) } diff --git a/Sources/Layoutable.swift b/Sources/Layoutable.swift index fa4e996..d1fd835 100644 --- a/Sources/Layoutable.swift +++ b/Sources/Layoutable.swift @@ -29,6 +29,13 @@ public protocol Layoutable: AnyObject, Equatable, CustomDebugStringConvertible { var superview: PinView? { get } var subviews: [PinView] { get } + /// A Boolean value that determines whether the view is included in the PinLayout's size calculation. + /// + /// An excluded view does not take up space in the layout + /// when using `wrapContent(_:padding:_:)` or `autoSizeThatFits(_:layoutClosure:)`. + /// The default value is `true`. + var isIncludedInPinLayoutSizeCalculation: Bool { get set } + func getRect(keepTransform: Bool) -> CGRect func setRect(_ rect: CGRect, keepTransform: Bool) @@ -36,3 +43,9 @@ public protocol Layoutable: AnyObject, Equatable, CustomDebugStringConvertible { func isLTR() -> Bool } + +extension Layoutable { + var subviewsIncludedInSizeCalculation: [PinView] { + return subviews.filter(\.isIncludedInPinLayoutSizeCalculation) + } +} From ec85f63b84af3f62a64e14052c0d43119136fe10 Mon Sep 17 00:00:00 2001 From: Dongkyu Kim Date: Tue, 16 May 2023 21:11:56 +0900 Subject: [PATCH 2/5] Use `subviewsIncludedInSizeCalculation` in `autoSizeThatFits(_:layoutClosure:)` --- Sources/Extensions/UIView+PinLayout.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift index dbb8150..9188f83 100644 --- a/Sources/Extensions/UIView+PinLayout.swift +++ b/Sources/Extensions/UIView+PinLayout.swift @@ -143,7 +143,7 @@ extension UIView: AutoSizeCalculable { layoutClosure() - let boundingRect = subviews.compactMap({ $0.autoSizingRectWithMargins }).reduce(CGRect.zero) { (result: CGRect, autoSizingRect: CGRect) -> CGRect in + let boundingRect = subviewsIncludedInSizeCalculation.compactMap({ $0.autoSizingRectWithMargins }).reduce(CGRect.zero) { (result: CGRect, autoSizingRect: CGRect) -> CGRect in return result.union(autoSizingRect) } From d9a76af637048ee3db0a2c4def4a424ca681994d Mon Sep 17 00:00:00 2001 From: Dongkyu Kim Date: Tue, 16 May 2023 21:10:41 +0900 Subject: [PATCH 3/5] Use `subviewsIncludedInSizeCalculation` in `wrapContent(_:padding:_:)` --- Sources/PinLayout+WrapContent.swift | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/PinLayout+WrapContent.swift b/Sources/PinLayout+WrapContent.swift index e58731c..be59757 100644 --- a/Sources/PinLayout+WrapContent.swift +++ b/Sources/PinLayout+WrapContent.swift @@ -25,7 +25,7 @@ import AppKit extension PinLayout { /** - Adjust the view's width & height to wrap all its subviews. The method also adjust subviews position to create a tight wrap. + Adjust the view's width & height to wrap all its subviews that are included in the size calculation. The method also adjust subviews position to create a tight wrap. */ @discardableResult public func wrapContent() -> PinLayout { @@ -33,7 +33,7 @@ extension PinLayout { } /** - Adjust the view's width & height to wrap all its subviews. The method also adds a padding around all subviews. + Adjust the view's width & height to wrap all its subviews that are included in the size calculation. The method also adds a padding around all subviews. - Parameters: - padding: Specify a padding value. @@ -45,7 +45,7 @@ extension PinLayout { /** The method... - - Adjust the view's width and height to wrap all its subviews. + - Adjust the view's width and height to wrap all its subviews that are included in the size calculation. - Adjust subviews's position to create a tight wrap. - Apply padding around all subviews. @@ -59,7 +59,7 @@ extension PinLayout { /** The method... - - Adjust the view's width and height to wrap all its subviews. + - Adjust the view's width and height to wrap all its subviews that are included in the size calculation. - Adjust subviews's position to create a tight wrap. - Parameters: @@ -72,7 +72,7 @@ extension PinLayout { /** The method... - - Adjust the view's width and height to wrap all its subviews. + - Adjust the view's width and height to wrap all its subviews that are included in the size calculation. - Adjust subviews's position to create a tight wrap. - Apply padding around all subviews. @@ -87,7 +87,7 @@ extension PinLayout { /** The method... - - Adjust the view's width and height to wrap all its subviews. + - Adjust the view's width and height to wrap all its subviews that are included in the size calculation. - Adjust subviews's position to create a tight wrap. - Apply padding around all subviews. @@ -101,11 +101,11 @@ extension PinLayout { } private func wrapContent(_ type: WrapType, padding: PEdgeInsets, _ context: Context) -> PinLayout { - let subviews = view.subviews - guard !subviews.isEmpty else { return self } + let includedSubviews = view.subviewsIncludedInSizeCalculation + guard !includedSubviews.isEmpty else { return self } - let firstViewRect = subviews[0].getRect(keepTransform: keepTransform) - let boundingRect = subviews.reduce(firstViewRect, { (result, view) in + let firstViewRect = includedSubviews[0].getRect(keepTransform: keepTransform) + let boundingRect = includedSubviews.reduce(firstViewRect, { (result, view) in result.union(view.getRect(keepTransform: keepTransform)) }) @@ -131,7 +131,7 @@ extension PinLayout { } if offsetDx != 0 || offsetDy != 0 { - subviews.forEach { (view) in + includedSubviews.forEach { (view) in let viewRect = view.getRect(keepTransform: keepTransform) let newRect = viewRect.offsetBy(dx: offsetDx, dy: offsetDy) view.setRect(newRect, keepTransform: keepTransform) From 38bbd92fbd8ef3bab56b8eee87bad7ef3374e027 Mon Sep 17 00:00:00 2001 From: Dongkyu Kim Date: Tue, 16 May 2023 21:11:02 +0900 Subject: [PATCH 4/5] Update documentation --- README.md | 6 +++--- Sources/Types.swift | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 47045d2..30d1a75 100644 --- a/README.md +++ b/README.md @@ -1367,17 +1367,17 @@ The property expose the `UIKit` value [`UIView.keyboardLayoutGuide`](https://dev ## WrapContent -The following methods are useful to adjust view's width and/or height to wrap all its subviews. These methods also adjust subviews position to create a tight wrap. +The following methods are useful to adjust view's width and/or height to wrap all its subviews that are included in the layout. These methods also adjust subviews position to create a tight wrap. **Methods:** * **`wrapContent()`** **`wrapContent(padding: CGFloat)`** **`wrapContent(padding: UIEdgeInsets)`** -Adjust the view's width and height to wrap all its subviews. The method also adjusts subviews's position to create a tight wrap. It is also possible to specify an optional padding around all subviews. +Adjust the view's width and height to wrap all its subviews that are included in the layout. The method also adjusts subviews's position to create a tight wrap. It is also possible to specify an optional padding around all subviews. * **`wrapContent(:WrapType)`** **`wrapContent(:WrapType, padding: CGFloat)`** **`wrapContent(:WrapType, padding: UIEdgeInsets)`** -Adjust the view's width AND/OR height to wrap all its subviews. Accept a WrapType parameter to define the wrapping type. It is also possible to specify an optional padding around all subviews. +Adjust the view's width AND/OR height to wrap all its subviews that are included in the layout. Accept a WrapType parameter to define the wrapping type. It is also possible to specify an optional padding around all subviews. **Types:** diff --git a/Sources/Types.swift b/Sources/Types.swift index 90ab6bb..1635999 100644 --- a/Sources/Types.swift +++ b/Sources/Types.swift @@ -186,11 +186,11 @@ public enum FitType { } @objc public enum WrapType: Int { - /// Adjust the view's width AND height to wrap all its subviews. + /// Adjust the view's width AND height to wrap all its subviews that are included in the size calculation. case all - /// Adjust only the view's width to wrap all its subviews. The view's height won't be modified. + /// Adjust only the view's width to wrap all its subviews that are included in the size calculation. The view's height won't be modified. case horizontally - /// Adjust only the view's height to wrap all its subviews. The view's width won't be modified. + /// Adjust only the view's height to wrap all its subviews that are included in the size calculation. The view's width won't be modified. case vertically } From 7afd8968820c73d5fffae9a778d2370b87e29f4f Mon Sep 17 00:00:00 2001 From: Dongkyu Kim Date: Tue, 16 May 2023 22:40:13 +0900 Subject: [PATCH 5/5] `isIncludedInPinLayoutSizeCalculation` -> `pin.isIncludedInSizeCalculation` --- .DS_Store | Bin 0 -> 6148 bytes Sources/Extensions/CALayer+PinLayout.swift | 13 ------------ Sources/Extensions/NSView+PinLayout.swift | 13 ------------ Sources/Extensions/UIView+PinLayout.swift | 10 --------- Sources/Layoutable.swift | 23 ++++++++++++++------- Sources/PinLayout.swift | 10 +++++++++ 6 files changed, 25 insertions(+), 44 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..16e143c8bcd0f2d52d78ef15fbecc042518ad013 GIT binary patch literal 6148 zcmeHKO-jQ+6#k}mk>aKx1((4C2)#ipapyuPxVC?&wK1Vu)LjnZ#>2R9?FC$TfF8l` z%?vRi7L0<3ya#W-$;`Z&eBVG`9sn~~P5VF>KtLC4b=Z7jGA~}UmLHKxWA_;09w}D1 z!G3ME4*W$0<| zZ?E&`m(J5clj!LWqO.allocate(capacity: 1) - } - public typealias PinView = CALayer public var superview: CALayer? { @@ -42,15 +38,6 @@ extension CALayer: Layoutable { return PinLayout(view: self, keepTransform: false) } - public var isIncludedInPinLayoutSizeCalculation: Bool { - get { - return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation) as? Bool ?? true - } - set { - objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) - } - } - public func getRect(keepTransform: Bool) -> CGRect { if keepTransform { /* diff --git a/Sources/Extensions/NSView+PinLayout.swift b/Sources/Extensions/NSView+PinLayout.swift index 0b55fe5..ee81f9a 100644 --- a/Sources/Extensions/NSView+PinLayout.swift +++ b/Sources/Extensions/NSView+PinLayout.swift @@ -23,10 +23,6 @@ import Foundation import AppKit extension NSView: Layoutable { - private struct pinlayoutAssociatedKeys { - static var pinlayoutIsIncludedInPinLayoutSizeCalculation = UnsafeMutablePointer.allocate(capacity: 1) - } - public typealias PinView = NSView public var pin: PinLayout { @@ -41,15 +37,6 @@ extension NSView: Layoutable { return PinLayoutObjCImpl(view: self, keepTransform: true) } - public var isIncludedInPinLayoutSizeCalculation: Bool { - get { - return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation) as? Bool ?? true - } - set { - objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) - } - } - public func getRect(keepTransform: Bool) -> CGRect { if let superview = superview, !superview.isFlipped { var flippedRect = frame diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift index 9188f83..d6a7e10 100644 --- a/Sources/Extensions/UIView+PinLayout.swift +++ b/Sources/Extensions/UIView+PinLayout.swift @@ -37,15 +37,6 @@ extension UIView: Layoutable, SizeCalculable { return PinLayoutObjCImpl(view: self, keepTransform: true) } - public var isIncludedInPinLayoutSizeCalculation: Bool { - get { - return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation) as? Bool ?? true - } - set { - objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInPinLayoutSizeCalculation, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) - } - } - public func getRect(keepTransform: Bool) -> CGRect { guard !Pin.autoSizingInProgress || autoSizingRect == nil else { return autoSizingRect ?? CGRect.zero } @@ -104,7 +95,6 @@ extension UIView: Layoutable, SizeCalculable { extension UIView: AutoSizeCalculable { private struct pinlayoutAssociatedKeys { - static var pinlayoutIsIncludedInPinLayoutSizeCalculation = UnsafeMutablePointer.allocate(capacity: 1) static var pinlayoutAutoSizingRect = UnsafeMutablePointer.allocate(capacity: 1) static var pinlayoutAutoSizingRectWithMargins = UnsafeMutablePointer.allocate(capacity: 1) } diff --git a/Sources/Layoutable.swift b/Sources/Layoutable.swift index d1fd835..cb70407 100644 --- a/Sources/Layoutable.swift +++ b/Sources/Layoutable.swift @@ -29,13 +29,6 @@ public protocol Layoutable: AnyObject, Equatable, CustomDebugStringConvertible { var superview: PinView? { get } var subviews: [PinView] { get } - /// A Boolean value that determines whether the view is included in the PinLayout's size calculation. - /// - /// An excluded view does not take up space in the layout - /// when using `wrapContent(_:padding:_:)` or `autoSizeThatFits(_:layoutClosure:)`. - /// The default value is `true`. - var isIncludedInPinLayoutSizeCalculation: Bool { get set } - func getRect(keepTransform: Bool) -> CGRect func setRect(_ rect: CGRect, keepTransform: Bool) @@ -44,8 +37,22 @@ public protocol Layoutable: AnyObject, Equatable, CustomDebugStringConvertible { func isLTR() -> Bool } +private struct pinlayoutAssociatedKeys { + static var pinlayoutIsIncludedInSizeCalculation = UnsafeMutablePointer.allocate(capacity: 1) +} + extension Layoutable { + + var isIncludedInSizeCalculation: Bool { + get { + return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInSizeCalculation) as? Bool ?? true + } + set { + objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutIsIncludedInSizeCalculation, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + var subviewsIncludedInSizeCalculation: [PinView] { - return subviews.filter(\.isIncludedInPinLayoutSizeCalculation) + return subviews.filter(\.isIncludedInSizeCalculation) } } diff --git a/Sources/PinLayout.swift b/Sources/PinLayout.swift index 33d79e3..41b78ef 100644 --- a/Sources/PinLayout.swift +++ b/Sources/PinLayout.swift @@ -84,6 +84,16 @@ public class PinLayout { apply() } + /// A Boolean value that determines whether the view is included in the PinLayout's size calculation. + /// + /// An excluded view does not take up space in the layout + /// when using `wrapContent(_:padding:_:)` or `autoSizeThatFits(_:layoutClosure:)`. + /// The default value is `true`. + public var isIncludedInSizeCalculation: Bool { + get { return view.isIncludedInSizeCalculation } + set { view.isIncludedInSizeCalculation = newValue } + } + #if os(iOS) || os(tvOS) public var safeArea: PEdgeInsets { if let view = view as? UIView {