From 666ba1a9cf088b98eaf848d65c8aa41b26f39729 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Sun, 27 May 2018 07:44:36 -0400 Subject: [PATCH 1/5] Initial commit --- Example/.swiftlint.yml | 1 + PinLayout.xcodeproj/project.pbxproj | 40 ++- .../contents.xcworkspacedata | 3 - Podfile.lock | 4 +- Sources/Filters.swift | 28 +++ Sources/Impl/PinLayoutImpl+Layouting.swift | 2 +- Sources/Impl/PinLayoutImpl+WrapContent.swift | 98 ++++++++ Sources/Impl/PinLayoutImpl.swift | 16 +- Sources/Impl/TypesImpl.swift | 41 ---- Sources/Pin.swift | 18 -- Sources/PinLayout.swift | 153 +----------- Sources/Types+Description.swift | 62 +++++ Sources/Types.swift | 229 ++++++++++++++++++ Sources/UIView+PinLayout.swift | 1 + Tests/Common/WrapContentSpec.swift | 216 +++++++++++++++++ 15 files changed, 679 insertions(+), 233 deletions(-) create mode 100644 Sources/Filters.swift create mode 100644 Sources/Impl/PinLayoutImpl+WrapContent.swift create mode 100644 Sources/Types+Description.swift create mode 100644 Sources/Types.swift create mode 100644 Tests/Common/WrapContentSpec.swift diff --git a/Example/.swiftlint.yml b/Example/.swiftlint.yml index 0df8a810..adee2693 100644 --- a/Example/.swiftlint.yml +++ b/Example/.swiftlint.yml @@ -24,3 +24,4 @@ disabled_rules: # rule identifiers to exclude from running excluded: # paths to ignore during linting. overridden by `included`. - Pods + - PinLayoutExampleMacOS \ No newline at end of file diff --git a/PinLayout.xcodeproj/project.pbxproj b/PinLayout.xcodeproj/project.pbxproj index 4dcefc0d..d8a6f080 100644 --- a/PinLayout.xcodeproj/project.pbxproj +++ b/PinLayout.xcodeproj/project.pbxproj @@ -47,9 +47,9 @@ 2482908C1E78CFFC00667D08 /* RelativePositionSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */; }; 248E4C741F7A883800C0E7F7 /* AspectRatioTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */; }; 248E4C771F7A88D200C0E7F7 /* UIImage+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */; }; - 24949A2E1EF69474003643D3 /* PinLayout+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */; }; + 24949A2E1EF69474003643D3 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* Filters.swift */; }; 249EFE841E64FB4C00165E39 /* PinLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 249EFE7A1E64FB4C00165E39 /* PinLayout.framework */; }; - 24B02B091F2A713000C18179 /* PinLayout+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */; }; + 24B02B091F2A713000C18179 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* Filters.swift */; }; 24B02B0A1F2A713300C18179 /* PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */; }; 24D18D171F3B4381008129EF /* RTLSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D151F3B42E0008129EF /* RTLSpec.swift */; }; 24D18D241F3E37DD008129EF /* Pin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D231F3E37DD008129EF /* Pin.swift */; }; @@ -62,7 +62,7 @@ DF1A5D352084CFC100725EF5 /* NSView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */; }; DF1A5D362084CFC100725EF5 /* NSView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */; }; DF1A5D372084CFC200725EF5 /* NSView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */; }; - DF1A5D382084CFC600725EF5 /* PinLayout+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */; }; + DF1A5D382084CFC600725EF5 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2D1EF69474003643D3 /* Filters.swift */; }; DF1A5D392084CFC600725EF5 /* Pin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D231F3E37DD008129EF /* Pin.swift */; }; DF1A5D3A2084CFC600725EF5 /* UIView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */; }; DF1A5D3B2084CFD600725EF5 /* PinLayoutImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6C61FC37C1C0054CADD /* PinLayoutImpl.swift */; }; @@ -106,6 +106,14 @@ DFF222B220B877F600AC2A84 /* PinLayoutObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277B1F8E958F00B1AD39 /* PinLayoutObjC.swift */; }; DFF222B320B877F800AC2A84 /* PinLayoutObjCImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277C1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift */; }; DFF222B420B877F900AC2A84 /* PinLayoutObjCImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277C1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift */; }; + DFF222C920B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */; }; + DFF222CA20B9994200AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */; }; + DFF222CB20B9994300AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */; }; + DFF222CD20B999BD00AC2A84 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CC20B999BD00AC2A84 /* Types.swift */; }; + DFF222CF20B99A6600AC2A84 /* Types+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CE20B99A6600AC2A84 /* Types+Description.swift */; }; + DFF222E320BACBBF00AC2A84 /* WrapContentSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */; }; + DFF222E420BACBC000AC2A84 /* WrapContentSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */; }; + DFF222E520BACBC000AC2A84 /* WrapContentSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */; }; DFF6F9C72084DCD3004F5AED /* PinLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244DF2F81EF46C500090508B /* PinLayout.framework */; }; DFF6F9CD2084E15A004F5AED /* BasicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C5011E75D88500073BEE /* BasicView.swift */; }; DFF6F9CE2084E15A004F5AED /* AdjustSizeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C4FF1E75D74000073BEE /* AdjustSizeSpec.swift */; }; @@ -188,7 +196,7 @@ 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativePositionSpec.swift; sourceTree = ""; }; 248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AspectRatioTests.swift; sourceTree = ""; }; 248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Color.swift"; sourceTree = ""; }; - 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PinLayout+Filters.swift"; sourceTree = ""; }; + 24949A2D1EF69474003643D3 /* Filters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Filters.swift; sourceTree = ""; }; 249EFE7A1E64FB4C00165E39 /* PinLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PinLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 249EFE831E64FB4C00165E39 /* PinLayoutTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PinLayoutTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 249EFE8A1E64FB4C00165E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Common/Info.plist; sourceTree = ""; }; @@ -216,6 +224,10 @@ DFB3ECB02061602E005F226B /* PinSafeArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PinSafeArea.swift; path = Impl/PinSafeArea.swift; sourceTree = ""; }; DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PinLayout.swift; sourceTree = ""; }; DFCA5F1420111BCF00180CD7 /* UIScrollViewSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIScrollViewSpec.swift; sourceTree = ""; }; + DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "PinLayoutImpl+WrapContent.swift"; path = "Impl/PinLayoutImpl+WrapContent.swift"; sourceTree = ""; }; + DFF222CC20B999BD00AC2A84 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; }; + DFF222CE20B99A6600AC2A84 /* Types+Description.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Types+Description.swift"; sourceTree = ""; }; + DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WrapContentSpec.swift; sourceTree = ""; }; DFF6F9C22084DCD3004F5AED /* PinLayoutTests-tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PinLayoutTests-tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -327,9 +339,10 @@ 249EFE7C1E64FB4C00165E39 /* Sources */ = { isa = PBXGroup; children = ( + 24949A2D1EF69474003643D3 /* Filters.swift */, DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */, - 24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */, 24D18D231F3E37DD008129EF /* Pin.swift */, + DFF222CC20B999BD00AC2A84 /* Types.swift */, DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */, DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */, DFA06B031E8B38B300B6D5E7 /* Impl */, @@ -382,10 +395,12 @@ 2475B6C41FC37A900054CADD /* PinLayoutImpl+Layouting.swift */, 2475B6C91FC37C1C0054CADD /* PinLayoutImpl+Relative.swift */, 2475B6C81FC37C1C0054CADD /* PinLayoutImpl+Warning.swift */, + DFF222C820B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift */, DFB3ECB02061602E005F226B /* PinSafeArea.swift */, 2475B6D21FC37CD40054CADD /* Coordinates.swift */, 243C620E1FC3834B0082C327 /* Percent.swift */, 2475B6CE1FC37C570054CADD /* TypesImpl.swift */, + DFF222CE20B99A6600AC2A84 /* Types+Description.swift */, 2475B6D01FC37C8C0054CADD /* UIView+LTR.swift */, ); name = Impl; @@ -407,6 +422,7 @@ 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */, 242E8DC11EED5982005935FB /* RelativePositionMultipleViewsSpec.swift */, 240F88BF1F0C1ED900280FC8 /* WarningSpec.swift */, + DFF222E120BACBA800AC2A84 /* WrapContentSpec.swift */, ); path = Common; sourceTree = ""; @@ -797,10 +813,11 @@ DF1A5D362084CFC100725EF5 /* NSView+PinLayout.swift in Sources */, 243C62041FC37F680082C327 /* PinLayoutImpl.swift in Sources */, 243C62071FC37F6C0082C327 /* PinLayoutImpl+Relative.swift in Sources */, + DFF222CB20B9994300AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, 243B12BC1FC393580072A9C3 /* Percent.swift in Sources */, DFB3ECB72062A937005F226B /* PinSafeArea.swift in Sources */, DF1A5D0420812DE100725EF5 /* UIView+PinLayout.swift in Sources */, - 24B02B091F2A713000C18179 /* PinLayout+Filters.swift in Sources */, + 24B02B091F2A713000C18179 /* Filters.swift in Sources */, 24B02B0A1F2A713300C18179 /* PinLayout.swift in Sources */, 243C620B1FC37F6C0082C327 /* UIView+LTR.swift in Sources */, 243C62091FC37F6C0082C327 /* Coordinates.swift in Sources */, @@ -816,11 +833,14 @@ files = ( 24D18D241F3E37DD008129EF /* Pin.swift in Sources */, 2475B6CA1FC37C1C0054CADD /* PinLayoutImpl.swift in Sources */, + DFF222CF20B99A6600AC2A84 /* Types+Description.swift in Sources */, 241A277E1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift in Sources */, DF1A5D372084CFC200725EF5 /* NSView+PinLayout.swift in Sources */, + DFF222CD20B999BD00AC2A84 /* Types.swift in Sources */, 243C620F1FC3834B0082C327 /* Percent.swift in Sources */, 2475B6CB1FC37C1C0054CADD /* PinLayoutImpl+Coordinates.swift in Sources */, 2475B6C51FC37A900054CADD /* PinLayoutImpl+Layouting.swift in Sources */, + DFF222C920B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, 2475B6CF1FC37C570054CADD /* TypesImpl.swift in Sources */, 2475B6D11FC37C8C0054CADD /* UIView+LTR.swift in Sources */, DFC97CA71E8A8F2C001545D5 /* PinLayout.swift in Sources */, @@ -828,7 +848,7 @@ DF1A5CBB208106A900725EF5 /* UIView+PinLayout.swift in Sources */, 2475B6D31FC37CD40054CADD /* Coordinates.swift in Sources */, 241A277D1F8E958F00B1AD39 /* PinLayoutObjC.swift in Sources */, - 24949A2E1EF69474003643D3 /* PinLayout+Filters.swift in Sources */, + 24949A2E1EF69474003643D3 /* Filters.swift in Sources */, DFB3ECB12061602F005F226B /* PinSafeArea.swift in Sources */, 2475B6CD1FC37C1C0054CADD /* PinLayoutImpl+Relative.swift in Sources */, ); @@ -838,6 +858,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DFF222E320BACBBF00AC2A84 /* WrapContentSpec.swift in Sources */, 240F88BE1F0C066800280FC8 /* JustifyAlignSpec.swift in Sources */, 2469C5001E75D74000073BEE /* AdjustSizeSpec.swift in Sources */, 243B12C81FC3D06F0072A9C3 /* LayoutMethodSpec.swift in Sources */, @@ -872,6 +893,7 @@ DFED154F20852F7E009EF9A7 /* BasicView.swift in Sources */, DFB288AF20854127001F9588 /* PinPointCoordinatesSpec.swift in Sources */, DFB288A320853E82001F9588 /* JustifyAlignSpec.swift in Sources */, + DFF222E420BACBC000AC2A84 /* WrapContentSpec.swift in Sources */, DFED15532085349A009EF9A7 /* RectNimbleMatcher.swift in Sources */, DFB288B12085419B001F9588 /* RelativePositionSpec.swift in Sources */, DFB288B2208541B7001F9588 /* RelativePositionMultipleViewsSpec.swift in Sources */, @@ -897,11 +919,12 @@ DF1A5D412084CFD600725EF5 /* Coordinates.swift in Sources */, DF1A5D422084CFD600725EF5 /* Percent.swift in Sources */, DF1A5D3E2084CFD600725EF5 /* PinLayoutImpl+Relative.swift in Sources */, + DFF222CA20B9994200AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, DF1A5D442084CFD600725EF5 /* UIView+LTR.swift in Sources */, DF1A5D352084CFC100725EF5 /* NSView+PinLayout.swift in Sources */, DF1A5D3A2084CFC600725EF5 /* UIView+PinLayout.swift in Sources */, DFED155120853085009EF9A7 /* PinLayout.swift in Sources */, - DF1A5D382084CFC600725EF5 /* PinLayout+Filters.swift in Sources */, + DF1A5D382084CFC600725EF5 /* Filters.swift in Sources */, DF1A5D392084CFC600725EF5 /* Pin.swift in Sources */, DF1A5D3D2084CFD600725EF5 /* PinLayoutImpl+Layouting.swift in Sources */, DF1A5D3C2084CFD600725EF5 /* PinLayoutImpl+Coordinates.swift in Sources */, @@ -914,6 +937,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DFF222E520BACBC000AC2A84 /* WrapContentSpec.swift in Sources */, DFF6F9DC2084E15A004F5AED /* RelativePositionMultipleViewsSpec.swift in Sources */, DFABC023208781EE00CB6494 /* Types+UIKit.swift in Sources */, DFF6F9DB2084E15A004F5AED /* RelativePositionSpec.swift in Sources */, diff --git a/PinLayout.xcworkspace/contents.xcworkspacedata b/PinLayout.xcworkspace/contents.xcworkspacedata index 3be1104b..16192094 100644 --- a/PinLayout.xcworkspace/contents.xcworkspacedata +++ b/PinLayout.xcworkspace/contents.xcworkspacedata @@ -10,7 +10,4 @@ - - diff --git a/Podfile.lock b/Podfile.lock index d8eb96e6..1c98d1a9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,6 +1,6 @@ PODS: - Nimble (7.0.3) - - PinLayout (1.7.3) + - PinLayout (1.7.4) - Quick (1.2.0) - Reveal-SDK (10) - SwiftLint (0.25.1) @@ -25,7 +25,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Nimble: 7f5a9c447a33002645a071bddafbfb24ea70e0ac - PinLayout: 04488e8fc8d19b59760bdf99a16deff7bfac422d + PinLayout: e20545b1fd5110133e0b03bed61f196161af8b36 Quick: 58d203b1c5e27fff7229c4c1ae445ad7069a7a08 Reveal-SDK: 7869ddf1f902cabbb07a1f0dd06bd25861a126f7 SwiftLint: ce933681be10c3266e82576dad676fa815a602e9 diff --git a/Sources/Filters.swift b/Sources/Filters.swift new file mode 100644 index 00000000..400ca72e --- /dev/null +++ b/Sources/Filters.swift @@ -0,0 +1,28 @@ +// Copyright (c) 2017 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if os(iOS) || os(tvOS) +import UIKit + +// Filter out all hidden views (isHidden is true or alpha is 0) +public func visible(_ views: [UIView]) -> [UIView] { + return views.filter({ !$0.isHidden && $0.alpha > 0 }) +} + +#endif diff --git a/Sources/Impl/PinLayoutImpl+Layouting.swift b/Sources/Impl/PinLayoutImpl+Layouting.swift index 405bae96..367a4dc0 100644 --- a/Sources/Impl/PinLayoutImpl+Layouting.swift +++ b/Sources/Impl/PinLayoutImpl+Layouting.swift @@ -23,7 +23,7 @@ import AppKit #endif -// MARK - UIView's frame computation methods +// MARK: UIView's frame computation methods extension PinLayoutImpl { public func layout() { apply() diff --git a/Sources/Impl/PinLayoutImpl+WrapContent.swift b/Sources/Impl/PinLayoutImpl+WrapContent.swift new file mode 100644 index 00000000..06d2a928 --- /dev/null +++ b/Sources/Impl/PinLayoutImpl+WrapContent.swift @@ -0,0 +1,98 @@ +// Copyright (c) 2018 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if os(iOS) || os(tvOS) +import UIKit +#else +import AppKit +#endif + +extension PinLayoutImpl { + func wrapContent() -> PinLayout { + return wrapContent(.all, padding: .zero, { return "wrapContent()" }) + } + + func wrapContent(_ type: WrapType) -> PinLayout { + return wrapContent(type, padding: .zero, { return "wrapContent(\(type.description)" }) + } + + @discardableResult + private func wrapContent(_ type: WrapType, padding: PPadding, _ context: Context) -> PinLayout { + let subviews = view.subviews + guard !subviews.isEmpty else { return self } + let firstViewFrame = subviews[0].frame + var minX = firstViewFrame.minX + var maxX = firstViewFrame.maxX + var minY = firstViewFrame.minY + var maxY = firstViewFrame.maxY + + for var i in 1.. maxX { + maxX = frame.maxX + } + if frame.minY < minY { + minY = frame.minY + } + if frame.maxY > maxY { + maxY = frame.maxY + } + } + + var offsetDx: CGFloat = 0 + var offsetDy: CGFloat = 0 + + if type == .all || type == .width { + let contentWidth = maxX - minX + if contentWidth >= 0 { + setWidth(contentWidth, context) + } + + offsetDx = -minX +// let contentWidth = view.subviews.max(by: { subview1, subview2 in +// subview1.frame.maxX < subview2.frame.maxX +// })?.frame.maxX ?? 0 + } + + if type == .all || type == .height { + let contentHeight = maxY - minY + if contentHeight >= 0 { + setHeight(contentHeight, context) + } + + offsetDy = -minY +// let contentHeight = view.subviews.max(by: { subview1, subview2 in +// subview1.frame.maxY < subview2.frame.maxY +// })?.frame.maxY ?? 0 + } + + if offsetDx != 0 || offsetDy != 0 { + subviews.forEach { (view) in + let viewRect = Coordinates.getViewRect(view, keepTransform: keepTransform) + let newRect = viewRect.offsetBy(dx: offsetDx, dy: offsetDy) + Coordinates.setViewRect(view, toRect: newRect, keepTransform: keepTransform) + } + } + + return self + } +} diff --git a/Sources/Impl/PinLayoutImpl.swift b/Sources/Impl/PinLayoutImpl.swift index ae01e5e9..2d07b3b8 100644 --- a/Sources/Impl/PinLayoutImpl.swift +++ b/Sources/Impl/PinLayoutImpl.swift @@ -728,14 +728,8 @@ class PinLayoutImpl: PinLayout { func context() -> String { return "size(of \(viewDescription(view)))" } return setSize(view.bounds.size, context) } - -// func wrapSubViews() -> PinLayout { -// let neededWidth = view.subviews.max(by: { subview1, subview2 in subview1.frame.maxX < subview2.frame.maxX })?.frame.maxX ?? 0 -// let neededHeight = view.subviews.max(by: { subview1, subview2 in subview1.frame.maxY < subview2.frame.maxY })?.frame.maxY ?? 0 -// -// return setSize(CGSize(width: neededWidth, height: neededHeight), { return "wrapSubViews()" }) -// } - + + @discardableResult func aspectRatio(_ ratio: CGFloat) -> PinLayout { return setAspectRatio(ratio, context: { "aspectRatio(\(ratio))" }) } @@ -761,7 +755,7 @@ class PinLayoutImpl: PinLayout { #endif func sizeToFit(_ fitType: FitType) -> PinLayout { - return setFitSize(fitType: fitType, { return "sizeToFit(\(fitType.name))" }) + return setFitSize(fitType: fitType, { return "sizeToFit(\(fitType.description))" }) } #if os(iOS) || os(tvOS) @@ -992,7 +986,7 @@ extension PinLayoutImpl { } else if fitType != nil && legacyFitSize { warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with fitSize().") } else if let currentFitType = self.fitType, currentFitType != fitType { - warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(currentFitType.name)).") + warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(currentFitType.description)).") } else { if fitType == nil { legacyFitSize = true @@ -1006,7 +1000,7 @@ extension PinLayoutImpl { @discardableResult internal func setAspectRatio(_ ratio: CGFloat, context: Context) -> PinLayout { if let fitType = fitType { - warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(fitType.name)).") + warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with sizeToFit(\(fitType.description)).") } else if legacyFitSize { warn("PinLayout Conflict: \(context()) won't be applied since it conflicts with fitSize().") } else if ratio <= 0 { diff --git a/Sources/Impl/TypesImpl.swift b/Sources/Impl/TypesImpl.swift index eb1060d2..94526a7a 100644 --- a/Sources/Impl/TypesImpl.swift +++ b/Sources/Impl/TypesImpl.swift @@ -28,28 +28,6 @@ import Foundation typealias Context = () -> String typealias Size = (width: CGFloat?, height: CGFloat?) -extension HorizontalAlign { - var description: String { - switch self { - case .left: return "left" - case .center: return "center" - case .right: return "right" - case .start: return "start" - case .end: return "end" - } - } -} - -extension VerticalAlign { - var description: String { - switch self { - case .top: return "top" - case .center: return "center" - case .bottom: return "bottom" - } - } -} - class EdgeListImpl: EdgeList { internal let view: PView @@ -185,26 +163,7 @@ class AnchorImpl: Anchor { } } -extension CGFloat { - public var description: String { - if self.truncatingRemainder(dividingBy: 1) == 0.0 { - return "\(Int(self))" - } else { - return "\(self)" - } - } -} - internal extension FitType { - var name: String { - switch self { - case .width: return ".width" - case .height: return ".height" - case .widthFlexible: return ".widthFlexible" - case .heightFlexible: return ".heightFlexible" - } - } - var isFlexible: Bool { return self == .widthFlexible || self == .heightFlexible } diff --git a/Sources/Pin.swift b/Sources/Pin.swift index 30a33003..ca74db56 100644 --- a/Sources/Pin.swift +++ b/Sources/Pin.swift @@ -19,24 +19,6 @@ import Foundation -@objc public enum LayoutDirection: Int { - case auto - case ltr - case rtl -} - -/// Control how PinLayout will calls `UIView.safeAreaInsetsDidChange` when the `UIView.pin.safeArea` change. -/// This support is usefull only on iOS 8/9/10. On iOS 11 `UIView.safeAreaInsetsDidChange` is supported -/// natively so this settings have no impact. -@objc public enum PinSafeAreaInsetsDidChangeMode: Int { - /// PinLayout won't call `UIView.safeAreaInsetsDidChange` on iOS 8/9/10. - case disable - /// PinLayout will call `UIView.safeAreaInsetsDidChange` only if the UIView implement the PinSafeAreaInsetsUpdate protocol. - case optIn - /// PinLayout will automatically calls `UIView.safeAreaInsetsDidChange` if the view has implemented this method. - case always -} - @objc public class Pin: NSObject { @objc public static var layoutDirection = LayoutDirection.ltr diff --git a/Sources/PinLayout.swift b/Sources/PinLayout.swift index e456a11b..9a659ad9 100644 --- a/Sources/PinLayout.swift +++ b/Sources/PinLayout.swift @@ -23,85 +23,6 @@ import UIKit import AppKit #endif -/* - UIView's anchors point - ====================== - - topLeft topCenter topRight - o-------------o--------------o - | | - | | - | | - | | - | | - | center | - centerLeft o o o centerRight - | | - | | - | | - | | - | | - | | - o-------------o--------------o - bottomLeft bottomCenter bottomLeft - - */ - -/// UIViews's anchor definition -@objc public protocol Anchor { -} - -/// UIViews's list of anchors. -@objc public protocol AnchorList { - var topLeft: Anchor { get } - var topCenter: Anchor { get } - var topRight: Anchor { get } - var centerLeft: Anchor { get } - var center: Anchor { get } - var centerRight: Anchor { get } - var bottomLeft: Anchor { get } - var bottomCenter: Anchor { get } - var bottomRight: Anchor { get } - - // RTL support - var topStart: Anchor { get } - var topEnd: Anchor { get } - var centerStart: Anchor { get } - var centerEnd: Anchor { get } - var bottomStart: Anchor { get } - var bottomEnd: Anchor { get } -} - -/* - UIView's Edges - ====================== - top - +-----------------+ - | | - | | - | hCenter | - left | + | right - | vCenter | - | | - | | - +-----------------+ - bottom -*/ - -/// UIViews's list of edges -@objc public protocol EdgeList { - var top: VerticalEdge { get } - var vCenter: VerticalEdge { get } - var bottom: VerticalEdge { get } - var left: HorizontalEdge { get } - var hCenter: HorizontalEdge { get } - var right: HorizontalEdge { get } - - // RTL support - var start: HorizontalEdge { get } - var end: HorizontalEdge { get } -} - /// PinLayout interface public protocol PinLayout { @@ -387,8 +308,10 @@ public protocol PinLayout { @discardableResult func size(of view: NSView) -> PinLayout #endif - // @discardableResult func wrapSubViews() -> PinLayout - // @discardableResult func wrapSubViews(insets: UIEdgeInsets) -> PinLayout + @discardableResult func wrapContent() -> PinLayout + @discardableResult func wrapContent(_ type: WrapType) -> PinLayout + @discardableResult func wrapContent(padding: PPadding) -> PinLayout + @discardableResult func wrapContent(_ type: WrapType, padding: PPadding) -> PinLayout /** Set the view aspect ratio. @@ -620,71 +543,3 @@ public protocol PinLayout { */ func layout() } - -/// Horizontal alignment used with relative positionning methods: above(of relativeView:, aligned:), below(of relativeView:, aligned:) -/// -/// - left: left aligned -/// - center: center aligned -/// - right: right aligned -@objc public enum HorizontalAlign: Int { - case left - case center - case right - - // RTL support - case start - case end -} - -/// Vertical alignment used with relative positionning methods: left(of relativeView:, aligned:), right(of relativeView:, aligned:) -/// -/// - top: top aligned -/// - center: center aligned -/// - bottom: bottom aligned -@objc public enum VerticalAlign: Int { - case top - case center - case bottom -} - -/// UIView's horizontal edges (left/right) definition -@objc public protocol HorizontalEdge { -} - -/// UIView's vertical edges (top/bottom) definition -@objc public protocol VerticalEdge { -} - -public enum FitType { - /** - **Adjust the view's height** based on the reference width. - * If properties related to the width have been pinned (e.g: width, left & right, margins), - the **reference width will be determined by these properties**, else the **current view's width** - will be used. - * The resulting width will always **match the reference width**. - */ - case width - /** - **Adjust the view's width** based on the reference height. - * If properties related to the height have been pinned (e.g: height, top & bottom, margins), - the reference height will be determined by these properties, else the **current view's height** - will be used. - * The resulting height will always **match the reference height*. - */ - case height - - /** - Similar to `.width`, except that PinLayout won't constrain the resulting width to - match the reference width. The resulting width may be smaller of bigger depending on the view's - sizeThatFits(..) method result. For example a single line UILabel may returns a smaller width if its - string is smaller than the reference width. - */ - case widthFlexible - /** - Similar to `.height`, except that PinLayout won't constrain the resulting height to - match the reference height. The resulting height may be smaller of bigger depending on the view's - sizeThatFits(..) method result. - */ - case heightFlexible -} - diff --git a/Sources/Types+Description.swift b/Sources/Types+Description.swift new file mode 100644 index 00000000..28946b2a --- /dev/null +++ b/Sources/Types+Description.swift @@ -0,0 +1,62 @@ +// +// Types+Description.swift +// PinLayout-iOS +// +// Created by Luc Dion on 2018-05-26. +// Copyright © 2018 mcswiftlayyout.mirego.com. All rights reserved. +// + +import Foundation + +extension HorizontalAlign { + var description: String { + switch self { + case .left: return "left" + case .center: return "center" + case .right: return "right" + case .start: return "start" + case .end: return "end" + } + } +} + +extension VerticalAlign { + var description: String { + switch self { + case .top: return "top" + case .center: return "center" + case .bottom: return "bottom" + } + } +} + +extension CGFloat { + public var description: String { + if self.truncatingRemainder(dividingBy: 1) == 0.0 { + return "\(Int(self))" + } else { + return "\(self)" + } + } +} + +extension FitType { + var description: String { + switch self { + case .width: return ".width" + case .height: return ".height" + case .widthFlexible: return ".widthFlexible" + case .heightFlexible: return ".heightFlexible" + } + } +} + +extension WrapType { + var description: String { + switch self { + case .all: return ".all" + case .width: return ".width" + case .height: return ".height" + } + } +} diff --git a/Sources/Types.swift b/Sources/Types.swift new file mode 100644 index 00000000..32f691c3 --- /dev/null +++ b/Sources/Types.swift @@ -0,0 +1,229 @@ +// Copyright (c) 2018 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + + +/* + UIView's anchors point + ====================== + + topLeft topCenter topRight + o-------------o--------------o + | | + | | + | | + | | + | | + | center | + centerLeft o o o centerRight + | | + | | + | | + | | + | | + | | + o-------------o--------------o + bottomLeft bottomCenter bottomLeft + + */ + +/// UIViews's anchor definition +@objc public protocol Anchor { +} + +/// UIViews's list of anchors. +@objc public protocol AnchorList { + var topLeft: Anchor { get } + var topCenter: Anchor { get } + var topRight: Anchor { get } + var centerLeft: Anchor { get } + var center: Anchor { get } + var centerRight: Anchor { get } + var bottomLeft: Anchor { get } + var bottomCenter: Anchor { get } + var bottomRight: Anchor { get } + + // RTL support + var topStart: Anchor { get } + var topEnd: Anchor { get } + var centerStart: Anchor { get } + var centerEnd: Anchor { get } + var bottomStart: Anchor { get } + var bottomEnd: Anchor { get } +} + +/* + UIView's Edges + ====================== + top + +-----------------+ + | | + | | + | hCenter | + left | + | right + | vCenter | + | | + | | + +-----------------+ + bottom + */ + +/// UIViews's list of edges +@objc public protocol EdgeList { + var top: VerticalEdge { get } + var vCenter: VerticalEdge { get } + var bottom: VerticalEdge { get } + var left: HorizontalEdge { get } + var hCenter: HorizontalEdge { get } + var right: HorizontalEdge { get } + + // RTL support + var start: HorizontalEdge { get } + var end: HorizontalEdge { get } +} + +/// Horizontal alignment used with relative positionning methods: above(of relativeView:, aligned:), below(of relativeView:, aligned:) +/// +/// - left: left aligned +/// - center: center aligned +/// - right: right aligned +@objc public enum HorizontalAlign: Int { + case left + case center + case right + + // RTL support + case start + case end +} + +/// Vertical alignment used with relative positionning methods: left(of relativeView:, aligned:), right(of relativeView:, aligned:) +/// +/// - top: top aligned +/// - center: center aligned +/// - bottom: bottom aligned +@objc public enum VerticalAlign: Int { + case top + case center + case bottom +} + +/// UIView's horizontal edges (left/right) definition +@objc public protocol HorizontalEdge { +} + +/// UIView's vertical edges (top/bottom) definition +@objc public protocol VerticalEdge { +} + +public enum FitType { + /** + **Adjust the view's height** based on the reference width. + * If properties related to the width have been pinned (e.g: width, left & right, margins), + the **reference width will be determined by these properties**, else the **current view's width** + will be used. + * The resulting width will always **match the reference width**. + */ + case width + /** + **Adjust the view's width** based on the reference height. + * If properties related to the height have been pinned (e.g: height, top & bottom, margins), + the reference height will be determined by these properties, else the **current view's height** + will be used. + * The resulting height will always **match the reference height*. + */ + case height + + /** + Similar to `.width`, except that PinLayout won't constrain the resulting width to + match the reference width. The resulting width may be smaller of bigger depending on the view's + sizeThatFits(..) method result. For example a single line UILabel may returns a smaller width if its + string is smaller than the reference width. + */ + case widthFlexible + /** + Similar to `.height`, except that PinLayout won't constrain the resulting height to + match the reference height. The resulting height may be smaller of bigger depending on the view's + sizeThatFits(..) method result. + */ + case heightFlexible +} + +public enum WrapType { + /** + */ + case all + /** + */ + case width + /** + */ + case height +} + +public struct PPadding { + let top: CGFloat + let left: CGFloat + let bottom: CGFloat + let right: CGFloat + + static var zero: PPadding { + return PPadding(0) + } + + init(_ all: CGFloat) { + top = all + left = all + bottom = all + right = all + } + + init(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) { + self.top = top + self.left = left + self.bottom = bottom + self.right = right + } + + init(h: CGFloat, v: CGFloat) { + top = v + left = h + bottom = v + right = h + } +} + +@objc public enum LayoutDirection: Int { + case auto + case ltr + case rtl +} + +/// Control how PinLayout will calls `UIView.safeAreaInsetsDidChange` when the `UIView.pin.safeArea` change. +/// This support is usefull only on iOS 8/9/10. On iOS 11 `UIView.safeAreaInsetsDidChange` is supported +/// natively so this settings have no impact. +@objc public enum PinSafeAreaInsetsDidChangeMode: Int { + /// PinLayout won't call `UIView.safeAreaInsetsDidChange` on iOS 8/9/10. + case disable + /// PinLayout will call `UIView.safeAreaInsetsDidChange` only if the UIView implement the PinSafeAreaInsetsUpdate protocol. + case optIn + /// PinLayout will automatically calls `UIView.safeAreaInsetsDidChange` if the view has implemented this method. + case always +} diff --git a/Sources/UIView+PinLayout.swift b/Sources/UIView+PinLayout.swift index c99c394b..7ac26804 100644 --- a/Sources/UIView+PinLayout.swift +++ b/Sources/UIView+PinLayout.swift @@ -33,4 +33,5 @@ public extension UIView { return PinLayoutObjCImpl(view: self, keepTransform: true) } } + #endif diff --git a/Tests/Common/WrapContentSpec.swift b/Tests/Common/WrapContentSpec.swift new file mode 100644 index 00000000..e877d8b1 --- /dev/null +++ b/Tests/Common/WrapContentSpec.swift @@ -0,0 +1,216 @@ +// Copyright (c) 2018 Luc Dion +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Quick +import Nimble +import PinLayout + +class WrapContentSpec: QuickSpec { + override func spec() { + var viewController: PViewController! + var rootView: BasicView! + + /* + root + | + - aView + | | + | |- aViewChild + |- aViewChild2 + |- aViewChild3 + */ + var aView: BasicView! + var aViewChild: BasicView! + var aViewChild2: BasicView! + var aViewChild3: BasicView! + + beforeSuite { + _pinlayoutSetUnitTest(displayScale: 2) + } + + beforeEach { + Pin.lastWarningText = nil + + viewController = PViewController() + viewController.view = BasicView() + + rootView = BasicView() + viewController.view.addSubview(rootView) + + aView = BasicView() + aView.sizeThatFitsExpectedArea = 40 * 40 + rootView.addSubview(aView) + + aViewChild = BasicView() + aView.addSubview(aViewChild) + + aViewChild2 = BasicView() + aView.addSubview(aViewChild2) + + aViewChild3 = BasicView() + aView.addSubview(aViewChild3) + + rootView.frame = CGRect(x: 0, y: 100, width: 400, height: 400) + } + + describe("wrapContent") { + it("wrap and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.all) should have the same result") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.all) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.width) + wrapContent(.height) should have the same result") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.width) + aView.pin.wrapContent(.height) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.all) and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.all) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 0.0, width: 60.0, height: 60.0))) + } + + it("wrapContent(.width) and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.width) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 120.0, width: 60.0, height: 60.0))) + } + it("wrapContent(.height) and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.height) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 0.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 0.0, width: 60.0, height: 60.0))) + } + it("wrap and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 180, y: 140, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 220, y: 180, width: 60, height: 60) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 120.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 20.0, y: 20.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 60.0, y: 60.0, width: 60.0, height: 60.0))) + } + + it("wrap when views are of size zero") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 0, height: 0) + aViewChild2.frame = CGRect(x: 180, y: 140, width: 0, height: 0) + aViewChild3.frame = CGRect(x: 220, y: 180, width: 0, height: 0) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 0.0, height: 0.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 20.0, y: 20.0, width: 0.0, height: 0.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 60.0, y: 60.0, width: 0.0, height: 0.0))) + } + + it("wrap with subviews with negative position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: -40, y: -40, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 350, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 350, y: -100, width: 60, height: 60) + + aView.pin.wrapContent() + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 450.0, height: 280.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 60.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 390.0, y: 220.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 390.0, y: 0.0, width: 60.0, height: 60.0))) + } + it("wrap and update subviews position") { + + } + it("wrap and update subviews position") { + // warning + aView.pin.wrapContent().width(20) + } + + it("wrap and update subviews position") { + // warning + aView.pin.width(20).wrapContent() + } + + it("wrap and update subviews position") { + // warning + aView.pin.height(20).wrapContent() + } + } + } +} From 2de27085f715c578f131c343632cbc4ed60e0b91 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Fri, 1 Jun 2018 18:45:19 -0400 Subject: [PATCH 2/5] Initial commit --- .gitignore | 3 +- README.md | 48 ++++- Sources/Impl/PinLayoutImpl+WrapContent.swift | 37 ++-- Sources/PinLayout+Filters.swift | 28 --- Sources/PinLayout.swift | 42 ++++- Sources/Types+Description.swift | 4 +- Sources/Types.swift | 45 +---- Tests/Common/WrapContentSpec.swift | 188 +++++++++++++++++-- 8 files changed, 294 insertions(+), 101 deletions(-) delete mode 100644 Sources/PinLayout+Filters.swift diff --git a/.gitignore b/.gitignore index 2325e32c..491ff75e 100644 --- a/.gitignore +++ b/.gitignore @@ -19,9 +19,10 @@ TestProjects/cocoapods/macos/PinLayout-macOS.xcworkspace/ TestProjects/cocoapods/macos/Podfile.lock TestProjects/cocoapods/tvos/PinLayout-tvOS.xcworkspace/ TestProjects/cocoapods/tvos/Podfile.lock + TestProjects/carthage/ios/Cartfile.resolved TestProjects/carthage/ios/Carthage/ TestProjects/swift-package-manager -Example/PinLayoutExampleMacOS \ No newline at end of file +Example/PinLayoutExampleMacOS diff --git a/README.md b/README.md index f4803bed..9c7fd543 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co * Swift 3.2+ / Swift 4.0 / Objective-C ### Recent features +* :star: Add methods `wrapConten(...)` that adjust the view's width & height to wrap all its subviews. See [wrapContent](#wrapCcontent) for more information. + * :star: PinLayout now support macOS. See [macOS Support](#macos_support) for more information. * :star: PinLayout expose the `safeAreaInsets` through [`UIView.pin.safeArea`](#safeAreaInsets), this property support not only iOS 11, but is also backward compatible for earlier iOS releases (7/8/9/10). See [safeAreaInsets support](#safeAreaInsets) for more information. @@ -61,6 +63,7 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co * [Aspect Ratio](#aspect_ratio) * [Margins](#margins) * [safeAreaInsets support](#safeAreaInsets) + * [WrapContent](#wrapCcontent) * [justify, align](#justify_align) * [UIView's transforms](#uiview_transform) * [Warnings](#warnings) @@ -1134,8 +1137,51 @@ This example runs perfectly on a iPhone X (iOS 11), but it also runs on any devi
+ +## WrapContent - +The following methods are useful to adjust the view's width and/or height to wrap all its subviews. These method also adjust subviews position to create a tight wrap. + +**Methods:** + +* **`wrapContent()`** +Bla. +* **`wrapContent(padding: CGFloat)`** +Bla. +* **`wrapContent(padding: UIEdgeInsets)`** +Bla. +* **`wrapContent(:WrapType)`** +Bla. +* **`wrapContent(:WrapType, padding: CGFloat)`** +Bla. +* **`wrapContent(:WrapType, padding: UIEdgeInsets)`** +Bla. + +TABLE SHOWING DIFFERENCES!!! + +###### Usage examples: +```swift + view.pin.wrapContent().center() // wrap all subviews and centered the view inside its parent. + view.pin.wrapContent(padding: 20) // wrap all subviews with a padding of 20 pixels all around +``` + + +###### Example: +...: + + + + +```swift + viewA.pin..... +``` + +
+ + + + + ## justify() / align() **Methods:** diff --git a/Sources/Impl/PinLayoutImpl+WrapContent.swift b/Sources/Impl/PinLayoutImpl+WrapContent.swift index 06d2a928..d89e07f7 100644 --- a/Sources/Impl/PinLayoutImpl+WrapContent.swift +++ b/Sources/Impl/PinLayoutImpl+WrapContent.swift @@ -28,12 +28,27 @@ extension PinLayoutImpl { return wrapContent(.all, padding: .zero, { return "wrapContent()" }) } + func wrapContent(padding: CGFloat) -> PinLayout { + return wrapContent(.all, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(padding: \(padding)" }) + } + + func wrapContent(padding: UIEdgeInsets) -> PinLayout { + return wrapContent(.all, padding: padding, { return "wrapContent(padding: \(insetsDescription(padding))" }) + } + func wrapContent(_ type: WrapType) -> PinLayout { return wrapContent(type, padding: .zero, { return "wrapContent(\(type.description)" }) } - @discardableResult - private func wrapContent(_ type: WrapType, padding: PPadding, _ context: Context) -> PinLayout { + func wrapContent(_ type: WrapType, padding: CGFloat) -> PinLayout { + return wrapContent(type, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(\(type.description), padding: \(padding)" }) + } + + func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout { + return wrapContent(type, padding: padding, { return "wrapContent(\(type.description), padding: \(insetsDescription(padding))" }) + } + + private func wrapContent(_ type: WrapType, padding: UIEdgeInsets, _ context: Context) -> PinLayout { let subviews = view.subviews guard !subviews.isEmpty else { return self } let firstViewFrame = subviews[0].frame @@ -61,28 +76,22 @@ extension PinLayoutImpl { var offsetDx: CGFloat = 0 var offsetDy: CGFloat = 0 - if type == .all || type == .width { - let contentWidth = maxX - minX + if type == .all || type == .horizontally { + let contentWidth = maxX - minX + padding.left + padding.right if contentWidth >= 0 { setWidth(contentWidth, context) } - offsetDx = -minX -// let contentWidth = view.subviews.max(by: { subview1, subview2 in -// subview1.frame.maxX < subview2.frame.maxX -// })?.frame.maxX ?? 0 + offsetDx = -minX + padding.left } - if type == .all || type == .height { - let contentHeight = maxY - minY + if type == .all || type == .vertically { + let contentHeight = maxY - minY + padding.top + padding.bottom if contentHeight >= 0 { setHeight(contentHeight, context) } - offsetDy = -minY -// let contentHeight = view.subviews.max(by: { subview1, subview2 in -// subview1.frame.maxY < subview2.frame.maxY -// })?.frame.maxY ?? 0 + offsetDy = -minY + padding.top } if offsetDx != 0 || offsetDy != 0 { diff --git a/Sources/PinLayout+Filters.swift b/Sources/PinLayout+Filters.swift deleted file mode 100644 index 400ca72e..00000000 --- a/Sources/PinLayout+Filters.swift +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2017 Luc Dion -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#if os(iOS) || os(tvOS) -import UIKit - -// Filter out all hidden views (isHidden is true or alpha is 0) -public func visible(_ views: [UIView]) -> [UIView] { - return views.filter({ !$0.isHidden && $0.alpha > 0 }) -} - -#endif diff --git a/Sources/PinLayout.swift b/Sources/PinLayout.swift index 9a659ad9..543f2e85 100644 --- a/Sources/PinLayout.swift +++ b/Sources/PinLayout.swift @@ -308,10 +308,48 @@ public protocol PinLayout { @discardableResult func size(of view: NSView) -> PinLayout #endif + /** + Adjust the view's width & height to wrap all its subviews. The method also adjust subviews position to create a tight wrap. + */ @discardableResult func wrapContent() -> PinLayout + /** + Adjust the view's width & height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - padding: Specify a padding value. + */ + @discardableResult func wrapContent(padding: CGFloat) -> PinLayout + /** + Adjust the view's width & height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - padding: Specify a padding using an UIEdgeInsets. + */ + @discardableResult func wrapContent(padding: UIEdgeInsets) -> PinLayout + + /** + Adjust the view's width AND/OR height to wrap all its subviews. + + - Parameters: + - type: Specify the wrap type (.all, .horizontally, .vertically) + */ @discardableResult func wrapContent(_ type: WrapType) -> PinLayout - @discardableResult func wrapContent(padding: PPadding) -> PinLayout - @discardableResult func wrapContent(_ type: WrapType, padding: PPadding) -> PinLayout + /** + Adjust the view's width AND/OR height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - type: Specify the wrap type (.all, .horizontally, .vertically) + - padding: Specify a padding value. + */ + @discardableResult func wrapContent(_ type: WrapType, padding: CGFloat) -> PinLayout + /** + Adjust the view's width AND/OR height to wrap all its subviews. The method also adds a padding around all subviews. + + - Parameters: + - type: Specify the wrap type (.all, .horizontally, .vertically) + - padding: Specify a padding using an UIEdgeInsets. + */ + @discardableResult func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout /** Set the view aspect ratio. diff --git a/Sources/Types+Description.swift b/Sources/Types+Description.swift index 28946b2a..ccfad56f 100644 --- a/Sources/Types+Description.swift +++ b/Sources/Types+Description.swift @@ -55,8 +55,8 @@ extension WrapType { var description: String { switch self { case .all: return ".all" - case .width: return ".width" - case .height: return ".height" + case .horizontally: return ".horizontally" + case .vertically: return ".vertically" } } } diff --git a/Sources/Types.swift b/Sources/Types.swift index 32f691c3..77cce2b0 100644 --- a/Sources/Types.swift +++ b/Sources/Types.swift @@ -167,47 +167,12 @@ public enum FitType { } public enum WrapType { - /** - */ + /// Adjust the view's width AND height to wrap all its subviews. case all - /** - */ - case width - /** - */ - case height -} - -public struct PPadding { - let top: CGFloat - let left: CGFloat - let bottom: CGFloat - let right: CGFloat - - static var zero: PPadding { - return PPadding(0) - } - - init(_ all: CGFloat) { - top = all - left = all - bottom = all - right = all - } - - init(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) { - self.top = top - self.left = left - self.bottom = bottom - self.right = right - } - - init(h: CGFloat, v: CGFloat) { - top = v - left = h - bottom = v - right = h - } + /// Adjust only the view's width to wrap all its subviews. 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. + case vertically } @objc public enum LayoutDirection: Int { diff --git a/Tests/Common/WrapContentSpec.swift b/Tests/Common/WrapContentSpec.swift index e877d8b1..eaaa684c 100644 --- a/Tests/Common/WrapContentSpec.swift +++ b/Tests/Common/WrapContentSpec.swift @@ -104,8 +104,8 @@ class WrapContentSpec: QuickSpec { aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) - aView.pin.wrapContent(.width) - aView.pin.wrapContent(.height) + aView.pin.wrapContent(.horizontally) + aView.pin.wrapContent(.vertically) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 60.0))) expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) @@ -133,7 +133,7 @@ class WrapContentSpec: QuickSpec { aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) - aView.pin.wrapContent(.width) + aView.pin.wrapContent(.horizontally) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 260.0, height: 100.0))) expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 120.0, width: 100.0, height: 40.0))) @@ -146,7 +146,7 @@ class WrapContentSpec: QuickSpec { aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) - aView.pin.wrapContent(.height) + aView.pin.wrapContent(.vertically) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 60.0))) expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 0.0, width: 100.0, height: 40.0))) @@ -194,22 +194,184 @@ class WrapContentSpec: QuickSpec { expect(aViewChild2.frame).to(equal(CGRect(x: 390.0, y: 220.0, width: 60.0, height: 60.0))) expect(aViewChild3.frame).to(equal(CGRect(x: 390.0, y: 0.0, width: 60.0, height: 60.0))) } + } + + describe("wrapContent with padding") { it("wrap and update subviews position") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(padding: 10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 280.0, height: 80.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 10.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 110.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 210.0, y: 10.0, width: 60.0, height: 60.0))) } - it("wrap and update subviews position") { - // warning - aView.pin.wrapContent().width(20) + it("wrap and update subviews position + center") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(padding: 10).center() + + expect(aView.frame).to(equal(CGRect(x: 60.0, y: 160.0, width: 280.0, height: 80.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 10.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 110.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 210.0, y: 10.0, width: 60.0, height: 60.0))) } - it("wrap and update subviews position") { - // warning - aView.pin.width(20).wrapContent() + it("wrap horizontally + padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 120, width: 60, height: 60) + + aView.pin.wrapContent(.horizontally, padding: 10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 280.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 10.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 110.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 210.0, y: 120.0, width: 60.0, height: 60.0))) } - it("wrap and update subviews position") { - // warning - aView.pin.height(20).wrapContent() + it("wrap vertically + padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + + aView.pin.wrapContent(.vertically, padding: 10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) + } + + it("wrap horizontally + negative padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 160, width: 60, height: 60) + aView.pin.wrapContent(.horizontally, padding: -10) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 240.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: -10.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 90.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 190.0, y: 160.0, width: 60.0, height: 60.0))) + } + + it("wrap vertically + negative padding") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 160, width: 60, height: 60) + + aView.pin.wrapContent(.vertically, padding: -10) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 80.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: -10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: -10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) + } + + + it("wrap all + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 220.0, y: 30.0, width: 60.0, height: 60.0))) + } + + it("wrap all + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 220.0, y: 30.0, width: 60.0, height: 60.0))) + + } + + it("wrap horizontally + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.horizontally, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 120.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 120.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 220.0, y: 140.0, width: 60.0, height: 60.0))) + + } + + + it("wrap vertically + padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.vertically, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 120.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) + + } + + it("wrap all + negative padding UIEdgeInsets") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: -10, left: -20, bottom: -30, right: -40)) + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 40.0))) + expect(aViewChild.frame).to(equal(CGRect(x: -20.0, y: -10.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 80.0, y: -10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 180.0, y: 10.0, width: 60.0, height: 60.0))) + } + } + + describe("wrapContent + min/max") { + it("wrap all + maxWidth + maxHeight") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 130, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + + aView.pin.wrapContent().maxWidth(200).maxHeight(50) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 50.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 20.0, width: 60.0, height: 60.0))) + } + + it("wrap all + minWidth + minHeight") { + aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) + aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) + aViewChild2.frame = CGRect(x: 260, y: 130, width: 60, height: 60) + aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) + + aView.pin.wrapContent().minWidth(300).minHeight(100) + + expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 300.0, height: 100.0))) + expect(aViewChild.frame).to(equal(CGRect(x: 0.0, y: 0.0, width: 100.0, height: 40.0))) + expect(aViewChild2.frame).to(equal(CGRect(x: 100.0, y: 10.0, width: 60.0, height: 60.0))) + expect(aViewChild3.frame).to(equal(CGRect(x: 200.0, y: 20.0, width: 60.0, height: 60.0))) } } } From 7b39081d5fe1da00f3a7ecbd3143abaae4545750 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Sat, 2 Jun 2018 07:11:58 -0400 Subject: [PATCH 3/5] Update for tvOS and macOS --- .../xcschemes/PinLayoutSample.xcscheme | 2 +- PinLayout.xcodeproj/project.pbxproj | 22 ++++++++++++++----- .../xcschemes/PinLayout-iOS.xcscheme | 2 +- .../xcschemes/PinLayout-macOS.xcscheme | 2 +- .../xcschemes/PinLayout-tvOS.xcscheme | 2 +- Sources/Impl/PinLayoutImpl+WrapContent.swift | 16 +++++++------- Sources/PinLayout.swift | 9 ++++++++ Sources/Types+Description.swift | 6 ++++- Tests/Common/WrapContentSpec.swift | 17 +++++++------- 9 files changed, 51 insertions(+), 27 deletions(-) diff --git a/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme b/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme index d6642870..06ff0930 100644 --- a/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme +++ b/Example/PinLayoutSample.xcodeproj/xcshareddata/xcschemes/PinLayoutSample.xcscheme @@ -1,6 +1,6 @@ PinLayout { - return wrapContent(.all, padding: .zero, { return "wrapContent()" }) + return wrapContent(.all, padding: PEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), { return "wrapContent()" }) } func wrapContent(padding: CGFloat) -> PinLayout { - return wrapContent(.all, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(padding: \(padding)" }) + return wrapContent(.all, padding: PEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(padding: \(padding)" }) } - func wrapContent(padding: UIEdgeInsets) -> PinLayout { + func wrapContent(padding: PEdgeInsets) -> PinLayout { return wrapContent(.all, padding: padding, { return "wrapContent(padding: \(insetsDescription(padding))" }) } func wrapContent(_ type: WrapType) -> PinLayout { - return wrapContent(type, padding: .zero, { return "wrapContent(\(type.description)" }) + return wrapContent(type, padding: PEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), { return "wrapContent(\(type.description)" }) } func wrapContent(_ type: WrapType, padding: CGFloat) -> PinLayout { - return wrapContent(type, padding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(\(type.description), padding: \(padding)" }) + return wrapContent(type, padding: PEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(\(type.description), padding: \(padding)" }) } - func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout { + func wrapContent(_ type: WrapType, padding: PEdgeInsets) -> PinLayout { return wrapContent(type, padding: padding, { return "wrapContent(\(type.description), padding: \(insetsDescription(padding))" }) } - private func wrapContent(_ type: WrapType, padding: UIEdgeInsets, _ context: Context) -> PinLayout { + private func wrapContent(_ type: WrapType, padding: PEdgeInsets, _ context: Context) -> PinLayout { let subviews = view.subviews guard !subviews.isEmpty else { return self } let firstViewFrame = subviews[0].frame @@ -57,7 +57,7 @@ extension PinLayoutImpl { var minY = firstViewFrame.minY var maxY = firstViewFrame.maxY - for var i in 1.. PinLayout + #elseif os(macOS) + @discardableResult func wrapContent(padding: NSEdgeInsets) -> PinLayout + #endif /** Adjust the view's width AND/OR height to wrap all its subviews. @@ -349,7 +353,12 @@ public protocol PinLayout { - type: Specify the wrap type (.all, .horizontally, .vertically) - padding: Specify a padding using an UIEdgeInsets. */ + #if os(iOS) || os(tvOS) @discardableResult func wrapContent(_ type: WrapType, padding: UIEdgeInsets) -> PinLayout + #elseif os(macOS) + @discardableResult func wrapContent(_ type: WrapType, padding: NSEdgeInsets) -> PinLayout + #endif + /** Set the view aspect ratio. diff --git a/Sources/Types+Description.swift b/Sources/Types+Description.swift index ccfad56f..8a0a7dd7 100644 --- a/Sources/Types+Description.swift +++ b/Sources/Types+Description.swift @@ -6,7 +6,11 @@ // Copyright © 2018 mcswiftlayyout.mirego.com. All rights reserved. // -import Foundation +#if os(iOS) || os(tvOS) +import UIKit +#else +import AppKit +#endif extension HorizontalAlign { var description: String { diff --git a/Tests/Common/WrapContentSpec.swift b/Tests/Common/WrapContentSpec.swift index eaaa684c..ff56ae01 100644 --- a/Tests/Common/WrapContentSpec.swift +++ b/Tests/Common/WrapContentSpec.swift @@ -279,13 +279,12 @@ class WrapContentSpec: QuickSpec { expect(aViewChild3.frame).to(equal(CGRect(x: 360.0, y: 30.0, width: 60.0, height: 60.0))) } - it("wrap all + padding UIEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) @@ -297,7 +296,7 @@ class WrapContentSpec: QuickSpec { aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(.all, padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 120.0))) expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 10.0, width: 60.0, height: 60.0))) @@ -305,12 +304,12 @@ class WrapContentSpec: QuickSpec { } - it("wrap horizontally + padding UIEdgeInsets") { + it("wrap horizontally + padding PEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.horizontally, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(.horizontally, padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 320.0, height: 100.0))) expect(aViewChild.frame).to(equal(CGRect(x: 20.0, y: 120.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 120.0, y: 120.0, width: 60.0, height: 60.0))) @@ -319,12 +318,12 @@ class WrapContentSpec: QuickSpec { } - it("wrap vertically + padding UIEdgeInsets") { + it("wrap vertically + padding PEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.vertically, padding: UIEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) + aView.pin.wrapContent(.vertically, padding: PEdgeInsets(top: 10, left: 20, bottom: 30, right: 40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 120.0))) expect(aViewChild.frame).to(equal(CGRect(x: 160.0, y: 10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 260.0, y: 10.0, width: 60.0, height: 60.0))) @@ -332,12 +331,12 @@ class WrapContentSpec: QuickSpec { } - it("wrap all + negative padding UIEdgeInsets") { + it("wrap all + negative padding PEdgeInsets") { aView.frame = CGRect(x: 20, y: 10, width: 200, height: 100) aViewChild.frame = CGRect(x: 160, y: 120, width: 100, height: 40) aViewChild2.frame = CGRect(x: 260, y: 120, width: 60, height: 60) aViewChild3.frame = CGRect(x: 360, y: 140, width: 60, height: 60) - aView.pin.wrapContent(.all, padding: UIEdgeInsets(top: -10, left: -20, bottom: -30, right: -40)) + aView.pin.wrapContent(.all, padding: PEdgeInsets(top: -10, left: -20, bottom: -30, right: -40)) expect(aView.frame).to(equal(CGRect(x: 20.0, y: 10.0, width: 200.0, height: 40.0))) expect(aViewChild.frame).to(equal(CGRect(x: -20.0, y: -10.0, width: 100.0, height: 40.0))) expect(aViewChild2.frame).to(equal(CGRect(x: 80.0, y: -10.0, width: 60.0, height: 60.0))) From 174137d2569310a60b4b676b0647cd1e70f11024 Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Mon, 4 Jun 2018 22:28:50 -0400 Subject: [PATCH 4/5] Add wrapContent documentation. --- README.md | 49 +++++++++++++---------- docs/images/wrapContent_all.png | Bin 0 -> 25924 bytes docs/images/wrapContent_before.png | Bin 0 -> 25602 bytes docs/images/wrapContent_example_1.png | Bin 0 -> 60959 bytes docs/images/wrapContent_horizontally.png | Bin 0 -> 26242 bytes docs/images/wrapContent_padding.png | Bin 0 -> 25830 bytes docs/images/wrapContent_vertically.png | Bin 0 -> 25552 bytes 7 files changed, 28 insertions(+), 21 deletions(-) create mode 100644 docs/images/wrapContent_all.png create mode 100644 docs/images/wrapContent_before.png create mode 100644 docs/images/wrapContent_example_1.png create mode 100644 docs/images/wrapContent_horizontally.png create mode 100644 docs/images/wrapContent_padding.png create mode 100644 docs/images/wrapContent_vertically.png diff --git a/README.md b/README.md index 9c7fd543..a134fc6c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co * Swift 3.2+ / Swift 4.0 / Objective-C ### Recent features -* :star: Add methods `wrapConten(...)` that adjust the view's width & height to wrap all its subviews. See [wrapContent](#wrapCcontent) for more information. +* :star: Add `wrapContent()` methods that adjust view's width & height to wrap all its subviews. See [wrapContent](#wrapContent) for more information. * :star: PinLayout now support macOS. See [macOS Support](#macos_support) for more information. @@ -1137,50 +1137,57 @@ This example runs perfectly on a iPhone X (iOS 11), but it also runs on any devi
- + ## WrapContent -The following methods are useful to adjust the view's width and/or height to wrap all its subviews. These method 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. These methods also adjust subviews position to create a tight wrap. **Methods:** * **`wrapContent()`** -Bla. -* **`wrapContent(padding: CGFloat)`** -Bla. -* **`wrapContent(padding: UIEdgeInsets)`** -Bla. +**`wrapContent(padding: CGFloat)`** +**`wrapContent(padding: UIEdgeInsets)`** +Adjust the view's width and height to wrap all its subviews. The method also adjusts subviews position to create a tight wrap. It is also possible to specify an optional padding around all subviews. * **`wrapContent(:WrapType)`** -Bla. -* **`wrapContent(:WrapType, padding: CGFloat)`** -Bla. -* **`wrapContent(:WrapType, padding: UIEdgeInsets)`** -Bla. - -TABLE SHOWING DIFFERENCES!!! +**`wrapContent(:WrapType, padding: CGFloat)`** **`wrapContent(:WrapType, padding: UIEdgeInsets)`** +Adjust the view's width AND/OR height to wrap all its subviews. WrapType values are `.horizontally`/`.vertically`/`.all` It is also possible to specify an optional padding around all subviews. ###### Usage examples: ```swift view.pin.wrapContent().center() // wrap all subviews and centered the view inside its parent. view.pin.wrapContent(padding: 20) // wrap all subviews with a padding of 20 pixels all around + view.pin.wrapContent(.horizontally) ``` - ###### Example: -...: +This example show the result of different `wrapContent()` method calls. +Here is the initial state: - + +| Source code | Result | Description | +|---------------------|----------|-------------------| +| `view.pin.wrapContent()` | | Adjust the view's height and width to tight fit its subviews. | +| `view.pin.wrapContent(padding: 10)` | | Adjust the view's height and width and add a padding of 10 pixels around its subviews. | +| `view.pin.wrapContent(.horizontally)` | | Adjust only the view's width. | +| `view.pin.wrapContent(.vertically)` | | Adjust only the view's height. | + + +###### Example: +This example shows how a view (`containerView`) with two subviews (`imageView` and `label`), can be adjusted to the size of its subviews and then centered inside its parent. + + ```swift - viewA.pin..... + label.pin.below(of: imageView, aligned: .center).marginTop(4) + containerView.pin.wrapContent().center() ``` +* Line 1: Position the label below the imageView aligned on its center with a top margin of 4 pixels. +* Line 2: Adjust the `containerView`'s size and position its subviews to create a tight wrap around them, and then it center the `containerView` inside its parent (superview).
- - ## justify() / align() diff --git a/docs/images/wrapContent_all.png b/docs/images/wrapContent_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0f00ca0f08a6ad8bd097828e69b1252e4c901d57 GIT binary patch literal 25924 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 literal 0 HcmV?d00001 diff --git a/docs/images/wrapContent_before.png b/docs/images/wrapContent_before.png new file mode 100644 index 0000000000000000000000000000000000000000..ad081829f7d61ddffbf6f33896f78a802ffc0e90 GIT binary patch literal 25602 zcmeHvc|4Ts`~Rp;qJ=_9cFLBWFfp=Z3E9csU@*3^jI2Y8ND3uHA^R4x?{t(sOP1^; zWEo3FXso~I8J*6Y^Ev11^ZmVkfBgP{=jC?a*LJ_J>$>mjzMt0!(zvd8oScpv0)ZS? zR+86(KuB=FV}9f?*t2FB4*Vi>QZjIbKu(_r9};CP_HPi#F-fGHoQ8%C3XO8LK{+ui z%gHf2xuC3&_6P{XV<1}}siQr0de~h_mifcU-(+efgAR}%3iCXD$nr3U>?vkS*&}4! zZQY&Z-6S-m^xTFtc>_?07O6b%^{X$7PEZu3a~7q$F?vWJu)!?08(}ea!`|)CQJDAQ za(2Z+IcdjZs>VqzEsDk{E}Eq=nab`$G$WSp$eRQ*%ru$*RovUsQX2@Z$F^%#<$(hb zKIqX27q0D+6#i3Z$VgaETuDt=dQL&P0U40v)aN8opnzn}Tq`?ubC%>Yw^mmtNvbHs zu^9UG;AgAMaT|#7RdXMKw;v!P;s@@qp6hsW;4{t9f{5GK&qK~cE3qC#pE&T1>gy5t z+il(uw&mrc^0#xOAR8arJ@R*ckCtfUqO_!_pEZR*=vbbzmgxvk?JP#{>mIkcLGpQm zll2RU6N$N*sf>;!gd6j)--0W!Z-7XSZ5_U!QBS8ml zl7~fRRwlpQ?o)pS>Glw+V&@RN+N$16{oB&kre%;S9o2BVb~IZE{R6wYs|jQWpI=nI z!48qSZU2;$jcP+e{j|zc3&=ENqBXJ7KYe>Z@w~+Eg7*wFf3QP7LGEuR-ZACGUc7pv zl1|-oLW$L4efeYa%lAjzctv$NkElTej=gfJyPEOwps)OwFpVOnOr47=vunz_O%XCn zTR(VRkjBz+P|nDJhJ$YorLQJ_@xL=*n!=j5vx%G_uW!h3L*^KtjY?ltSf+e@)BiRp zjYp$Ai3qsi?3N9=GJ1qeL(0)*zHrBWM|)V(!D-<7ef9(^VnI~ zF{>VTYfBl(Zx2}%PU4)H$S1lk6f(`rDR%jyA@hnAAAJVwUWKGxe${*o5g@?!9IhIO ze5zG)0W1HLff|wJl&c8M)kr{ zK#U|-Vyp>i3yIi#M)kO4j z%zW*Iez|@U`wf0)Xb5!So~U`__L%lOkL#Q8&%ej=_uQ4ns`(#~#{?x;r>tr@bZgF1 zyM@^v3WdswYFcN=>5N-1)-!1^du#AAnm2}#a+5s1JmG7~5Gqmys$O1&IAO!0#ml0X}JgPrxb zHjDfTT*6!Qhx!B05)P>3owCb2`67=&+MI&UnNo3yr|s3jDCdK*)3p}gznmXAdFXf6 zLNdA9=K>t|M>uL9f2Q)4=RB$Qo(d^{_=#HM5gNf4KOUwtXFe!;e<3mCN3{4A`t#RM zP6c7#GbFz7P^di5^;FJ9S-3NjUJciDMd+a_ds(j055p&ir zZyH;n1xkGU079TOB&7IRcY-)^B(GQm@Oxhyg=G9@zVlRR(GC!g#dLuq7e zcX`rEfW=$qi9@azTyxhay3MW4)xp8RXdW_;c1T$@pNGy{43rd^VQFU{bp~~x zocYj|@e$ck_G(!^D%&pUT>53*68REC_uK`EVMeLqxNOrmaaT||rjJKRsL|??*YbRSdS5M4Zw+rV|q? z0!(SwZTr5#N#4DG*Bm&{c+0cT$Rf@;-8pVaXk203=t5yoQj>i6%!PBR*PnksHg#g{ zEFZlo%%}a^sG732VwXpkLFx;&_LypcbMVuS7sQM#Zhd%d?f>z??UQ9}dXK~<69ou+O(C@vuf(M_U@$mJQ+}BT{Kbxm#@S z>t^ZZ7L~0W!uEe!`BXFb#^J{$iA!1b1NNr<1O2Iez7~Tv8y$|%O_EK5Osa;}ydAv# zHe@#pH&jljl2*&bz4Hn@q1gFxSg;|le(5FE%)}VGv*9Azm)#<{SE;{o;E8^$MBAOV zy0(=zcZIW$A2RAfGo8D`KYmK;Qsh53d}%!?xFWb45!`ZI|6uP@PD)N|PWur3u)m|I zV^qCODA_q-lxo-WG>h2!hYgOj-mSwOn7bQd3)u@yl9E!?j1`jQQrS|%lD(d$ldgE@ z&1>7r`~mu5y^^{2Oi`6ml@TM}l{+}+)u!eCv1O;1!{SS&yyFXa!*y~WG5oFdrA?vD z>NV{5l5b~z^sbK{e?w0BoBeSQ%4y2y=SqdYDTk?qvD)}`WZhi+Eb%)pi;j|qlBbe) zx{Qt1^gzcTJQCgyUx8PREsPb^8nM!z)I8b3nxhbNm7ERB>fPWS5-+^%LCwL7xWs6so)|Q%G5aOs;dmZf|JtFFR%g5+0 zytdGvfsCK(-l-_|5v6=}t@A|}uou*?=cxEboO-Gi(HRYex?P`*76}(oHq?glNJ(Jq z)`OK3!u77t#>~OW>~RrXx3sNPB}98HGtsjN$nvg3U8`0CLRvz%EGy5vC%65LUx-b( z7qLoy?|znl=v9(LnncIE+|p~C%q?PB+*o)qY85xPK)>^H_9dh88_Vnoq@(;o{gA$A zp64KLJ(;U>7*B^kizl@_oG;nGbob=; zFV$Rw%A#G3rVLt*#B=R@e{9Yl6*)7(`y;zMr7-jRVy;%Tt*K41({`=5S)iYZS*ms_ zXT|#CcCm9cDK!y3gVi=45=Dbyk-^RC`lUKL`jxrVdU4xrD-}JXE4*!nL)GssngUWj zq~xdQN8`O;c5u9eDR=pG)*!sxLRrcnH*;}B!qd7Tltuc|yvs-tvgG5! z!}xFEvuTRb)|);E_3pS&Rhv~6tNn9EC8JJ$o(De)6eN@grsWlIWzTHhSt2!jfr(k$ z5t@y1Amu&riJs2IrU~Bq?kL3?1D6CY@#;vYtH{Q5)hA@OSV#(E1={D!(khiE$MtQx zRcv1I+hR5jj5?#_Bxd$4a(kv;n9-W9tvr5s=fwtUV^C_~T$^W{-R!qn8<_OM=Gf8g zGa;tO%6?!|8da?M8jN9n=VzLWvchw3nNpc}dzg4_%`Dc{)Km!WTo|{)^Hv%4l&GP4 zw_C={DlSVwDTc|)Tvr`yhtI9~uQBdues9>wxxZGls4p$xr?J*CKlb~=n}ra?a7H(& zNNL|*?bWpHcx+ssbpM+ETQh5KZSRUW?zmN{EFZ^BpTSX!9Y@T`wJ)nJn^B9V5jB^5 ztG15ss0|K2E1?)s^K192S-TMd3vpwx;nHdMzwLE+%U1+~MoZyC`{zcLA32o{ zoV*R3G{j#Zb#9<OO!c+&%?n9ICVfElF}Yda0@#Gn%Nv-jdYY^U96~K zWky;`vFeMe38*>AA#9LJUM>i2uj@J%UUn7|maNh+a!C&;Aix2EhBJFO*gLvHJ)~F( za-l#Q?B-`>CXk@*q*!G@h0Hh9G??X3E(m5(zDv9of`Wp~ViJ6UqT<3rq8FKk1O!F- z1tj2&7k)!KR>;M$`J>X9Kf_wt}|HNcz@r%dF&BdNznxzFl!XDv(a74QTe1iYT z=k&)(?-%=DRQ?+NSH*x&)YSf&`44*?9R5+YEBfj!0D_;8{zdH{oUS^aP6&Q2ge%I; z#R75l7BCgIf0{iSY4xXb{vrt+`B&Q!9>{-T14nk*2%)g+AxU7aP&pR_9F33%9vBco z;=BTvcm+gsgan`hB2YmQpbZrekmUax<)2IAf8isU$TO;_L9IYk!|Li29{1sPFIg~xh1(+rRCM?PSPu>5>1zbyL?A}ViEyux2*KpsNo zL*W+SY6x?M-$GbQ^8cmpPosYE{bWM^-@0#CJ`wxB>u|S0IQ}KM|CX4$q6k#~F2ogO zg?5L#AY`n8i1_a^Ygg`H8UI~@g$>-%8es|J{{y=}I{wZg$q#Ng_Q=2bZnyWZE+r&4 z5ajxe|dgnp{~TQ?CGxZLlqMA|@Qf`DBT6%`hhXh=>XH;UY$3&-OlCdqPA^un!k88hf_);o1`-VuF3R zh|$=yy${!(5D^pX!$pk7p6z|O_JoL-U>`1GH1=%o!?hqZdmpYnAtEN& zhl?1EJ=^1Ttp>fe64L5X!KLx#(Ho(~{B3@-jLe19QWk&rIFmJ4@}ui>~nr%16ljZ<}?;G``BCiuT3=qCf4VE3LB zyXFDL-VUSsY3bi&`~w9z(VwPF)d2st#^1-5t}kS8gE=%Ks zm#3G5MR@_gK_pjK;SoU9mVeX~KCFpPi&mi=Jq(|74r9l-w3AMF#Ywh@TMXt8 z2$o#5n|*}k)S?y45nO_84A8ik=;vUY^Di1iiq3>Oox~~gwdA+?pJ~Xe)l+HJQ`z~^ z`4JQoD>~(fujU_Jn=E&<)^!|Qr9RvH#4uZfw_fzZ9rac}jkv{@W#j(hE{XTo8_DqL z7b-8dJYx?^Hu4j7n!}-@=E6e-t_FsegkXgbhGZARWG&&y+byEAPt?TbY?k@?>t=C3G zC$|TE)#DT>iYar`5QEYEO{U1z1HdHa zv9XB29&BchZMhKizSN1Q$rS5i8My;#wnf}EohQnWP0qs^!a3M^X9nRM!918G_SSDQ zy1;bZz&N-^mTQ`urHAd+UCJPM=52*022=5jg{ky&Ym6a_wXsG1kKpK%sI<(x+(718 z2#!TeHP~&5nnVbUB`~u0D0t2ML5I6v4xj#LaYyTJgFTJ{H zx|wY2oRHG%f6WEx_HLiq7+9AMlt@}X8~VC^C7dQmujW~S3@{sx2`UtxEber>sIHRG zfS-F4L*9bNCAJCw$~3u=Ysp@f^Z0Io_C2{4?3qT(DfgEKkQ?9A-sr|(8c zzzf^9C;H!Ymo<3h4@&J!ZBT9D+_}z00WOe*RbSLzAGwTa{dQdHhfiwm5FIwX>SC;` z>e<&>Olsemc+y5EZd&o?ypEm!+1zaMF1x7tep?I8Hi#r=Y^ z#6A>sE0M>#sih}l90uc=7N+Mn`kp2qMFkb&>So*!d;sQbD|J*-3<7DA)xKk`PxKr= zbKfEe5bx&|K+jzEIU9iPiqY9YkAAi+Udu_XcFE^ZUSCWT-r6$h!pbrNw2HHHVr5V( znX}1vk_-u97#b`s+3|^q;l_0YP^FS2moe< zT0Ph*f(N&Zdi4GM1wC;3R5<6Gw4Eu7--?WG+L&Z_SUdKuv&IUWp|Em+k>SJA!%@?z zqFqyoVxaO`kz}Uo64u<|BEn}#3stWeSPp)1lHuemZfd7{rS7NCg_@C@ksPHV-@Q;l%4a&wUyUlzTY7f_gDyyPZC}$SxJy< zR-UVHuPdLQnWN#zX=(ee>vn8Kaq=L4KJv{p^F$ZN1QvTgZn$zwW_}>R3g7wqVFJwk zTM*WOPpS~s)xOQq!)^LfmM{!`95eRGO#4l^HD~knWKD?I`ZW_E zl-%D-pq$;hH-)YZdcQpd(gB&=3@k3|E*s}Lhn-r&qpRK37frt_06`Gq(N0plU5c5V ziA-xgI(lW-sv4i9r0`WfipPE%AvY*0-;77~#snmws)oCcjcPoPGEx|*uHM1vi+gsCoS`|MW;!c0y^c%5u zJW`bN$yUhyCEt4gu#cUYpzl?{x7(BJvvO8D&v4Xi&CA&+wIXA*=qc;2DA=d{>B-6Iuk)9g< z_G4O~Ty9jmn(N~CB|ABUR52&$D|UKq=%TnfX)AB2hEz$}CPE@*oUq6^I$fN}7xvLL zku%_nb#q8JjACRen-kX$T+m$bH>=_Ogu!}Y35$$b6Oh&LW!2cy#!uT75hp3Mk^PSo zK7I0_JqEhDQYFOX=1e$>`0Nm`Y=sdSm?1GrKyTO4qkS z$qyYG-IL#5`cCTW8L=L@s9rV^a>HG+#Ymg5m75f99#Rh;4BRZQvRwu2bJx|$YiZEp ztGd+vmC?)K5SSrMk7YZn?1Z=Mbu$~xzIs3jHUxiNIa@w~HhWqqaj_76tj&U7sWQs$c$A z)coT67h~f2Sok?A4YO0TzG(N219e@6G6r*yWo^dcQenIBCf#Ae+@V~*d4r?V?ROU-y#slie&3Y?6Z1S}0AFLph}mf?)m zWkfYZ(=!M3b&CeluB9YiOJQwrhVr;{i2&>6D4vYJ-Sxb3BImgcyagz+AB=;Jm-p)=Nr>mX z$W8@L4NuvdX?v%?Zd=mE(iCG$T}(=jxl?i;IiP#*if>)iB0ir%vDg8KBpB2)&iz8A zcnHn?1Vgw=tCdQ&o;IA8J7l~~qTw!$Cq=+e7@SV%xOSvNQ!#^Q4o~}W?zwM4ob7?*8yoylwiGuSDd6VKfKBM7_`Z^guGJizi z8Y8EgiXHlkhl8Yn;7p47*8C1T|6DPlRzQbZ;o+Cxbyeafn}cP|Cp*2nLg9@f$D$+8 z5AwD9RpfBApZme7fBIn7Qj_m>6xNx6i#$naS~K~%^J78dC+7mVxKbs5{_46 zf=oYXp<}di)z(7ll0bw{1AY}c)+F!&zR?w_SeRN{E#H`C^C8fePa5Y^RO{cn9Nzw! zU4-^~TYO72vTtprw)88j*rSGO5vNiN^FkH1vn-5^qiTNZY?n0xW`Bw<-!Pt>1UNtm z9mcf0Q7^&-g{kK$qgu!)Rb`E~8OG`QmM}=~4H|Hj`s2Rf&x;1aox{Q1tBb!<5MNzv z_CmlrmCL9WF|>n3wWn+Ekqh@7Dh)FAN4_2g7OoJkQ%eaU?xBKgb{GL5F~M>@lIZ_MFBgZnR-mf|UZ_Et4LaGP|C zdqPfs97war3fj_rJ{Li{qFy=REUrEX zRQ#iIgXYj3 z21X!cMmeiI&)=w+nYqU2DDJm0&u3 z-z(?%V_5@1{I(xx(7~=t6OmlJ1~$m114cmcKG{FGGx9ntZst&YQ8Ye}b*^*PDo!;Y} z`>3C^KKLNuQiF@)o^&OwH_ERo_T6VWir(D*=XU*v=uJUvNxh&GIp?>&NzoY0AML4e zu^TEPEf-JyK2jHAsl=V^XBN%LFl9GFNRYS__&cs@CQf%bl)b9;riI1)xxH+R2yT{Q zz^(BXuWa9=SMHo|w_Im8PwM#c6$48uH0=U8z(3SNaIi(-i z$|JYEv#9dj%&s$T;1j`U^}x-<@WV_^>peymQUXCE#tMW4k!dumE4hBohf=jQP{Wp^o%c0Jio_T`+y5%d# zwkP1?@Qe)4#At&JJ#lf7ZD;9SkZ;N2Xw<<>|Bh~)(m8Ijexhc1g>V*8 z(a-UYME6&4XZB6@QaS5Nf|=LR#S)bqtiDos)5>#l-7Pewd^2Hz-c;H#AtjW_gt3?q zD4vhG2up?MTGa-`h)KM(@^kj-GlpKk#mZ5|w>3_cY4-+7inpeJmzOq^+CI~H63jX& zCS3oW1XTP&3$iAB6Fkp5JS$0HfVFo{MV1P&Pu?&5KA=%U(Xay-{uwF8Phn0ElH3=~ z;yx^dlJiz@bq3V8&D*(V22|gAn3ic&k2BL}UoWAday2>!+AhE=yD->!K5ZjrGU|@E zm1|D0V^9y%eBbuh{?0S%-wM}qCUL&NogLr0TC(}wxXo)IEULj_DxD)0F^0Z(IchKw z_|!KYDem=NX#Y?LDIaweCfLx-kmDyNn)M-mHV1N!1^hf{-P=O4GMy29AYgJ`t1CH^ z6+cat<1=*DUbjB8cb@gptLvyen>tcnl9IHR5B1yGc+*j`_^8O`Zu~H?t^!K40Ht@& zrowJLOS)R{0q$o;-T5`WBULYfGyLn$odgqOi>yWbWQ>l!^wZ2})y)^(gkVRWaZ%1c zHdDA|A6r;5?Abb#g&%Gy+aBEtiW?H~9C-zXsnu*@QxxZv;y;Tun2;C{=Z$*Wq?WT9+E&G|F=8AA6(#X!UhLK zAUH+fNg|bFRJ6U+64txE;U>z$6dtywn}zc+%fX%k<8=6#=WD&Je$ywtXg3#baI=R_ zIqGh#Pk1sCg6uR4D&u2%)+e*Bh$SxjmyUrx3sSRLdXt2A4#*fn?7GXwu?HDuM*?RT z+m-Shn<~P#Jva^n%K3%24~Ik$1XW2-5C)eg@@fUN3i>swMmlP`L#@Zr{T!=4SHMej z6NwNuu&}v6&|4lh<(b2-Onp_ej2m^S$ELf-{!))^5%tw4o$R`i*4#Mb-(EPpQ0;n# ze4fu>6f)kphQU|oGN*F`hX`&O;0KV_;M}}OSYZ{|P=S)IT6NBVtRh3;kO!0_SK;a6 zK@q7LxQqIl)Z9w=PvLitoef}lCt^8RY(E&;3p-=F!~+~+fY&1J%Rqr-Ke!+dB1+$f z51T5(N$N);u65}+Q*%9JyAMz1d`R7p*C{gddMG$iL#CnRfd^jtpeA3gLdhgFguZwF z(6HNZThDB;F*nzcS^&f2#@BjsNqT(SLZW z2_`1+?)DEY1Pc5Q(9%bAzh0200_85`%9+PTz^}LO*$4+4$gelPfXDuP7uy%G!vImb YDgT+?-JJ&f@4CuYugmAi-n{#N0G`TvF#rGn literal 0 HcmV?d00001 diff --git a/docs/images/wrapContent_example_1.png b/docs/images/wrapContent_example_1.png new file mode 100644 index 0000000000000000000000000000000000000000..38ca574f4b5225b47726a16b01e3d71225637a91 GIT binary patch literal 60959 zcmeFZbyQXF_by6zBPG%;0vizNmXef4YSW@fcc&oTp>&skfOKu??vn15?!0S*pYQpe zbMN^6&basdbI15GmI8b2wbp#!Ip1eK^O^7Fi;{vACfZXp7#J8#8R^%`Ffd3MFfgzU zC`iC7a30|%FfbUj=HlW?GUDQtO14&}<`%$9(qG~dkX2P=h&ngoXlZFHMHrREtVZ~y zOK}mh(O!w+Ni$L*_y&{ds)AYagTN9R5*8m}jo;$BX(71jMbY5f5=Bu7)byU)6M2qRgPn|ovKs*?+{c&B$y-o{T-a|Td~rZR>I?%X##yPqkq zprx@RZk1dMX*JB|k}cIXRj7$Ah#W*$p~<2w5^Z8#>{-sa@n=H~p$NZk=|=aT!~nsF z6zDiA@fhoNNk;cM-y576gqRo^2z=G)ija-nkP28%PF%Wqp8;a#Fyv7rN$Y&N^i)sJ zdRJQRE2Tdo$-H>w+sMIS(gBwykw_d=E!3mihQ6tTr5}Unmp)Nhb~1+9UzY?sMI7g) zSrTQw^3Y0>N7No67IztVy%rK?l@lWT)?v{5^1bN5;+lLg@o?)JB4Y0;SVF+yrc9w& zCzb+-^I5ZQEP>#&2(IIDu^dmDu1_wAKWL1ukC$5MOA(Ptb`OV-Tx=ZPdfF%JkPaZ= zQsN-M(nq$$quGie;Z&Y-o%lqh;yAgLlbVfirFt zP=dMDmux)B!jz6VCG3(k_GO5yupyg8KL16tIE?*DYL@Jrn50vcJSmP?4ukqLu6R)V zD5AtN#SsTAvU()qH)8)*PHc6$amr`IcP!XTs2P3-LDqglGBxmcEk?u)7g7NW<*1S# z_#zB_PdRjSx6j9yOqG73lY6^~-zxDBv^aQU?qM(=c6u0mVja5vQ+Uh&CmMI$*p1`O z1nqSci)W}xxw0(@8O`@UZYj391zB+j;b%8I+KWyD=7+62c8%QG<$6@ZAhp^{; zL=i-#Q7|)Teh0xC25ZuU2k|faA<*DTV?_IBQ*H&}L{ZvBN=P#)hpSR)N4;CsSY@=u ztM#_0bc$rnCUOaL7h{hNF3fVxC;1Rqmv#4^=V_pV#OSb2C5~<=s}%F_Q+w=p5vi}) zGPs8nP7wLLVdZd*z@HN_*TWGF-)eHifBy2rMH5xsXB>Q8M(>Y4c~NrP~V)xUh6t;Qe@-{xbgdzc9quGknYZto^N# znp6b+onBK%iN0j0gE(=0Nfb?%e?enOyT?$4!yh!)28;J4TfUs$B_>naLRqLFu`;zX z(B9WRZcO|tJv|?szL<}b8CguJ%BY;LH1*wDXQ}X)N`PoN+H~x$OgOb&cSRR-*G#wk zD)TD&5v4?&p~7Kq+glDsbf&mik66yw>sapK;9$vM@?d-d#9;I%%mmnssT#Y=H_~cZ z@7}@}sN~~q+ioj-KtIJg#SD|=%(@(oHovS~t99_cAWV*WO?|8CbieBm$yerV# zDjbnDDK9T5Z$5gtCbovQCf=hFd#&2_-1NE6bBj2a=i|?%)GP}y@<-IjRI^ko)OuB& ziu9B`awU~HRnXN}3R%==avk4%{}w(Rw&i1w<$>$Le~Zy5m6C5+GN3%D#HO}TG@m

f{@4 zNvEp4S985}@UB;`8Lrfgr>=P?S0^M_o>wGSA5S87&Yuopx?><9eZ){87BKq&x=qsR zd$VqC+MH2hkeJbCU1acWDLtz8ZNuBBVb3h&jweP=D=$~LI=*+@(j(F1%dIDlCCzft zeXIL+BtMyy%IRTcY8n5&s;wBZn^YUm+uJbIFmTg^*#B#idNQ+PxsGmlWR7FhHp`@* z;KQ0>dv#$|onhF!`giEX-0z%1=|WG5nV)HMp2cI1cP!+#nwH=zx*Zr~0lb-3{NgEB_ zmsRLTqQ{B2> z(46D-`JVhf0rm`b*_#G-A6^iC1E~tZKr};?PV^Jx1LP2*2Ei5&6&n%X7P}JH6*CL0 z^2h!4t5rQ<&T#7oPw_kTd*|vyyUsMMyw9DVH3Ec#%Yt#FUdoFwgr=3b{<@VOl{PRI ze-dOU@jcuX=M#Af>Fvzx<+jZ)Rk%mLeEw4P0

    ^G{}*gnY;;A)Dsxt;(jNL;IWd1Lxt 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 P5Byv@ucuL{}@N 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 S8vO6h@-oWOnOAPz|Nj6>kU1m( literal 0 HcmV?d00001 diff --git a/docs/images/wrapContent_padding.png b/docs/images/wrapContent_padding.png new file mode 100644 index 0000000000000000000000000000000000000000..b71b2303e3b5a0b1bb0e440da9d5a309e7b58027 GIT binary patch literal 25830 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 literal 0 HcmV?d00001 diff --git a/docs/images/wrapContent_vertically.png b/docs/images/wrapContent_vertically.png new file mode 100644 index 0000000000000000000000000000000000000000..32b5af9b5f8463510298b9b744941a8390fd0061 GIT binary patch literal 25552 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 Date: Tue, 5 Jun 2018 17:58:45 -0400 Subject: [PATCH 5/5] Update following reviews + update doc --- README.md | 15 ++++++--- Sources/Impl/PinLayoutImpl+WrapContent.swift | 32 +++++--------------- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index a134fc6c..2765ecb7 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co * Swift 3.2+ / Swift 4.0 / Objective-C ### Recent features -* :star: Add `wrapContent()` methods that adjust view's width & height to wrap all its subviews. See [wrapContent](#wrapContent) for more information. +* :star: Add `wrapContent()` methods that adjust view's width and height to wrap all its subviews. See [wrapContent](#wrapContent) for more information. * :star: PinLayout now support macOS. See [macOS Support](#macos_support) for more information. @@ -1147,10 +1147,17 @@ The following methods are useful to adjust view's width and/or height to wrap al * **`wrapContent()`** **`wrapContent(padding: CGFloat)`** **`wrapContent(padding: UIEdgeInsets)`** -Adjust the view's width and height to wrap all its subviews. The method also adjusts subviews 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. 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. WrapType values are `.horizontally`/`.vertically`/`.all` It is also possible to specify an optional padding around all subviews. +**`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. + +**Types:** + +* **`WrapType`** values: + * `.horizontally`: Adjust the view's width and update subviews's horizontal position. + * `.vertically`: Adjust only the view's height and update subviews's vertical position. + * `.all`: Adjust the view's width AND height and update subviews position. This is the default WrapType parameter value `wrapContent()` methods. ###### Usage examples: ```swift diff --git a/Sources/Impl/PinLayoutImpl+WrapContent.swift b/Sources/Impl/PinLayoutImpl+WrapContent.swift index 0a5e0da3..01f8fde1 100644 --- a/Sources/Impl/PinLayoutImpl+WrapContent.swift +++ b/Sources/Impl/PinLayoutImpl+WrapContent.swift @@ -51,47 +51,31 @@ extension PinLayoutImpl { private func wrapContent(_ type: WrapType, padding: PEdgeInsets, _ context: Context) -> PinLayout { let subviews = view.subviews guard !subviews.isEmpty else { return self } - let firstViewFrame = subviews[0].frame - var minX = firstViewFrame.minX - var maxX = firstViewFrame.maxX - var minY = firstViewFrame.minY - var maxY = firstViewFrame.maxY - for i in 1.. maxX { - maxX = frame.maxX - } - if frame.minY < minY { - minY = frame.minY - } - if frame.maxY > maxY { - maxY = frame.maxY - } - } + let firstViewRect = Coordinates.getViewRect(subviews[0], keepTransform: keepTransform) + let boundingRect = subviews.reduce(firstViewRect, { (result, view) in + result.union(Coordinates.getViewRect(view, keepTransform: keepTransform)) + }) var offsetDx: CGFloat = 0 var offsetDy: CGFloat = 0 if type == .all || type == .horizontally { - let contentWidth = maxX - minX + padding.left + padding.right + let contentWidth = boundingRect.width + padding.left + padding.right if contentWidth >= 0 { setWidth(contentWidth, context) } - offsetDx = -minX + padding.left + offsetDx = -boundingRect.minX + padding.left } if type == .all || type == .vertically { - let contentHeight = maxY - minY + padding.top + padding.bottom + let contentHeight = boundingRect.height + padding.top + padding.bottom if contentHeight >= 0 { setHeight(contentHeight, context) } - offsetDy = -minY + padding.top + offsetDy = -boundingRect.minY + padding.top } if offsetDx != 0 || offsetDy != 0 {