diff --git a/PinLayout.podspec b/PinLayout.podspec index 113ce5ff..709400e6 100644 --- a/PinLayout.podspec +++ b/PinLayout.podspec @@ -24,6 +24,6 @@ Pod::Spec.new do |spec| spec.tvos.deployment_target = '9.0' spec.tvos.frameworks = 'Foundation', 'CoreGraphics', 'UIKit' - spec.osx.deployment_target = '10.9' + spec.osx.deployment_target = '10.10' spec.osx.frameworks = 'Foundation', 'CoreGraphics', 'AppKit' end diff --git a/PinLayout.xcodeproj/project.pbxproj b/PinLayout.xcodeproj/project.pbxproj index bcbe9fef..c653fc50 100644 --- a/PinLayout.xcodeproj/project.pbxproj +++ b/PinLayout.xcodeproj/project.pbxproj @@ -23,7 +23,6 @@ 243C62081FC37F6C0082C327 /* PinLayoutImpl+Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6C81FC37C1C0054CADD /* PinLayoutImpl+Warning.swift */; }; 243C62091FC37F6C0082C327 /* Coordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6D21FC37CD40054CADD /* Coordinates.swift */; }; 243C620A1FC37F6C0082C327 /* TypesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6CE1FC37C570054CADD /* TypesImpl.swift */; }; - 243C620B1FC37F6C0082C327 /* View+LTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6D01FC37C8C0054CADD /* View+LTR.swift */; }; 243C620C1FC37FA30082C327 /* PinLayoutTVOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2475B6D71FC37D4D0054CADD /* PinLayoutTVOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 243C620F1FC3834B0082C327 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 243C620E1FC3834B0082C327 /* Percent.swift */; }; 244C6E151E776A0C0074FC74 /* MarginsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244C6E141E776A0C0074FC74 /* MarginsSpec.swift */; }; @@ -39,7 +38,6 @@ 2475B6CC1FC37C1C0054CADD /* PinLayoutImpl+Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6C81FC37C1C0054CADD /* PinLayoutImpl+Warning.swift */; }; 2475B6CD1FC37C1C0054CADD /* PinLayoutImpl+Relative.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6C91FC37C1C0054CADD /* PinLayoutImpl+Relative.swift */; }; 2475B6CF1FC37C570054CADD /* TypesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6CE1FC37C570054CADD /* TypesImpl.swift */; }; - 2475B6D11FC37C8C0054CADD /* View+LTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6D01FC37C8C0054CADD /* View+LTR.swift */; }; 2475B6D31FC37CD40054CADD /* Coordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6D21FC37CD40054CADD /* Coordinates.swift */; }; 2475B6DB1FC37D4D0054CADD /* PinLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 2475B6D91FC37D4D0054CADD /* PinLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2482908C1E78CFFC00667D08 /* RelativePositionSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */; }; @@ -53,6 +51,15 @@ 24D18D241F3E37DD008129EF /* Pin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D231F3E37DD008129EF /* Pin.swift */; }; 24D18D261F3E5EA5008129EF /* Pin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24D18D231F3E37DD008129EF /* Pin.swift */; }; 32A65F57D5D8D5204831FF3A /* Pods_PinLayoutTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 417E52FC81E208F91CF03C1D /* Pods_PinLayoutTests_iOS.framework */; }; + C80435D320D0891C00EB1BD7 /* SizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */; }; + C80435D520D0898000EB1BD7 /* Layoutable+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */; }; + C80435D620D08A2B00EB1BD7 /* SizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */; }; + C80435D720D08A2C00EB1BD7 /* SizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */; }; + C80435D820D08B7300EB1BD7 /* Layoutable+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */; }; + C80435D920D08B7400EB1BD7 /* Layoutable+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */; }; + C82DC20C20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; }; + C82DC20D20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; }; + C82DC20E20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; }; DF1A5CBB208106A900725EF5 /* UIView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */; }; DF1A5D0420812DE100725EF5 /* UIView+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */; }; DF1A5D202084C94700725EF5 /* PinLayoutTestMacOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1A5D1F2084C94700725EF5 /* PinLayoutTestMacOS.swift */; }; @@ -72,16 +79,12 @@ DF1A5D412084CFD600725EF5 /* Coordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6D21FC37CD40054CADD /* Coordinates.swift */; }; DF1A5D422084CFD600725EF5 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 243C620E1FC3834B0082C327 /* Percent.swift */; }; DF1A5D432084CFD600725EF5 /* TypesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6CE1FC37C570054CADD /* TypesImpl.swift */; }; - DF1A5D442084CFD600725EF5 /* View+LTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2475B6D01FC37C8C0054CADD /* View+LTR.swift */; }; DF1E39B520482B200002D0AA /* PinSafeAreaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1E39B420482B1F0002D0AA /* PinSafeAreaTests.swift */; }; DF28022420C2B13800A1833B /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CC20B999BD00AC2A84 /* Types.swift */; }; DF28022520C2B13900A1833B /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CC20B999BD00AC2A84 /* Types.swift */; }; DF28022620C2B15A00A1833B /* Types+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CE20B99A6600AC2A84 /* Types+Description.swift */; }; DF28022720C2B15B00A1833B /* Types+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF222CE20B99A6600AC2A84 /* Types+Description.swift */; }; DF7A36BD1E918301000F9856 /* PinEdgesSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7A36BC1E918301000F9856 /* PinEdgesSpec.swift */; }; - DF96F30920CB5DB7007CA714 /* View+Rect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF96F30820CB5DB7007CA714 /* View+Rect.swift */; }; - DF96F30A20CB5DDC007CA714 /* View+Rect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF96F30820CB5DB7007CA714 /* View+Rect.swift */; }; - DF96F30B20CB5DDD007CA714 /* View+Rect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF96F30820CB5DB7007CA714 /* View+Rect.swift */; }; DF96F30E20CB6362007CA714 /* PinLayoutObjCImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241A277C1F8E958F00B1AD39 /* PinLayoutObjCImpl.swift */; }; DFABC01F208781A900CB6494 /* Types+Appkit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFABC01E208781A900CB6494 /* Types+Appkit.swift */; }; DFABC022208781ED00CB6494 /* Types+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFABC020208781C700CB6494 /* Types+UIKit.swift */; }; @@ -197,7 +200,6 @@ 2475B6C81FC37C1C0054CADD /* PinLayoutImpl+Warning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "PinLayoutImpl+Warning.swift"; path = "Impl/PinLayoutImpl+Warning.swift"; sourceTree = ""; }; 2475B6C91FC37C1C0054CADD /* PinLayoutImpl+Relative.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "PinLayoutImpl+Relative.swift"; path = "Impl/PinLayoutImpl+Relative.swift"; sourceTree = ""; }; 2475B6CE1FC37C570054CADD /* TypesImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypesImpl.swift; path = Impl/TypesImpl.swift; sourceTree = ""; }; - 2475B6D01FC37C8C0054CADD /* View+LTR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "View+LTR.swift"; path = "Impl/View+LTR.swift"; sourceTree = ""; }; 2475B6D21FC37CD40054CADD /* Coordinates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Coordinates.swift; path = Impl/Coordinates.swift; sourceTree = ""; }; 2475B6D61FC37D4D0054CADD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2475B6D71FC37D4D0054CADD /* PinLayoutTVOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PinLayoutTVOS.h; sourceTree = ""; }; @@ -219,6 +221,9 @@ A02D58138C6BA063EB3E8E66 /* Pods-PinLayoutTests-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutTests-iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-PinLayoutTests-iOS/Pods-PinLayoutTests-iOS.release.xcconfig"; sourceTree = ""; }; B7A69A7C17E9071CF457C39A /* Pods_PinLayoutTests_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PinLayoutTests_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BC74F9FA5B66BF5C299B7581 /* Pods-PinLayoutTests-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutTests-macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PinLayoutTests-macOS/Pods-PinLayoutTests-macOS.debug.xcconfig"; sourceTree = ""; }; + C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeCalculable.swift; sourceTree = ""; }; + C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Layoutable+PinLayout.swift"; sourceTree = ""; }; + C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Layoutable.swift; sourceTree = ""; }; C8BDEE8FC7F6D6F36D69AE89 /* Pods-PinLayoutTests-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutTests-iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PinLayoutTests-iOS/Pods-PinLayoutTests-iOS.debug.xcconfig"; sourceTree = ""; }; DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+PinLayout.swift"; sourceTree = ""; }; DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView+PinLayout.swift"; sourceTree = ""; }; @@ -228,7 +233,6 @@ DF1A5D2E2084CF9700725EF5 /* PinLayoutMacOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PinLayoutMacOS.h; sourceTree = ""; }; DF1E39B420482B1F0002D0AA /* PinSafeAreaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PinSafeAreaTests.swift; sourceTree = ""; }; DF7A36BC1E918301000F9856 /* PinEdgesSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PinEdgesSpec.swift; sourceTree = ""; }; - DF96F30820CB5DB7007CA714 /* View+Rect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Rect.swift"; sourceTree = ""; }; DFABC01E208781A900CB6494 /* Types+Appkit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Types+Appkit.swift"; sourceTree = ""; }; DFABC020208781C700CB6494 /* Types+UIKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Types+UIKit.swift"; sourceTree = ""; }; DFB3ECB02061602E005F226B /* PinSafeArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PinSafeArea.swift; path = Impl/PinSafeArea.swift; sourceTree = ""; }; @@ -355,6 +359,9 @@ DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */, 24D18D231F3E37DD008129EF /* Pin.swift */, DFF222CC20B999BD00AC2A84 /* Types.swift */, + C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */, + C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */, + C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */, DF1A5CBA208106A900725EF5 /* UIView+PinLayout.swift */, DF1A5CBC208106C900725EF5 /* NSView+PinLayout.swift */, DFA06B031E8B38B300B6D5E7 /* Impl */, @@ -414,8 +421,6 @@ 243C620E1FC3834B0082C327 /* Percent.swift */, 2475B6CE1FC37C570054CADD /* TypesImpl.swift */, DFF222CE20B99A6600AC2A84 /* Types+Description.swift */, - 2475B6D01FC37C8C0054CADD /* View+LTR.swift */, - DF96F30820CB5DB7007CA714 /* View+Rect.swift */, ); name = Impl; sourceTree = ""; @@ -831,17 +836,18 @@ 243C62041FC37F680082C327 /* PinLayoutImpl.swift in Sources */, 243C62071FC37F6C0082C327 /* PinLayoutImpl+Relative.swift in Sources */, DFF222CB20B9994300AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, + C80435D720D08A2C00EB1BD7 /* SizeCalculable.swift in Sources */, 243B12BC1FC393580072A9C3 /* Percent.swift in Sources */, DFB3ECB72062A937005F226B /* PinSafeArea.swift in Sources */, - DF96F30B20CB5DDD007CA714 /* View+Rect.swift in Sources */, + C82DC20E20CE9F6800B7ACF5 /* Layoutable.swift in Sources */, DFEAF75420C9667D00E33147 /* PinLayoutImpl+Size.swift in Sources */, DF1A5D0420812DE100725EF5 /* UIView+PinLayout.swift in Sources */, 24B02B091F2A713000C18179 /* Filters.swift in Sources */, 24B02B0A1F2A713300C18179 /* PinLayout.swift in Sources */, - 243C620B1FC37F6C0082C327 /* View+LTR.swift in Sources */, 243C62091FC37F6C0082C327 /* Coordinates.swift in Sources */, 243C620A1FC37F6C0082C327 /* TypesImpl.swift in Sources */, 243C62061FC37F6C0082C327 /* PinLayoutImpl+Layouting.swift in Sources */, + C80435D920D08B7400EB1BD7 /* Layoutable+PinLayout.swift in Sources */, 243C62051FC37F6C0082C327 /* PinLayoutImpl+Coordinates.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -860,9 +866,9 @@ 2475B6C51FC37A900054CADD /* PinLayoutImpl+Layouting.swift in Sources */, DFF222C920B997A500AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, 2475B6CF1FC37C570054CADD /* TypesImpl.swift in Sources */, - 2475B6D11FC37C8C0054CADD /* View+LTR.swift in Sources */, - DF96F30920CB5DB7007CA714 /* View+Rect.swift in Sources */, + C80435D320D0891C00EB1BD7 /* SizeCalculable.swift in Sources */, DFEAF71220C8081800E33147 /* PinLayoutImpl+Size.swift in Sources */, + C82DC20C20CE9F6800B7ACF5 /* Layoutable.swift in Sources */, DF96F30E20CB6362007CA714 /* PinLayoutObjCImpl.swift in Sources */, DFC97CA71E8A8F2C001545D5 /* PinLayout.swift in Sources */, 2475B6CC1FC37C1C0054CADD /* PinLayoutImpl+Warning.swift in Sources */, @@ -871,6 +877,7 @@ 241A277D1F8E958F00B1AD39 /* PinLayoutObjC.swift in Sources */, 24949A2E1EF69474003643D3 /* Filters.swift in Sources */, DFB3ECB12061602F005F226B /* PinSafeArea.swift in Sources */, + C80435D520D0898000EB1BD7 /* Layoutable+PinLayout.swift in Sources */, 2475B6CD1FC37C1C0054CADD /* PinLayoutImpl+Relative.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -943,9 +950,9 @@ DF1A5D422084CFD600725EF5 /* Percent.swift in Sources */, DF1A5D3E2084CFD600725EF5 /* PinLayoutImpl+Relative.swift in Sources */, DFF222CA20B9994200AC2A84 /* PinLayoutImpl+WrapContent.swift in Sources */, - DF1A5D442084CFD600725EF5 /* View+LTR.swift in Sources */, + C80435D620D08A2B00EB1BD7 /* SizeCalculable.swift in Sources */, DF1A5D352084CFC100725EF5 /* NSView+PinLayout.swift in Sources */, - DF96F30A20CB5DDC007CA714 /* View+Rect.swift in Sources */, + C82DC20D20CE9F6800B7ACF5 /* Layoutable.swift in Sources */, DFEAF75320C9667C00E33147 /* PinLayoutImpl+Size.swift in Sources */, DF1A5D3A2084CFC600725EF5 /* UIView+PinLayout.swift in Sources */, DFED155120853085009EF9A7 /* PinLayout.swift in Sources */, @@ -954,6 +961,7 @@ DF1A5D3D2084CFD600725EF5 /* PinLayoutImpl+Layouting.swift in Sources */, DF1A5D3C2084CFD600725EF5 /* PinLayoutImpl+Coordinates.swift in Sources */, DF1A5D402084CFD600725EF5 /* PinSafeArea.swift in Sources */, + C80435D820D08B7300EB1BD7 /* Layoutable+PinLayout.swift in Sources */, DF1A5D432084CFD600725EF5 /* TypesImpl.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1320,7 +1328,7 @@ INFOPLIST_FILE = Sources/SupportingFiles/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = "com.layoutbox.PinLayout-macOS"; PRODUCT_NAME = PinLayout; SDKROOT = macosx; @@ -1352,7 +1360,7 @@ INFOPLIST_FILE = Sources/SupportingFiles/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = "com.layoutbox.PinLayout-macOS"; PRODUCT_NAME = PinLayout; SDKROOT = macosx; diff --git a/Podfile b/Podfile index 8b197a0c..9b22165d 100644 --- a/Podfile +++ b/Podfile @@ -38,7 +38,7 @@ target 'PinLayoutSample' do end #target 'PinLayoutMacOsSample' do -# platform :osx, '10.9' +# platform :osx, '10.10' # project 'Example/PinLayoutMacOsSample.xcodeproj' # # pod 'PinLayout', :path => './' diff --git a/Sources/Impl/Coordinates.swift b/Sources/Impl/Coordinates.swift index f900bfa7..a83a81f5 100644 --- a/Sources/Impl/Coordinates.swift +++ b/Sources/Impl/Coordinates.swift @@ -23,69 +23,69 @@ import UIKit import AppKit #endif -public func _pinlayoutSetUnitTest(displayScale: CGFloat) { - Coordinates.displayScale = displayScale -} +#if os(iOS) || os(tvOS) +internal var displayScale: CGFloat = UIScreen.main.scale +#elseif os(OSX) +internal var displayScale: CGFloat = NSScreen.main?.backingScaleFactor ?? 2.0 +#endif +internal var onePixelLength: CGFloat = 1 / displayScale -final class Coordinates { - #if os(iOS) || os(tvOS) - internal static var displayScale: CGFloat = UIScreen.main.scale - #elseif os(OSX) - internal static var displayScale: CGFloat = NSScreen.main?.backingScaleFactor ?? 2.0 - #endif - internal static var onePixelLength: CGFloat = 1 / displayScale +public func _pinlayoutSetUnitTest(scale: CGFloat) { + displayScale = scale +} - static func hCenter(_ view: PView, keepTransform: Bool) -> CGFloat { +final class Coordinates { + static func hCenter(_ view: View, keepTransform: Bool) -> CGFloat { let rect = view.getRect(keepTransform: keepTransform) return rect.minX + (rect.width / 2) } - static func vCenter(_ view: PView, keepTransform: Bool) -> CGFloat { + static func vCenter(_ view: View, keepTransform: Bool) -> CGFloat { let rect = view.getRect(keepTransform: keepTransform) return rect.minY + (rect.height / 2) } - static func topLeft(_ view: PView, keepTransform: Bool) -> CGPoint { + static func topLeft(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX, y: rect.minY) } - static func topCenter(_ view: PView, keepTransform: Bool) -> CGPoint { + static func topCenter(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX + (rect.width / 2), y: rect.minY) } - static func topRight(_ view: PView, keepTransform: Bool) -> CGPoint { + static func topRight(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX + rect.width, y: rect.minY) } - static func centerLeft(_ view: PView, keepTransform: Bool) -> CGPoint { + static func centerLeft(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX, y: rect.minY + (rect.height / 2)) } - static func center(_ view: PView, keepTransform: Bool) -> CGPoint { + static func center(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX + (rect.width / 2), y: rect.minY + (rect.height / 2)) } - static func centerRight(_ view: PView, keepTransform: Bool) -> CGPoint { + static func centerRight(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX + rect.width, y: rect.minY + (rect.height / 2)) } - static func bottomLeft(_ view: PView, keepTransform: Bool) -> CGPoint { + static func bottomLeft(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX, y: rect.minY + rect.height) } - static func bottomCenter(_ view: PView, keepTransform: Bool) -> CGPoint { + static func bottomCenter(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX + (rect.width / 2), y: rect.minY + rect.height) } - static func bottomRight(_ view: PView, keepTransform: Bool) -> CGPoint { + static func bottomRight(_ view: View, keepTransform: Bool) -> CGPoint { let rect = view.getRect(keepTransform: keepTransform) return CGPoint(x: rect.minX + rect.width, y: rect.minY + rect.height) } diff --git a/Sources/Impl/PinLayoutImpl+Coordinates.swift b/Sources/Impl/PinLayoutImpl+Coordinates.swift index 4cfb8738..4e40c787 100644 --- a/Sources/Impl/PinLayoutImpl+Coordinates.swift +++ b/Sources/Impl/PinLayoutImpl+Coordinates.swift @@ -23,7 +23,7 @@ import AppKit #endif -extension PinLayoutImpl { +extension PinLayout { internal func top(_ context: Context) { setTop(0, context) } @@ -361,10 +361,10 @@ extension PinLayoutImpl { } } - fileprivate func computeCoordinates(_ point: CGPoint, _ layoutSuperview: PView, _ referenceSuperview: PView) -> CGPoint { + fileprivate func computeCoordinates(_ point: CGPoint, _ layoutSuperview: View, _ referenceSuperview: View) -> CGPoint { if layoutSuperview == referenceSuperview { return point // same superview => no coordinates conversion required. - } else if referenceSuperview == layoutSuperview.superview { + } else if referenceSuperview == layoutSuperview.superview as? View { let layoutSuperviewRect = layoutSuperview.getRect(keepTransform: keepTransform) return CGPoint(x: point.x - layoutSuperviewRect.origin.x, y: point.y - layoutSuperviewRect.origin.y) @@ -372,7 +372,7 @@ extension PinLayoutImpl { // coordinates, but UIView.convert(...) below use transformed coordinates! // Currently we only support 1 and 2 levels. } else { - return referenceSuperview.convert(point, to: layoutSuperview) + return referenceSuperview.convert(point, to: layoutSuperview as? View.View) } } @@ -380,7 +380,7 @@ extension PinLayoutImpl { guard let layoutSuperview = layoutSuperview(context) else { return nil } var results: [CGPoint] = [] anchors.forEach({ (anchor) in - let anchor = anchor as! AnchorImpl + let anchor = anchor as! AnchorImpl if let referenceSuperview = referenceSuperview(anchor.view, context) { results.append(computeCoordinates(anchor.point(keepTransform: keepTransform), layoutSuperview, referenceSuperview)) @@ -396,7 +396,7 @@ extension PinLayoutImpl { } internal func computeCoordinate(forEdge edge: HorizontalEdge, _ context: Context) -> CGFloat? { - let edge = edge as! HorizontalEdgeImpl + let edge = edge as! HorizontalEdgeImpl guard let layoutSuperview = layoutSuperview(context) else { return nil } guard let referenceSuperview = referenceSuperview(edge.view, context) else { return nil } @@ -405,7 +405,7 @@ extension PinLayoutImpl { } internal func computeCoordinate(forEdge edge: VerticalEdge, _ context: Context) -> CGFloat? { - let edge = edge as! VerticalEdgeImpl + let edge = edge as! VerticalEdgeImpl guard let layoutSuperview = layoutSuperview(context) else { return nil } guard let referenceSuperview = referenceSuperview(edge.view, context) else { return nil } diff --git a/Sources/Impl/PinLayoutImpl+Layouting.swift b/Sources/Impl/PinLayoutImpl+Layouting.swift index b08499a1..144ef49a 100644 --- a/Sources/Impl/PinLayoutImpl+Layouting.swift +++ b/Sources/Impl/PinLayoutImpl+Layouting.swift @@ -24,7 +24,17 @@ #endif // MARK: UIView's frame computation methods -extension PinLayoutImpl { +extension PinLayout { + /** + The method will execute PinLayout commands immediately. This method is **required only if your + source codes should also work in Xcode Playgrounds**. Outside of playgrounds, PinLayout executes + this method implicitly, it is not necessary to call it. + + Examples: + ```swift + view.pin.top(20).width(100).layout() + ``` + */ public func layout() { apply() } @@ -35,7 +45,7 @@ extension PinLayoutImpl { isLayouted = true } - private func apply(onView view: PView) { + private func apply(onView view: View) { displayLayoutWarnings() var newRect = view.getRect(keepTransform: keepTransform) @@ -183,7 +193,7 @@ extension PinLayoutImpl { } } } - + private func computeSize() -> Size { var size = resolveSize() @@ -227,6 +237,10 @@ extension PinLayoutImpl { } private func computeLegacyFitSize(size: Size) -> Size { + guard let sizeCalculableView = view as? SizeCalculable else { + assertionFailure("Should not occurs, protocol conformance is checked before assigning adjustSizeType") + return size + } guard size.width != nil || size.height != nil else { warn("fitSize() won't be applied, neither the width nor the height can be determined.") return size @@ -243,11 +257,7 @@ extension PinLayoutImpl { fitHeight = height } - #if os(iOS) || os(tvOS) - let sizeThatFits = view.sizeThatFits(CGSize(width: fitWidth, height: fitHeight)) - #else - let sizeThatFits = view.intrinsicContentSize - #endif + let sizeThatFits = sizeCalculableView.sizeThatFits(CGSize(width: fitWidth, height: fitHeight)) if fitWidth != .greatestFiniteMagnitude && (sizeThatFits.width > fitWidth) { size.width = fitWidth @@ -265,6 +275,11 @@ extension PinLayoutImpl { } private func computeSizeToFit(adjustSizeType: AdjustSizeType, size: Size) -> Size { + guard let sizeCalculableView = view as? SizeCalculable else { + assertionFailure("Should not occurs, protocol conformance is checked before assigning adjustSizeType") + return size + } + var fitWidth = CGFloat.greatestFiniteMagnitude var fitHeight = CGFloat.greatestFiniteMagnitude var size = size @@ -287,20 +302,7 @@ extension PinLayoutImpl { assertionFailure("Should not occured") } - #if os(iOS) || os(tvOS) - let sizeThatFits = view.sizeThatFits(CGSize(width: fitWidth, height: fitHeight)) - #else - let sizeThatFits: CGSize - if #available(OSX 10.10, *) { - if let control = view as? NSControl { - sizeThatFits = control.sizeThatFits(CGSize(width: fitWidth, height: fitHeight)) - } else { - sizeThatFits = view.intrinsicContentSize - } - } else { - sizeThatFits = view.intrinsicContentSize - } - #endif + let sizeThatFits = sizeCalculableView.sizeThatFits(CGSize(width: fitWidth, height: fitHeight)) if fitWidth != .greatestFiniteMagnitude { size.width = adjustSizeType.isFlexible ? sizeThatFits.width : fitWidth diff --git a/Sources/Impl/PinLayoutImpl+Relative.swift b/Sources/Impl/PinLayoutImpl+Relative.swift index f30d9852..98ff0d39 100644 --- a/Sources/Impl/PinLayoutImpl+Relative.swift +++ b/Sources/Impl/PinLayoutImpl+Relative.swift @@ -23,27 +23,27 @@ import AppKit #endif -extension PinLayoutImpl { +extension PinLayout { // // above(of ...) // - func above(of relativeView: PView) -> PinLayout { + public func above(of relativeView: View) -> PinLayout { func context() -> String { return "above(of: \(relativeView))" } return above(relativeViews: [relativeView], aligned: nil, context: context) } - func above(of relativeViews: [PView]) -> PinLayout { + public func above(of relativeViews: [View]) -> PinLayout { func context() -> String { return "above(of: \(relativeViews))" } return above(relativeViews: relativeViews, aligned: nil, context: context) } - func above(of relativeView: PView, aligned: HorizontalAlign) -> PinLayout { + public func above(of relativeView: View, aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "above(of: \(relativeView), aligned: \(aligned))" } return above(relativeViews: [relativeView], aligned: aligned, context: context) } - func above(of relativeViews: [PView], aligned: HorizontalAlign) -> PinLayout { + public func above(of relativeViews: [View], aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "above(of: \(relativeViews), aligned: \(aligned))" } return above(relativeViews: relativeViews, aligned: aligned, context: context) } @@ -51,22 +51,22 @@ extension PinLayoutImpl { // // below(of ...) // - func below(of relativeView: PView) -> PinLayout { + public func below(of relativeView: View) -> PinLayout { func context() -> String { return "below(of: \(relativeView))" } return below(relativeViews: [relativeView], aligned: nil, context: context) } - func below(of relativeViews: [PView]) -> PinLayout { + public func below(of relativeViews: [View]) -> PinLayout { func context() -> String { return "below(of: \(relativeViews))" } return below(relativeViews: relativeViews, aligned: nil, context: context) } - func below(of relativeView: PView, aligned: HorizontalAlign) -> PinLayout { + public func below(of relativeView: View, aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "below(of: \(relativeView), aligned: \(aligned))" } return below(relativeViews: [relativeView], aligned: aligned, context: context) } - func below(of relativeViews: [PView], aligned: HorizontalAlign) -> PinLayout { + public func below(of relativeViews: [View], aligned: HorizontalAlign) -> PinLayout { func context() -> String { return "below(of: \(relativeViews), aligned: \(aligned))" } return below(relativeViews: relativeViews, aligned: aligned, context: context) } @@ -74,22 +74,22 @@ extension PinLayoutImpl { // // left(of ...) // - func left(of relativeView: PView) -> PinLayout { + public func left(of relativeView: View) -> PinLayout { func context() -> String { return "left(of: \(relativeView))" } return left(relativeViews: [relativeView], aligned: nil, context: context) } - func left(of relativeViews: [PView]) -> PinLayout { + public func left(of relativeViews: [View]) -> PinLayout { func context() -> String { return "left(of: \(relativeViews))" } return left(relativeViews: relativeViews, aligned: nil, context: context) } - func left(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { + public func left(of relativeView: View, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "left(of: \(relativeView), aligned: \(aligned))" } return left(relativeViews: [relativeView], aligned: aligned, context: context) } - func left(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { + public func left(of relativeViews: [View], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "left(of: \(relativeViews), aligned: \(aligned))" } return left(relativeViews: relativeViews, aligned: aligned, context: context) } @@ -97,27 +97,27 @@ extension PinLayoutImpl { // // right(of ...) // - func right(of relativeView: PView) -> PinLayout { + public func right(of relativeView: View) -> PinLayout { func context() -> String { return "right(of: \(relativeView))" } return right(relativeViews: [relativeView], aligned: nil, context: context) } - func right(of relativeViews: [PView]) -> PinLayout { + public func right(of relativeViews: [View]) -> PinLayout { func context() -> String { return "right(of: \(relativeViews))" } return right(relativeViews: relativeViews, aligned: nil, context: context) } - func right(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { + public func right(of relativeView: View, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "right(of: \(relativeView), aligned: \(aligned))" } return right(relativeViews: [relativeView], aligned: aligned, context: context) } - func right(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { + public func right(of relativeViews: [View], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "right(of: \(relativeViews), aligned: \(aligned))" } return right(relativeViews: relativeViews, aligned: aligned, context: context) } - func before(of relativeView: PView) -> PinLayout { + public func before(of relativeView: View) -> PinLayout { func context() -> String { return "before(of: \(relativeView))" } if isLTR() { return left(relativeViews: [relativeView], aligned: nil, context: context) @@ -126,7 +126,7 @@ extension PinLayoutImpl { } } - func before(of relativeViews: [PView]) -> PinLayout { + public func before(of relativeViews: [View]) -> PinLayout { func context() -> String { return "before(of: \(relativeViews))" } if isLTR() { return left(relativeViews: relativeViews, aligned: nil, context: context) @@ -135,7 +135,7 @@ extension PinLayoutImpl { } } - func before(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { + public func before(of relativeView: View, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "before(of: \(relativeView), aligned: \(aligned))" } if isLTR() { return left(relativeViews: [relativeView], aligned: aligned, context: context) @@ -144,7 +144,7 @@ extension PinLayoutImpl { } } - func before(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { + public func before(of relativeViews: [View], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "before(of: \(relativeViews), aligned: \(aligned))" } if isLTR() { return left(relativeViews: relativeViews, aligned: aligned, context: context) @@ -153,7 +153,7 @@ extension PinLayoutImpl { } } - func after(of relativeView: PView) -> PinLayout { + public func after(of relativeView: View) -> PinLayout { func context() -> String { return "after(of: \(relativeView))" } if isLTR() { return right(relativeViews: [relativeView], aligned: nil, context: context) @@ -162,7 +162,7 @@ extension PinLayoutImpl { } } - func after(of relativeViews: [PView]) -> PinLayout { + public func after(of relativeViews: [View]) -> PinLayout { func context() -> String { return "after(of: \(relativeViews))" } if isLTR() { return right(relativeViews: relativeViews, aligned: nil, context: context) @@ -171,7 +171,7 @@ extension PinLayoutImpl { } } - func after(of relativeView: PView, aligned: VerticalAlign) -> PinLayout { + public func after(of relativeView: View, aligned: VerticalAlign) -> PinLayout { func context() -> String { return "after(of: \(relativeView))" } if isLTR() { return right(relativeViews: [relativeView], aligned: aligned, context: context) @@ -180,7 +180,7 @@ extension PinLayoutImpl { } } - func after(of relativeViews: [PView], aligned: VerticalAlign) -> PinLayout { + public func after(of relativeViews: [View], aligned: VerticalAlign) -> PinLayout { func context() -> String { return "after(of: \(relativeViews), aligned: \(aligned))" } if isLTR() { return right(relativeViews: relativeViews, aligned: aligned, context: context) @@ -191,8 +191,8 @@ extension PinLayoutImpl { } // MARK: fileprivate -extension PinLayoutImpl { - fileprivate func above(relativeViews: [PView], aligned: HorizontalAlign?, context: Context) -> PinLayout { +extension PinLayout { + fileprivate func above(relativeViews: [View], aligned: HorizontalAlign?, context: Context) -> PinLayout { guard let relativeViews = validateRelativeViews(relativeViews, context: context) else { return self } let anchors: [Anchor] @@ -215,7 +215,7 @@ extension PinLayoutImpl { return self } - fileprivate func below(relativeViews: [PView], aligned: HorizontalAlign?, context: Context) -> PinLayout { + fileprivate func below(relativeViews: [View], aligned: HorizontalAlign?, context: Context) -> PinLayout { guard let relativeViews = validateRelativeViews(relativeViews, context: context) else { return self } let anchors: [Anchor] @@ -238,7 +238,7 @@ extension PinLayoutImpl { return self } - fileprivate func left(relativeViews: [PView], aligned: VerticalAlign?, context: Context) -> PinLayout { + fileprivate func left(relativeViews: [View], aligned: VerticalAlign?, context: Context) -> PinLayout { guard let relativeViews = validateRelativeViews(relativeViews, context: context) else { return self } let anchors: [Anchor] @@ -259,7 +259,7 @@ extension PinLayoutImpl { return self } - fileprivate func right(relativeViews: [PView], aligned: VerticalAlign?, context: Context) -> PinLayout { + fileprivate func right(relativeViews: [View], aligned: VerticalAlign?, context: Context) -> PinLayout { guard let relativeViews = validateRelativeViews(relativeViews, context: context) else { return self } let anchors: [Anchor] @@ -355,7 +355,7 @@ extension PinLayoutImpl { return sum / CGFloat(list.count) } - fileprivate func validateRelativeViews(_ relativeViews: [PView], context: Context) -> [PView]? { + fileprivate func validateRelativeViews(_ relativeViews: [View], context: Context) -> [View]? { guard let _ = layoutSuperview(context) else { return nil } guard relativeViews.count > 0 else { warnWontBeApplied("At least one view must be visible (i.e. UIView.isHidden != true) ", context) diff --git a/Sources/Impl/PinLayoutImpl+Size.swift b/Sources/Impl/PinLayoutImpl+Size.swift index bb91bccf..665e8f60 100644 --- a/Sources/Impl/PinLayoutImpl+Size.swift +++ b/Sources/Impl/PinLayoutImpl+Size.swift @@ -42,6 +42,15 @@ enum AdjustSizeType { } } + internal var requiresSizeCalculable: Bool { + switch self { + case .fitTypeWidth, .fitTypeHeight, .fitTypeWidthFlexible, .fitTypeHeightFlexible, .fitSizeLegacy: + return true + case .aspectRatio(_): + return false + } + } + func toFitType() -> FitType? { switch self { case .fitTypeWidth: return .width @@ -64,39 +73,66 @@ extension FitType { } } -extension PinLayoutImpl { - func size(_ size: CGSize) -> PinLayout { +extension PinLayout { + public func size(_ size: CGSize) -> PinLayout { return setSize(size, { return "size(CGSize(width: \(size.width), height: \(size.height)))" }) } - func size(_ sideLength: CGFloat) -> PinLayout { + public func size(_ sideLength: CGFloat) -> PinLayout { return setSize(CGSize(width: sideLength, height: sideLength), { return "size(sideLength: \(sideLength))" }) } - func size(_ percent: Percent) -> PinLayout { + public func size(_ percent: Percent) -> PinLayout { func context() -> String { return "size(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } let size = CGSize(width: percent.of(layoutSuperviewRect.width), height: percent.of(layoutSuperviewRect.height)) return setSize(size, context) } - func size(of view: PView) -> PinLayout { + public func size(of view: View) -> PinLayout { func context() -> String { return "size(of \(viewDescription(view)))" } return setSize(view.getRect(keepTransform: keepTransform).size, context) } + /** + Set the view aspect ratio. + + AspectRatio is applied only if a single dimension (either width or height) can be determined, + in that case the aspect ratio will be used to compute the other dimension. + + * AspectRatio is defined as the ratio between the width and the height (width / height). + * An aspect ratio of 2 means the width is twice the size of the height. + * AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight) + dimensions of an item. + */ @discardableResult - func aspectRatio(_ ratio: CGFloat) -> PinLayout { + public func aspectRatio(_ ratio: CGFloat) -> PinLayout { return setAdjustSizeType(.aspectRatio(ratio), { "aspectRatio(\(ratio))" }) } - func aspectRatio(of view: PView) -> PinLayout { + /** + Set the view aspect ratio using another UIView's aspect ratio. + + AspectRatio is applied only if a single dimension (either width or height) can be determined, + in that case the aspect ratio will be used to compute the other dimension. + + * AspectRatio is defined as the ratio between the width and the height (width / height). + * AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight) + dimensions of an item. + */ + public func aspectRatio(of view: View) -> PinLayout { let rect = view.getRect(keepTransform: keepTransform) return setAdjustSizeType(.aspectRatio(rect.width / rect.height), { "aspectRatio(of: \(viewDescription(view)))" }) } + /** + If the layouted view is an UIImageView, this method will set the aspectRatio using + the UIImageView's image dimension. + + For other types of views, this method as no impact. + */ #if os(iOS) || os(tvOS) - func aspectRatio() -> PinLayout { + public func aspectRatio() -> PinLayout { func context() -> String { return "aspectRatio()" } guard let imageView = view as? UIImageView else { warnWontBeApplied("the layouted must be an UIImageView() to use the aspectRatio() method without parameter.", context) @@ -112,12 +148,71 @@ extension PinLayoutImpl { } #endif - func sizeToFit(_ fitType: FitType) -> PinLayout { + /** + The method adjust the view's size based on the view's `sizeThatFits()` method result. + PinLayout will adjust either the view's width or height based on the `fitType` parameter value. + + Notes: + * If margin rules apply, margins will be applied when determining the reference dimension (width/height). + * The resulting size will always respect `minWidth` / `maxWidth` / `minHeight` / `maxHeight`. + + - Parameter fitType: Identify the reference dimension (width / height) that will be used + to adjust the view's size: + + .width: The method adjust the view's size 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**, if not the **current view's width** + will be used. + * The resulting width will always **match the reference width**. + + .height: The method adjust the view's size 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**, if not the **current view's height** + will be used. + * The resulting height will always **match the reference height**. + + .widthFlexible: Similar to `.width`, except that PinLayout won't constrain the resulting width to + match the reference width. The resulting width may be smaller or 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. + + .heightFlexible: Similar to `.height`, except that PinLayout won't constrain the resulting height to + match the reference height. The resulting height may be smaller or bigger depending on the view's + sizeThatFits(..) method result. + + Examples: + + ``` + // Adjust the view's size based on a width of 100 pixels. + // The resulting width will always match the pinned property `width(100)`. + view.pin.width(100).sizeToFit(.width) + + // Adjust the view's size based on view's current width. + // The resulting width will always match the view's original width. + // The resulting height will never be bigger than the specified `maxHeight`. + view.pin.sizeToFit(.width).maxHeight(100) + + // Adjust the view's size based on 100% of the superview's height. + // The resulting height will always match the pinned property `height(100%)`. + view.pin.height(100%).sizeToFit(.height) + + // Adjust the view's size based on view's current height. + // The resulting width will always match the view's original height. + view.pin.sizeToFit(.height) + + // Since `.widthFlexible` has been specified, its possible that the resulting + // width will be smaller or bigger than 100 pixels, based of the label's sizeThatFits() + // method result. + label.pin.width(100).sizeToFit(.widthFlexible) + ``` + */ + public func sizeToFit(_ fitType: FitType) -> PinLayout { return setAdjustSizeType(fitType.toAdjustSizeType(), { return "sizeToFit(\(fitType.description))" }) } #if os(iOS) || os(tvOS) - func fitSize() -> PinLayout { + @available(*, deprecated, message: "fitSize() is deprecated, please use sizeToFit(fitType: FitType)") + public func fitSize() -> PinLayout { return setAdjustSizeType(.fitSizeLegacy, { return "fitSize()" }) } #endif @@ -125,7 +220,7 @@ extension PinLayoutImpl { // // MARK: Private methods -extension PinLayoutImpl { +extension PinLayout { internal func setSize(_ size: CGSize, _ context: Context) -> PinLayout { setWidth(size.width, { return "\(context())'s width" }) setHeight(size.height, { return "\(context())'s height" }) @@ -138,9 +233,14 @@ extension PinLayoutImpl { return self } - if let type = type, case let AdjustSizeType.aspectRatio(ratio) = type, ratio <= 0 { - warnWontBeApplied("the aspectRatio (\(ratio)) must be greater than zero.", context) - return self + if let type = type { + if case let AdjustSizeType.aspectRatio(ratio) = type, ratio <= 0 { + warnWontBeApplied("the aspectRatio (\(ratio)) must be greater than zero.", context) + return self + } else if type.requiresSizeCalculable, !(view is SizeCalculable) { + warnWontBeApplied("the view must conform to protocol SizeCalculable for it's size to be computed.", context) + return self + } } adjustSizeType = type diff --git a/Sources/Impl/PinLayoutImpl+Warning.swift b/Sources/Impl/PinLayoutImpl+Warning.swift index 07c017e6..ef9fddca 100644 --- a/Sources/Impl/PinLayoutImpl+Warning.swift +++ b/Sources/Impl/PinLayoutImpl+Warning.swift @@ -30,23 +30,23 @@ fileprivate var numberFormatter: NumberFormatter = { return numberFormatter }() -extension PinLayoutImpl { +extension PinLayout { internal func pointContext(method: String, point: CGPoint) -> String { return "\(method)(to: CGPoint(x: \(point.x), y: \(point.y)))" } internal func relativeEdgeContext(method: String, edge: VerticalEdge) -> String { - let edge = edge as! VerticalEdgeImpl + let edge = edge as! VerticalEdgeImpl return "\(method)(to: .\(edge.type.rawValue), of: \(viewDescription(edge.view)))" } internal func relativeEdgeContext(method: String, edge: HorizontalEdge) -> String { - let edge = edge as! HorizontalEdgeImpl + let edge = edge as! HorizontalEdgeImpl return "\(method)(to: .\(edge.type.rawValue), of: \(viewDescription(edge.view))" } internal func relativeAnchorContext(method: String, anchor: Anchor) -> String { - let anchor = anchor as! AnchorImpl + let anchor = anchor as! AnchorImpl return "\(method)(to: .\(anchor.type.rawValue), of: \(viewDescription(anchor.view)))" } @@ -114,12 +114,12 @@ extension PinLayoutImpl { } } - internal func viewDescription(_ view: PView) -> String { + internal func viewDescription(_ view: View) -> String { let rect = view.getRect(keepTransform: keepTransform) return "(\(viewName(view)), Frame: \(rect))" } - internal func viewName(_ view: PView) -> String { + internal func viewName(_ view: View) -> String { return "\(type(of: view))" } @@ -127,7 +127,7 @@ extension PinLayoutImpl { return "UIEdgeInsets(top: \(insets.top), left: \(insets.left), bottom: \(insets.bottom), right: \(insets.right))" } - internal func pinLayoutDisplayConsoleWarning(_ text: String, _ view: PView) { + internal func pinLayoutDisplayConsoleWarning(_ text: String, _ view: View) { var displayText = "\n👉 \(text)" let rect = view.getRect(keepTransform: keepTransform) @@ -142,7 +142,7 @@ extension PinLayoutImpl { var hierarchy: [String] = [] while let parent = currentView.superview { hierarchy.insert("\(type(of: parent))", at: 0) - currentView = parent + currentView = parent as! View } if hierarchy.count > 0 { #if swift(>=4.1) @@ -152,7 +152,7 @@ extension PinLayoutImpl { #endif } - displayText += ", Tag: \(view.tag))\n" + displayText += ", Debug description: \(view.debugDescription))\n" print(displayText) Pin.lastWarningText = text diff --git a/Sources/Impl/PinLayoutImpl+WrapContent.swift b/Sources/Impl/PinLayoutImpl+WrapContent.swift index c52e1c38..75668099 100644 --- a/Sources/Impl/PinLayoutImpl+WrapContent.swift +++ b/Sources/Impl/PinLayoutImpl+WrapContent.swift @@ -23,28 +23,63 @@ import UIKit import AppKit #endif -extension PinLayoutImpl { - func wrapContent() -> PinLayout { +extension PinLayout { + /** + Adjust the view's width & height to wrap all its subviews. The method also adjust subviews position to create a tight wrap. + */ + public func wrapContent() -> PinLayout { return wrapContent(.all, padding: PEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), { return "wrapContent()" }) } - 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 value. + */ + public func wrapContent(padding: CGFloat) -> PinLayout { return wrapContent(.all, padding: PEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(padding: \(padding)" }) } - func wrapContent(padding: PEdgeInsets) -> 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. + */ + public func wrapContent(padding: PEdgeInsets) -> PinLayout { return wrapContent(.all, padding: padding, { return "wrapContent(padding: \(insetsDescription(padding))" }) } - func wrapContent(_ type: WrapType) -> PinLayout { + /** + Adjust the view's width AND/OR height to wrap all its subviews. + + - Parameters: + - type: Specify the wrap type (.all, .horizontally, .vertically) + */ + public func wrapContent(_ type: WrapType) -> PinLayout { return wrapContent(type, padding: PEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), { return "wrapContent(\(type.description)" }) } - 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 value. + */ + public func wrapContent(_ type: WrapType, padding: CGFloat) -> PinLayout { return wrapContent(type, padding: PEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), { return "wrapContent(\(type.description), padding: \(padding)" }) } - func wrapContent(_ type: WrapType, padding: PEdgeInsets) -> 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. + */ + public func wrapContent(_ type: WrapType, padding: PEdgeInsets) -> PinLayout { return wrapContent(type, padding: padding, { return "wrapContent(\(type.description), padding: \(insetsDescription(padding))" }) } diff --git a/Sources/Impl/PinLayoutImpl.swift b/Sources/Impl/PinLayoutImpl.swift index bb0fe222..5d3a2b45 100644 --- a/Sources/Impl/PinLayoutImpl.swift +++ b/Sources/Impl/PinLayoutImpl.swift @@ -21,16 +21,14 @@ import Foundation #if os(iOS) || os(tvOS) import UIKit - typealias PView = UIView - typealias PEdgeInsets = UIEdgeInsets + public typealias PEdgeInsets = UIEdgeInsets #else import AppKit - typealias PView = NSView - typealias PEdgeInsets = NSEdgeInsets + public typealias PEdgeInsets = NSEdgeInsets #endif -class PinLayoutImpl: PinLayout { - internal let view: PView +public class PinLayout { + internal let view: View internal let keepTransform: Bool internal var _top: CGFloat? // offset from superview's top edge @@ -70,7 +68,7 @@ class PinLayoutImpl: PinLayout { internal var isLayouted = false - init(view: PView, keepTransform: Bool) { + init(view: View, keepTransform: Bool) { self.view = view self.keepTransform = keepTransform @@ -87,169 +85,183 @@ class PinLayoutImpl: PinLayout { } #if os(iOS) || os(tvOS) - var safeArea: PEdgeInsets { - if #available(iOS 11.0, tvOS 11.0, *) { - return view.safeAreaInsets + public var safeArea: PEdgeInsets { + if let view = view as? UIView { + if #available(iOS 11.0, tvOS 11.0, *) { + return view.safeAreaInsets + } else { + return view.pinlayoutComputeSafeAreaInsets() + } } else { - return view.pinlayoutComputeSafeAreaInsets() + return PEdgeInsets.zero } } #endif + // + // MARK: Layout using distances from superview’s edges // // top, left, bottom, right // - func top() -> PinLayout { + + public func top() -> PinLayout { top({ return "top()" }) return self } - func top(_ value: CGFloat) -> PinLayout { + public func top(_ value: CGFloat) -> PinLayout { return top(value, { return "top(\(value))" }) } - func top(_ percent: Percent) -> PinLayout { + public func top(_ percent: Percent) -> PinLayout { func context() -> String { return "top(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setTop(percent.of(layoutSuperviewRect.height), context) return self } - func top(_ insets: PEdgeInsets) -> PinLayout { + public func top(_ insets: PEdgeInsets) -> PinLayout { return top(insets.top, { return "top(\(insetsDescription(insets))" }) } - func left() -> PinLayout { + public func left() -> PinLayout { return left({ return "left()" }) } - func left(_ value: CGFloat) -> PinLayout { + public func left(_ value: CGFloat) -> PinLayout { return left(value, { return "left(\(value))" }) } - func left(_ percent: Percent) -> PinLayout { + public func left(_ percent: Percent) -> PinLayout { return left(percent, { return "left(\(percent.description))" }) } - func left(_ insets: PEdgeInsets) -> PinLayout { + public func left(_ insets: PEdgeInsets) -> PinLayout { return left(insets.left, { return "left(\(insetsDescription(insets))" }) } - func start() -> PinLayout { + public func start() -> PinLayout { func context() -> String { return "start()" } return isLTR() ? left(context) : right(context) } - func start(_ value: CGFloat) -> PinLayout { + public func start(_ value: CGFloat) -> PinLayout { func context() -> String { return "start(\(value))" } return isLTR() ? left(value, context) : right(value, context) } - func start(_ percent: Percent) -> PinLayout { + public func start(_ percent: Percent) -> PinLayout { func context() -> String { return "start(\(percent.description))" } return isLTR() ? left(percent, context) : right(percent, context) } - func start(_ insets: PEdgeInsets) -> PinLayout { + public func start(_ insets: PEdgeInsets) -> PinLayout { func context() -> String { return "start(\(insetsDescription(insets))" } return isLTR() ? left(insets.left, context) : right(insets.right, context) } - func bottom() -> PinLayout { + public func bottom() -> PinLayout { return bottom({ return "bottom()" }) } - func bottom(_ value: CGFloat) -> PinLayout { + public func bottom(_ value: CGFloat) -> PinLayout { return bottom(value, { return "bottom(\(value))" }) } - func bottom(_ percent: Percent) -> PinLayout { + public func bottom(_ percent: Percent) -> PinLayout { return bottom(percent, { return "bottom(\(percent.description))" }) } - func bottom(_ insets: PEdgeInsets) -> PinLayout { + public func bottom(_ insets: PEdgeInsets) -> PinLayout { return bottom(insets.bottom, { return "bottom(\(insetsDescription(insets))" }) } - func right() -> PinLayout { + public func right() -> PinLayout { return right({ return "right()" }) } - func right(_ value: CGFloat) -> PinLayout { + public func right(_ value: CGFloat) -> PinLayout { return right(value, { return "right(\(value))" }) } - func right(_ percent: Percent) -> PinLayout { + public func right(_ percent: Percent) -> PinLayout { return right(percent, { return "right(\(percent.description))" }) } - func right(_ insets: PEdgeInsets) -> PinLayout { + public func right(_ insets: PEdgeInsets) -> PinLayout { return right(insets.right, { return "right(\(insetsDescription(insets))" }) } - func end() -> PinLayout { + public func end() -> PinLayout { func context() -> String { return "end()" } return isLTR() ? right(context) : left(context) } - func end(_ value: CGFloat) -> PinLayout { + public func end(_ value: CGFloat) -> PinLayout { func context() -> String { return "end(\(value))" } return isLTR() ? right(value, context) : left(value, context) } - func end(_ percent: Percent) -> PinLayout { + public func end(_ percent: Percent) -> PinLayout { func context() -> String { return "end(\(percent.description))" } return isLTR() ? right(percent, context) : left(percent, context) } - func end(_ insets: PEdgeInsets) -> PinLayout { + public func end(_ insets: PEdgeInsets) -> PinLayout { func context() -> String { return "end(\(insetsDescription(insets))" } return isLTR() ? right(insets.right, context) : left(insets.left, context) } - func hCenter() -> PinLayout { + public func hCenter() -> PinLayout { func context() -> String { return "hCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setHorizontalCenter(layoutSuperviewRect.width / 2, context) return self } - func hCenter(_ value: CGFloat) -> PinLayout { + public func hCenter(_ value: CGFloat) -> PinLayout { func context() -> String { return "hCenter(\(value))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setHorizontalCenter((layoutSuperviewRect.width / 2) + value, context) return self } - func hCenter(_ percent: Percent) -> PinLayout { + public func hCenter(_ percent: Percent) -> PinLayout { func context() -> String { return "hCenter(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setHorizontalCenter((layoutSuperviewRect.width / 2) + percent.of(layoutSuperviewRect.width), context) return self } - func vCenter() -> PinLayout { + public func vCenter() -> PinLayout { func context() -> String { return "vCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setVerticalCenter(layoutSuperviewRect.height / 2, context) return self } - func vCenter(_ value: CGFloat) -> PinLayout { + public func vCenter(_ value: CGFloat) -> PinLayout { func context() -> String { return "vCenter(\(value))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setVerticalCenter((layoutSuperviewRect.height / 2) + value, context) return self } - func vCenter(_ percent: Percent) -> PinLayout { + public func vCenter(_ percent: Percent) -> PinLayout { func context() -> String { return "vCenter(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setVerticalCenter((layoutSuperviewRect.height / 2) + percent.of(layoutSuperviewRect.height), context) return self } - func all() -> PinLayout { + // Pin multiple edges at once. + + /** + Pin all edges on its superview's corresponding edges (top, bottom, left, right). + + Similar to calling `view.top().bottom().left().right()` + */ + public func all() -> PinLayout { top({ "all() top coordinate" }) bottom({ "all() bottom coordinate" }) right({ "all() right coordinate" }) @@ -257,7 +269,12 @@ class PinLayoutImpl: PinLayout { return self } - func all(_ value: CGFloat) -> PinLayout { + /** + Pin all edges on its superview's corresponding edges (top, bottom, left, right). + + Similar to calling `view.top().bottom().left().right()` + */ + public func all(_ value: CGFloat) -> PinLayout { top(value, { "all(\(value)) top coordinate" }) bottom(value, { "all(\(value)) bottom coordinate" }) left(value, { "all(\(value)) left coordinate" }) @@ -265,7 +282,12 @@ class PinLayoutImpl: PinLayout { return self } - func all(_ insets: PEdgeInsets) -> PinLayout { + /** + Pin all edges on its superview's corresponding edges (top, bottom, left, right). + + Similar to calling `view.top().bottom().left().right()` + */ + public func all(_ insets: PEdgeInsets) -> PinLayout { top(insets.top, { "all(\(insets)) top coordinate" }) bottom(insets.bottom, { "all(\(insets)) bottom coordinate" }) left(insets.left, { "all(\(insets)) left coordinate" }) @@ -273,58 +295,101 @@ class PinLayoutImpl: PinLayout { return self } - func horizontally() -> PinLayout { + /** + Pin the left and right edges on its superview's corresponding edges. + + Similar to calling `view.left().right()`. + */ + public func horizontally() -> PinLayout { right({ "horizontally() right coordinate" }) left({ "horizontally() left coordinate" }) return self } - func horizontally(_ value: CGFloat) -> PinLayout { + /** + Pin the left and right edges on its superview's corresponding edges. + + Similar to calling `view.left().right()`. + */ + public func horizontally(_ value: CGFloat) -> PinLayout { left(value, { return "horizontally(\(value)) left coordinate" }) right(value, { return "horizontally(\(value)) right coordinate" }) return self } - func horizontally(_ percent: Percent) -> PinLayout { + /** + Pin the left and right edges on its superview's corresponding edges. + + Similar to calling `view.left().right()`. + */ + public func horizontally(_ percent: Percent) -> PinLayout { left(percent, { return "horizontally(\(percent.description)) left coordinate" }) right(percent, { return "horizontally(\(percent.description)) right coordinate" }) return self } - func horizontally(_ insets: PEdgeInsets) -> PinLayout { + /** + Pin the left and right edges on its superview's corresponding edges. + + Similar to calling `view.left().right()`. + */ + public func horizontally(_ insets: PEdgeInsets) -> PinLayout { left(insets.left, { return "horizontally(\(insets)) left coordinate" }) right(insets.right, { return "horizontally(\(insets)) right coordinate" }) return self } - func vertically() -> PinLayout { + /** + Pin the **top and bottom edges** on its superview's corresponding edges. + + Similar to calling `view.top().bottom()`. + */ + public func vertically() -> PinLayout { top({ "vertically() top coordinate" }) bottom({ "vertically() bottom coordinate" }) return self } - func vertically(_ value: CGFloat) -> PinLayout { + /** + Pin the **top and bottom edges** on its superview's corresponding edges. + + Similar to calling `view.top().bottom()`. + */ + public func vertically(_ value: CGFloat) -> PinLayout { top(value, { return "vertically(\(value)) top coordinate" }) bottom(value, { return "vertically(\(value)) bottom coordinate" }) return self } - func vertically(_ percent: Percent) -> PinLayout { + /** + Pin the **top and bottom edges** on its superview's corresponding edges. + + Similar to calling `view.top().bottom()`. + */ + public func vertically(_ percent: Percent) -> PinLayout { top(percent, { return "vertically(\(percent.description)) top coordinate" }) bottom(percent, { return "vertically(\(percent.description)) bottom coordinate" }) return self } - func vertically(_ insets: PEdgeInsets) -> PinLayout { + /** + Pin the **top and bottom edges** on its superview's corresponding edges. + The UIEdgeInsets.top is used to pin the top edge and the UIEdgeInsets.bottom + for the bottom edge. + */ + public func vertically(_ insets: PEdgeInsets) -> PinLayout { top(insets.top, { return "vertically(\(insets)) top coordinate" }) bottom(insets.bottom, { return "vertically(\(insets)) bottom coordinate" }) return self } + // + // MARK: Layout using edges // // top, left, bottom, right // - func top(to edge: VerticalEdge) -> PinLayout { + + public func top(to edge: VerticalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "top", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setTop(coordinate, context) @@ -332,7 +397,7 @@ class PinLayoutImpl: PinLayout { return self } - func vCenter(to edge: VerticalEdge) -> PinLayout { + public func vCenter(to edge: VerticalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "vCenter", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setVerticalCenter(coordinate, context) @@ -340,7 +405,7 @@ class PinLayoutImpl: PinLayout { return self } - func bottom(to edge: VerticalEdge) -> PinLayout { + public func bottom(to edge: VerticalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "bottom", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setBottom(coordinate, context) @@ -348,7 +413,7 @@ class PinLayoutImpl: PinLayout { return self } - func left(to edge: HorizontalEdge) -> PinLayout { + public func left(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "left", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setLeft(coordinate, context) @@ -356,7 +421,7 @@ class PinLayoutImpl: PinLayout { return self } - func hCenter(to edge: HorizontalEdge) -> PinLayout { + public func hCenter(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "hCenter", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setHorizontalCenter(coordinate, context) @@ -364,7 +429,7 @@ class PinLayoutImpl: PinLayout { return self } - func right(to edge: HorizontalEdge) -> PinLayout { + public func right(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "right", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setRight(coordinate, context) @@ -372,7 +437,7 @@ class PinLayoutImpl: PinLayout { return self } - func start(to edge: HorizontalEdge) -> PinLayout { + public func start(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "start", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setStart(coordinate, context) @@ -380,20 +445,23 @@ class PinLayoutImpl: PinLayout { return self } - func end(to edge: HorizontalEdge) -> PinLayout { + public func end(to edge: HorizontalEdge) -> PinLayout { func context() -> String { return relativeEdgeContext(method: "end", edge: edge) } if let coordinate = computeCoordinate(forEdge: edge, context) { setEnd(coordinate, context) } return self } - + + // + // MARK: Layout using anchors // // topLeft, topCenter, topRight, // centerLeft, center, centerRight, // bottomLeft, bottomCenter, bottomRight, // - func topLeft(to anchor: Anchor) -> PinLayout { + + public func topLeft(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topLeft", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setTopLeft(coordinatesList[0], context) @@ -401,7 +469,7 @@ class PinLayoutImpl: PinLayout { return self } - func topLeft() -> PinLayout { + public func topLeft() -> PinLayout { return topLeft({ return "topLeft()" }) } @@ -410,7 +478,7 @@ class PinLayoutImpl: PinLayout { return self } - func topStart(to anchor: Anchor) -> PinLayout { + public func topStart(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topStart", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setTop(coordinatesList[0].y, context) @@ -419,12 +487,12 @@ class PinLayoutImpl: PinLayout { return self } - func topStart() -> PinLayout { + public func topStart() -> PinLayout { func context() -> String { return "topStart()" } return isLTR() ? topLeft(context) : topRight(context) } - func topCenter(to anchor: Anchor) -> PinLayout { + public func topCenter(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topCenter", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setTopCenter(coordinatesList[0], context) @@ -432,14 +500,14 @@ class PinLayoutImpl: PinLayout { return self } - func topCenter() -> PinLayout { + public func topCenter() -> PinLayout { func context() -> String { return "topCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setTopCenter(CGPoint(x: layoutSuperviewRect.width / 2, y: 0), context) return self } - func topRight(to anchor: Anchor) -> PinLayout { + public func topRight(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topRight", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setTopRight(coordinatesList[0], context) @@ -447,7 +515,7 @@ class PinLayoutImpl: PinLayout { return self } - func topRight() -> PinLayout { + public func topRight() -> PinLayout { return topRight({ return "topRight()" }) } @@ -457,7 +525,7 @@ class PinLayoutImpl: PinLayout { return self } - func topEnd(to anchor: Anchor) -> PinLayout { + public func topEnd(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "topEnd", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setTop(coordinatesList[0].y, context) @@ -466,12 +534,12 @@ class PinLayoutImpl: PinLayout { return self } - func topEnd() -> PinLayout { + public func topEnd() -> PinLayout { func context() -> String { return "topEnd()" } return isLTR() ? topRight(context) : topLeft(context) } - func centerLeft(to anchor: Anchor) -> PinLayout { + public func centerLeft(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerLeft", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setCenterLeft(coordinatesList[0], context) @@ -479,7 +547,7 @@ class PinLayoutImpl: PinLayout { return self } - func centerLeft() -> PinLayout { + public func centerLeft() -> PinLayout { return centerLeft({ return "centerLeft()" }) } @@ -489,7 +557,7 @@ class PinLayoutImpl: PinLayout { return self } - func centerStart(to anchor: Anchor) -> PinLayout { + public func centerStart(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerStart", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setVerticalCenter(coordinatesList[0].y, context) @@ -498,12 +566,12 @@ class PinLayoutImpl: PinLayout { return self } - func centerStart() -> PinLayout { + public func centerStart() -> PinLayout { func context() -> String { return "centerStart()" } return isLTR() ? centerLeft(context) : centerRight(context) } - func center(to anchor: Anchor) -> PinLayout { + public func center(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "center", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setCenter(coordinatesList[0], context) @@ -511,14 +579,14 @@ class PinLayoutImpl: PinLayout { return self } - func center() -> PinLayout { + public func center() -> PinLayout { func context() -> String { return "center()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setCenter(CGPoint(x: layoutSuperviewRect.width / 2, y: layoutSuperviewRect.height / 2), context) return self } - func centerRight(to anchor: Anchor) -> PinLayout { + public func centerRight(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerRight", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setCenterRight(coordinatesList[0], context) @@ -526,7 +594,7 @@ class PinLayoutImpl: PinLayout { return self } - func centerRight() -> PinLayout { + public func centerRight() -> PinLayout { return centerRight({ return "centerRight()" }) } @@ -536,7 +604,7 @@ class PinLayoutImpl: PinLayout { return self } - func centerEnd(to anchor: Anchor) -> PinLayout { + public func centerEnd(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "centerEnd", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setVerticalCenter(coordinatesList[0].y, context) @@ -545,12 +613,12 @@ class PinLayoutImpl: PinLayout { return self } - func centerEnd() -> PinLayout { + public func centerEnd() -> PinLayout { func context() -> String { return "centerEnd()" } return isLTR() ? centerRight(context) : centerLeft(context) } - func bottomLeft(to anchor: Anchor) -> PinLayout { + public func bottomLeft(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomLeft", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setBottomLeft(coordinatesList[0], context) @@ -558,7 +626,7 @@ class PinLayoutImpl: PinLayout { return self } - func bottomLeft() -> PinLayout { + public func bottomLeft() -> PinLayout { return bottomLeft({ return "bottomLeft()" }) } @@ -568,7 +636,7 @@ class PinLayoutImpl: PinLayout { return self } - func bottomStart(to anchor: Anchor) -> PinLayout { + public func bottomStart(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomStart", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setBottom(coordinatesList[0].y, context) @@ -577,12 +645,12 @@ class PinLayoutImpl: PinLayout { return self } - func bottomStart() -> PinLayout { + public func bottomStart() -> PinLayout { func context() -> String { return "bottomStart()" } return isLTR() ? bottomLeft(context) : bottomRight(context) } - func bottomCenter(to anchor: Anchor) -> PinLayout { + public func bottomCenter(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomCenter", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setBottomCenter(coordinatesList[0], context) @@ -590,14 +658,14 @@ class PinLayoutImpl: PinLayout { return self } - func bottomCenter() -> PinLayout { + public func bottomCenter() -> PinLayout { func context() -> String { return "bottomCenter()" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } setBottomCenter(CGPoint(x: layoutSuperviewRect.width / 2, y: layoutSuperviewRect.height), context) return self } - func bottomRight(to anchor: Anchor) -> PinLayout { + public func bottomRight(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomRight", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setBottomRight(coordinatesList[0], context) @@ -605,7 +673,7 @@ class PinLayoutImpl: PinLayout { return self } - func bottomRight() -> PinLayout { + public func bottomRight() -> PinLayout { return bottomRight({ return "bottomRight()" }) } @@ -615,7 +683,7 @@ class PinLayoutImpl: PinLayout { return self } - func bottomEnd(to anchor: Anchor) -> PinLayout { + public func bottomEnd(to anchor: Anchor) -> PinLayout { func context() -> String { return relativeAnchorContext(method: "bottomEnd", anchor: anchor) } if let coordinatesList = computeCoordinates(forAnchors: [anchor], context) { setBottom(coordinatesList[0].y, context) @@ -624,110 +692,119 @@ class PinLayoutImpl: PinLayout { return self } - func bottomEnd() -> PinLayout { + public func bottomEnd() -> PinLayout { func context() -> String { return "bottomEnd()" } return isLTR() ? bottomRight(context) : bottomLeft(context) } // - // width, height + // MARK: Width, height // - func width(_ width: CGFloat) -> PinLayout { + + public func width(_ width: CGFloat) -> PinLayout { return setWidth(width, { return "width(\(width))" }) } - func width(_ percent: Percent) -> PinLayout { + public func width(_ percent: Percent) -> PinLayout { func context() -> String { return "width(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setWidth(percent.of(layoutSuperviewRect.width), context) } - func width(of view: PView) -> PinLayout { + public func width(of view: View) -> PinLayout { let rect = view.getRect(keepTransform: keepTransform) return setWidth(rect.width, { return "width(of: \(viewDescription(view)))" }) } - func minWidth(_ width: CGFloat) -> PinLayout { + public func minWidth(_ width: CGFloat) -> PinLayout { setMinWidth(width, { return "minWidth(\(width))" }) return self } - func minWidth(_ percent: Percent) -> PinLayout { + public func minWidth(_ percent: Percent) -> PinLayout { func context() -> String { return "minWidth(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setMinWidth(percent.of(layoutSuperviewRect.width), context) } - func maxWidth(_ width: CGFloat) -> PinLayout { + public func maxWidth(_ width: CGFloat) -> PinLayout { setMaxWidth(width, { return "maxWidth(\(width))" }) return self } - func maxWidth(_ percent: Percent) -> PinLayout { + public func maxWidth(_ percent: Percent) -> PinLayout { func context() -> String { return "maxWidth(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setMaxWidth(percent.of(layoutSuperviewRect.width), context) } - func height(_ height: CGFloat) -> PinLayout { + public func height(_ height: CGFloat) -> PinLayout { return setHeight(height, { return "height(\(height))" }) } - func height(_ percent: Percent) -> PinLayout { + public func height(_ percent: Percent) -> PinLayout { func context() -> String { return "height(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setHeight(percent.of(layoutSuperviewRect.height), context) } - func height(of view: PView) -> PinLayout { + public func height(of view: View) -> PinLayout { let rect = view.getRect(keepTransform: keepTransform) return setHeight(rect.height, { return "height(of: \(viewDescription(view)))" }) } - func minHeight(_ height: CGFloat) -> PinLayout { + public func minHeight(_ height: CGFloat) -> PinLayout { setMinHeight(height, { return "minHeight(\(height))" }) return self } - func minHeight(_ percent: Percent) -> PinLayout { + public func minHeight(_ percent: Percent) -> PinLayout { func context() -> String { return "minHeight(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setMinHeight(percent.of(layoutSuperviewRect.height), context) } - func maxHeight(_ height: CGFloat) -> PinLayout { + public func maxHeight(_ height: CGFloat) -> PinLayout { setMaxHeight(height, { return "maxHeight(\(height))" }) return self } - func maxHeight(_ percent: Percent) -> PinLayout { + public func maxHeight(_ percent: Percent) -> PinLayout { func context() -> String { return "maxHeight(\(percent.description))" } guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self } return setMaxHeight(percent.of(layoutSuperviewRect.height), context) } - + // - // justify, align + // MARK: justify / align // - func justify(_ value: HorizontalAlign) -> PinLayout { + + public func justify(_ value: HorizontalAlign) -> PinLayout { justify = value return self } - func align(_ value: VerticalAlign) -> PinLayout { + public func align(_ value: VerticalAlign) -> PinLayout { align = value return self } // - // Margins + // MARK: Margins // - func marginTop(_ value: CGFloat) -> PinLayout { + + /** + Set the top margin. + */ + public func marginTop(_ value: CGFloat) -> PinLayout { marginTop = value return self } - func marginTop(_ percent: Percent) -> PinLayout { + /** + Set the top margin. + */ + public func marginTop(_ percent: Percent) -> PinLayout { func context() -> String { return "marginTop(\(percent.description))" } return marginTop(percent, context) } @@ -738,12 +815,18 @@ class PinLayoutImpl: PinLayout { return self } - func marginLeft(_ value: CGFloat) -> PinLayout { + /** + Set the left margin. + */ + public func marginLeft(_ value: CGFloat) -> PinLayout { marginLeft = value return self } - func marginLeft(_ percent: Percent) -> PinLayout { + /** + Set the left margin. + */ + public func marginLeft(_ percent: Percent) -> PinLayout { func context() -> String { return "marginLeft(\(percent.description))" } return marginLeft(percent, context) } @@ -754,12 +837,18 @@ class PinLayoutImpl: PinLayout { return self } - func marginBottom(_ value: CGFloat) -> PinLayout { + /** + Set the bottom margin. + */ + public func marginBottom(_ value: CGFloat) -> PinLayout { marginBottom = value return self } - func marginBottom(_ percent: Percent) -> PinLayout { + /** + Set the bottom margin. + */ + public func marginBottom(_ percent: Percent) -> PinLayout { func context() -> String { return "marginBottom(\(percent.description))" } return marginBottom(percent, context) } @@ -770,12 +859,18 @@ class PinLayoutImpl: PinLayout { return self } - func marginRight(_ value: CGFloat) -> PinLayout { + /** + Set the right margin. + */ + public func marginRight(_ value: CGFloat) -> PinLayout { marginRight = value return self } - func marginRight(_ percent: Percent) -> PinLayout { + /** + Set the right margin. + */ + public func marginRight(_ percent: Percent) -> PinLayout { func context() -> String { return "marginRight(\(percent.description))" } return marginRight(percent, context) } @@ -786,33 +881,69 @@ class PinLayoutImpl: PinLayout { return self } + // RTL support + + /** + Set the start margin. + + Depends on the value of `Pin.layoutDirection(...)`: + * In LTR direction, start margin specify the **left** margin. + * In RTL direction, start margin specify the **right** margin. + */ @discardableResult - func marginStart(_ value: CGFloat) -> PinLayout { + public func marginStart(_ value: CGFloat) -> PinLayout { return isLTR() ? marginLeft(value) : marginRight(value) } - func marginStart(_ percent: Percent) -> PinLayout { + /** + Set the start margin. + + Depends on the value of `Pin.layoutDirection(...)`: + * In LTR direction, start margin specify the **left** margin. + * In RTL direction, start margin specify the **right** margin. + */ + public func marginStart(_ percent: Percent) -> PinLayout { func context() -> String { return "marginStart(\(percent.description))" } return isLTR() ? marginLeft(percent, context) : marginRight(percent, context) } - + + /** + Set the end margin. + + Depends on the value of `Pin.layoutDirection(...)`: + * In LTR direction, end margin specify the **right** margin. + * In RTL direction, end margin specify the **left** margin. + */ @discardableResult - func marginEnd(_ value: CGFloat) -> PinLayout { + public func marginEnd(_ value: CGFloat) -> PinLayout { return isLTR() ? marginRight(value) : marginLeft(value) } - func marginEnd(_ percent: Percent) -> PinLayout { + /** + Set the end margin. + + Depends on the value of `Pin.layoutDirection(...)`: + * In LTR direction, end margin specify the **right** margin. + * In RTL direction, end margin specify the **left** margin. + */ + public func marginEnd(_ percent: Percent) -> PinLayout { func context() -> String { return "marginEnd(\(percent.description))" } return isLTR() ? marginRight(percent, context) : marginLeft(percent, context) } - func marginHorizontal(_ value: CGFloat) -> PinLayout { + /** + Set the left, right, start and end margins to the specified value. + */ + public func marginHorizontal(_ value: CGFloat) -> PinLayout { marginLeft = value marginRight = value return self } - func marginHorizontal(_ percent: Percent) -> PinLayout { + /** + Set the left, right, start and end margins to the specified value. + */ + public func marginHorizontal(_ percent: Percent) -> PinLayout { func context() -> String { return "marginHorizontal(\(percent.description))" } return marginHorizontal(percent, context) } @@ -821,13 +952,19 @@ class PinLayoutImpl: PinLayout { return marginLeft(percent, context).marginRight(percent, context) } - func marginVertical(_ value: CGFloat) -> PinLayout { + /** + Set the top and bottom margins to the specified value. + */ + public func marginVertical(_ value: CGFloat) -> PinLayout { marginTop = value marginBottom = value return self } - func marginVertical(_ percent: Percent) -> PinLayout { + /** + Set the top and bottom margins to the specified value. + */ + public func marginVertical(_ percent: Percent) -> PinLayout { func context() -> String { return "marginVertical(\(percent.description))" } return marginVertical(percent, context) } @@ -835,8 +972,12 @@ class PinLayoutImpl: PinLayout { private func marginVertical(_ percent: Percent, _ context: Context) -> Self { return marginTop(percent, context).marginBottom(percent, context) } - - func margin(_ insets: PEdgeInsets) -> PinLayout { + + /** + Set all margins using UIEdgeInsets. + This method is particularly useful to set all margins using iOS 11 `UIView.safeAreaInsets`. + */ + public func margin(_ insets: PEdgeInsets) -> PinLayout { marginTop = insets.top marginBottom = insets.bottom marginLeft = insets.left @@ -844,9 +985,15 @@ class PinLayoutImpl: PinLayout { return self } + /** + Set margins using NSDirectionalEdgeInsets. + This method is particularly to set all margins using iOS 11 `UIView.directionalLayoutMargins`. + + Available only on iOS 11 and higher. + */ #if os(iOS) || os(tvOS) @available(tvOS 11.0, iOS 11.0, *) - func margin(_ directionalInsets: NSDirectionalEdgeInsets) -> PinLayout { + public func margin(_ directionalInsets: NSDirectionalEdgeInsets) -> PinLayout { marginTop = directionalInsets.top marginBottom = directionalInsets.bottom marginStart(directionalInsets.leading) @@ -855,7 +1002,10 @@ class PinLayoutImpl: PinLayout { } #endif - func margin(_ value: CGFloat) -> PinLayout { + /** + Set all margins to the specified value. + */ + public func margin(_ value: CGFloat) -> PinLayout { marginTop = value marginLeft = value marginBottom = value @@ -863,7 +1013,10 @@ class PinLayoutImpl: PinLayout { return self } - func margin(_ percent: Percent) -> PinLayout { + /** + Set all margins to the specified value. + */ + public func margin(_ percent: Percent) -> PinLayout { func context() -> String { return "margin(\(percent.description))" } return marginTop(percent, context) .marginLeft(percent, context) @@ -871,7 +1024,10 @@ class PinLayoutImpl: PinLayout { .marginRight(percent, context) } - func margin(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) -> PinLayout { + /** + Set individually top, horizontal margins and bottom margin. + */ + public func margin(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) -> PinLayout { marginTop = top marginLeft = left marginBottom = bottom @@ -879,7 +1035,10 @@ class PinLayoutImpl: PinLayout { return self } - func margin(_ top: Percent, _ left: Percent, _ bottom: Percent, _ right: Percent) -> PinLayout { + /** + Set individually top, horizontal margins and bottom margin. + */ + public func margin(_ top: Percent, _ left: Percent, _ bottom: Percent, _ right: Percent) -> PinLayout { func context() -> String { return "margin(top: \(top.description), left: \(left.description), bottom: \(bottom.description), right: \(right.description)" } @@ -889,7 +1048,10 @@ class PinLayoutImpl: PinLayout { .marginRight(right, context) } - func margin(_ vertical: CGFloat, _ horizontal: CGFloat) -> PinLayout { + /** + Set individually vertical margins (top, bottom) and horizontal margins (left, right, start, end). + */ + public func margin(_ vertical: CGFloat, _ horizontal: CGFloat) -> PinLayout { marginTop = vertical marginLeft = horizontal marginBottom = vertical @@ -897,12 +1059,18 @@ class PinLayoutImpl: PinLayout { return self } - func margin(_ vertical: Percent, _ horizontal: Percent) -> PinLayout { + /** + Set individually vertical margins (top, bottom) and horizontal margins (left, right, start, end). + */ + public func margin(_ vertical: Percent, _ horizontal: Percent) -> PinLayout { func context() -> String { return "margin(vertical: \(vertical.description), horizontal: \(horizontal.description)"} return marginVertical(vertical, context).marginHorizontal(horizontal, context) } - func margin(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat) -> PinLayout { + /** + Set individually top, horizontal margins and bottom margin. + */ + public func margin(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat) -> PinLayout { marginTop = top marginLeft = horizontal marginBottom = bottom @@ -910,12 +1078,21 @@ class PinLayoutImpl: PinLayout { return self } - func margin(_ top: Percent, _ horizontal: Percent, _ bottom: Percent) -> PinLayout { + /** + Set individually top, horizontal margins and bottom margin. + */ + public func margin(_ top: Percent, _ horizontal: Percent, _ bottom: Percent) -> PinLayout { func context() -> String { return "margin(top: \(top.description), horizontal: \(horizontal.description), bottom: \(bottom.description)"} return marginTop(top, context).marginHorizontal(horizontal, context).marginBottom(bottom, context) } - func pinEdges() -> PinLayout { + /// Normally if only either left or right has been specified, PinLayout will MOVE the view to apply left or right margins. + /// This is also true even if the width has been set. + /// Calling pinEdges() will force PinLayout to pin the four edges and then apply left and/or right margins, and this without + /// moving the view. + /// + /// - Returns: PinLayout + public func pinEdges() -> PinLayout { shouldPinEdges = true return self } @@ -924,7 +1101,7 @@ class PinLayoutImpl: PinLayout { // // MARK: Private methods // -extension PinLayoutImpl { +extension PinLayout { internal func layoutSuperviewRect(_ context: Context) -> CGRect? { if let superview = view.superview { return superview.getRect(keepTransform: keepTransform) @@ -936,9 +1113,9 @@ extension PinLayoutImpl { } } - internal func layoutSuperview(_ context: Context) -> PView? { + internal func layoutSuperview(_ context: Context) -> View? { if let superview = view.superview { - return superview + return superview as? View } else { // Disable this warning: Using XIB, layoutSubview() is called even before views have been // added, and there is no way to modify that strange behaviour of UIKit. @@ -947,9 +1124,9 @@ extension PinLayoutImpl { } } - internal func referenceSuperview(_ referenceView: PView, _ context: Context) -> PView? { + internal func referenceSuperview(_ referenceView: View, _ context: Context) -> View? { if let superview = referenceView.superview { - return superview + return superview as? View } else { warnWontBeApplied("the reference view \(viewDescription(referenceView)) must be added as a sub-view before being used as a reference.", context) return nil diff --git a/Sources/Impl/TypesImpl.swift b/Sources/Impl/TypesImpl.swift index 49d5f27e..4dbfa9cf 100644 --- a/Sources/Impl/TypesImpl.swift +++ b/Sources/Impl/TypesImpl.swift @@ -32,10 +32,10 @@ struct Size { var height: CGFloat? } -class EdgeListImpl: EdgeList { - internal let view: PView +class EdgeListImpl: EdgeList { + internal let view: View - init(view: PView) { + init(view: View) { self.view = view } @@ -52,14 +52,14 @@ class EdgeListImpl: EdgeList { var end: HorizontalEdge { return view.isLTR() ? right : left } } -class HorizontalEdgeImpl: HorizontalEdge { +class HorizontalEdgeImpl: HorizontalEdge { enum EdgeType: String { case left case hCenter case right } - let view: PView + let view: View let type: EdgeType func x(keepTransform: Bool) -> CGFloat { @@ -72,20 +72,20 @@ class HorizontalEdgeImpl: HorizontalEdge { } } - internal init(view: PView, type: EdgeType) { + internal init(view: View, type: EdgeType) { self.view = view self.type = type } } -class VerticalEdgeImpl: VerticalEdge { +class VerticalEdgeImpl: VerticalEdge { enum EdgeType: String { case top case vCenter case bottom } - internal let view: PView + internal let view: View internal let type: EdgeType func y(keepTransform: Bool) -> CGFloat { @@ -99,16 +99,16 @@ class VerticalEdgeImpl: VerticalEdge { } } - internal init(view: PView, type: EdgeType) { + internal init(view: View, type: EdgeType) { self.view = view self.type = type } } -class AnchorListImpl: AnchorList { - internal let view: PView +class AnchorListImpl: AnchorList { + internal let view: View - internal init(view: PView) { + internal init(view: View) { self.view = view } @@ -143,8 +143,8 @@ enum AnchorType: String { case bottomRight } -class AnchorImpl: Anchor { - let view: PView +class AnchorImpl: Anchor { + let view: View let type: AnchorType func point(keepTransform: Bool) -> CGPoint { @@ -161,7 +161,7 @@ class AnchorImpl: Anchor { } } - fileprivate init(view: PView, type: AnchorType) { + fileprivate init(view: View, type: AnchorType) { self.view = view self.type = type } diff --git a/Sources/Impl/View+LTR.swift b/Sources/Impl/View+LTR.swift deleted file mode 100644 index 4931f65a..00000000 --- a/Sources/Impl/View+LTR.swift +++ /dev/null @@ -1,53 +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. - -import Foundation - -#if os(iOS) || os(tvOS) -import UIKit - -extension UIView { - func isLTR() -> Bool { - switch Pin.layoutDirection { - case .auto: - if #available(iOS 9.0, *) { - return UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .leftToRight - } else if let shared = UIApplication.value(forKey: "sharedApplication") as? UIApplication { - return shared.userInterfaceLayoutDirection == .leftToRight - } else { - return true - } - case .ltr: return true - case .rtl: return false - } - } -} -#else -import AppKit - -extension NSView { - func isLTR() -> Bool { - switch Pin.layoutDirection { - case .auto: return self.userInterfaceLayoutDirection == .leftToRight - case .ltr: return true - case .rtl: return false - } - } -} -#endif diff --git a/Sources/Layoutable+PinLayout.swift b/Sources/Layoutable+PinLayout.swift new file mode 100644 index 00000000..a43b4642 --- /dev/null +++ b/Sources/Layoutable+PinLayout.swift @@ -0,0 +1,27 @@ +// +// Layoutable+PinLayout.swift +// PinLayout-iOS +// +// Created by Antoine Lamy on 2018-06-12. +// Copyright © 2018 mcswiftlayyout.mirego.com. All rights reserved. +// + +import Foundation + +extension Layoutable { + public var pin: PinLayout { + return PinLayout(view: self as! Self.View, keepTransform: true) + } + + public var pinFrame: PinLayout { + return PinLayout(view: self as! Self.View, keepTransform: false) + } + + public var anchor: AnchorList { + return AnchorListImpl(view: self as! View) + } + + public var edge: EdgeList { + return EdgeListImpl(view: self as! View) + } +} diff --git a/Sources/Layoutable.swift b/Sources/Layoutable.swift new file mode 100644 index 00000000..398c8feb --- /dev/null +++ b/Sources/Layoutable.swift @@ -0,0 +1,27 @@ +// +// Layoutable.swift +// PinLayout +// +// Created by Antoine Lamy on 2018-06-11. +// Copyright © 2018 mcswiftlayyout.mirego.com. All rights reserved. +// + +#if os(iOS) || os(tvOS) +import UIKit +#else +import AppKit +#endif + +public protocol Layoutable: AnyObject, Equatable, CustomDebugStringConvertible { + associatedtype View: Layoutable + + var superview: View? { get } + var subviews: [View] { get } + + func getRect(keepTransform: Bool) -> CGRect + func setRect(_ rect: CGRect, keepTransform: Bool) + + func convert(_ point: CGPoint, to view: View?) -> CGPoint + + func isLTR() -> Bool +} diff --git a/Sources/NSView+PinLayout.swift b/Sources/NSView+PinLayout.swift index c683c02e..5d85ea25 100644 --- a/Sources/NSView+PinLayout.swift +++ b/Sources/NSView+PinLayout.swift @@ -22,21 +22,37 @@ import Foundation #if os(macOS) import AppKit -public extension NSView { - public var pin: PinLayout { - return PinLayoutImpl(view: self, keepTransform: true) - } +extension NSView: Layoutable { + public typealias View = NSView - public var pinFrame: PinLayout { - return PinLayoutImpl(view: self, keepTransform: false) + public func getRect(keepTransform: Bool) -> CGRect { + if let superview = superview, !superview.isFlipped { + var flippedRect = frame + flippedRect.origin.y = superview.frame.height - flippedRect.height - flippedRect.origin.y + return flippedRect + } else { + return frame + } } - public var anchor: AnchorList { - return AnchorListImpl(view: self) + public func setRect(_ rect: CGRect, keepTransform: Bool) { + let adjustedRect = Coordinates.adjustRectToDisplayScale(rect) + + if let superview = superview, !superview.isFlipped { + var flippedRect = adjustedRect + flippedRect.origin.y = superview.frame.height - flippedRect.height - flippedRect.origin.y + frame = flippedRect + } else { + frame = adjustedRect + } } - public var edge: EdgeList { - return EdgeListImpl(view: self) + public func isLTR() -> Bool { + switch Pin.layoutDirection { + case .auto: return self.userInterfaceLayoutDirection == .leftToRight + case .ltr: return true + case .rtl: return false + } } // Expose PinLayout's objective-c interface. @@ -45,4 +61,8 @@ public extension NSView { } } +extension NSControl: SizeCalculable { + +} + #endif diff --git a/Sources/ObjectiveC/PinLayoutObjCImpl.swift b/Sources/ObjectiveC/PinLayoutObjCImpl.swift index 87ad03a7..6f8f2535 100644 --- a/Sources/ObjectiveC/PinLayoutObjCImpl.swift +++ b/Sources/ObjectiveC/PinLayoutObjCImpl.swift @@ -23,11 +23,39 @@ import UIKit import AppKit #endif +#if os(iOS) || os(tvOS) +@objc extension UIView { + public var anchor: AnchorList { + return AnchorListImpl(view: self) + } + + public var edge: EdgeList { + return EdgeListImpl(view: self) + } +} +#else +@objc extension NSView { + public var anchor: AnchorList { + return AnchorListImpl(view: self) + } + + public var edge: EdgeList { + return EdgeListImpl(view: self) + } +} +#endif + @objc class PinLayoutObjCImpl: NSObject, PinLayoutObjC { - fileprivate var impl: PinLayoutImpl? + #if os(iOS) || os(tvOS) + typealias PView = UIView + #else + typealias PView = NSView + #endif + + fileprivate var impl: PinLayout? init(view: PView, keepTransform: Bool) { - impl = PinLayoutImpl(view: view, keepTransform: keepTransform) + impl = PinLayout(view: view, keepTransform: keepTransform) } deinit { diff --git a/Sources/PinLayout.swift b/Sources/PinLayout.swift index a94e6756..64411f4f 100644 --- a/Sources/PinLayout.swift +++ b/Sources/PinLayout.swift @@ -16,7 +16,7 @@ // 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 @@ -589,3 +589,4 @@ public protocol PinLayout { */ func layout() } + */ diff --git a/Sources/SizeCalculable.swift b/Sources/SizeCalculable.swift new file mode 100644 index 00000000..9125bbc5 --- /dev/null +++ b/Sources/SizeCalculable.swift @@ -0,0 +1,18 @@ +// +// Sizable.swift +// PinLayout-iOS +// +// Created by Antoine Lamy on 2018-06-12. +// Copyright © 2018 mcswiftlayyout.mirego.com. All rights reserved. +// + +#if os(iOS) || os(tvOS) +import UIKit +#else +import AppKit +#endif + +public protocol SizeCalculable { + func sizeThatFits(_ size: CGSize) -> CGSize + func sizeToFit() +} diff --git a/Sources/UIView+PinLayout.swift b/Sources/UIView+PinLayout.swift index 36121e59..35bc2ab9 100644 --- a/Sources/UIView+PinLayout.swift +++ b/Sources/UIView+PinLayout.swift @@ -22,21 +22,62 @@ import Foundation #if os(iOS) || os(tvOS) import UIKit -public extension UIView { - public var pin: PinLayout { - return PinLayoutImpl(view: self, keepTransform: true) - } +extension UIView: Layoutable, SizeCalculable { + public typealias View = UIView + + public func getRect(keepTransform: Bool) -> CGRect { + if keepTransform { + /* + To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the + view's transform (UIView.transform). + By setting the view's center and bounds we really set the frame of the non-transformed view, and this keep + the view's transform. So view's transforms won't be affected/altered by PinLayout. + */ + let size = bounds.size + // See setRect(...) for details about this calculation. + let origin = CGPoint(x: center.x - (size.width * layer.anchorPoint.x), + y: center.y - (size.height * layer.anchorPoint.y)) - public var pinFrame: PinLayout { - return PinLayoutImpl(view: self, keepTransform: false) + return CGRect(origin: origin, size: size) + } else { + return frame + } } - @objc public var anchor: AnchorList { - return AnchorListImpl(view: self) + public func setRect(_ rect: CGRect, keepTransform: Bool) { + let adjustedRect = Coordinates.adjustRectToDisplayScale(rect) + + if keepTransform { + /* + To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the + view's transform (UIView.transform). + By setting the view's center and bounds we really set the frame of the non-transformed view, and this keep + the view's transform. So view's transforms won't be affected/altered by PinLayout. + */ + + // NOTE: The center is offset by the layer.anchorPoint, so we have to take it into account. + center = CGPoint(x: adjustedRect.origin.x + (adjustedRect.width * layer.anchorPoint.x), + y: adjustedRect.origin.y + (adjustedRect.height * layer.anchorPoint.y)) + // NOTE: We must set only the bounds's size and keep the origin. + bounds.size = adjustedRect.size + } else { + frame = adjustedRect + } } - @objc public var edge: EdgeList { - return EdgeListImpl(view: self) + public func isLTR() -> Bool { + switch Pin.layoutDirection { + case .auto: + if #available(iOS 9.0, *) { + return UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .leftToRight + } else if let shared = UIApplication.value(forKey: "sharedApplication") as? UIApplication { + return shared.userInterfaceLayoutDirection == .leftToRight + } else { + return true + } + case .ltr: return true + case .rtl: return false + } } // Expose PinLayout's objective-c interface. diff --git a/Sources/View+Rect.swift b/Sources/View+Rect.swift deleted file mode 100644 index ed09591a..00000000 --- a/Sources/View+Rect.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// View+Rect.swift -// PinLayout-iOS -// -// Created by Luc Dion on 2018-06-08. -// Copyright © 2018 mcswiftlayyout.mirego.com. All rights reserved. -// - -import Foundation - -#if os(iOS) || os(tvOS) -import UIKit - -extension UIView { - func getRect(keepTransform: Bool) -> CGRect { - if keepTransform { - /* - To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the - view's transform (UIView.transform). - By setting the view's center and bounds we really set the frame of the non-transformed view, and this keep - the view's transform. So view's transforms won't be affected/altered by PinLayout. - */ - let size = bounds.size - // See setRect(...) for details about this calculation. - let origin = CGPoint(x: center.x - (size.width * layer.anchorPoint.x), - y: center.y - (size.height * layer.anchorPoint.y)) - - return CGRect(origin: origin, size: size) - } else { - return frame - } - } - - func setRect(_ rect: CGRect, keepTransform: Bool) { - let adjustedRect = Coordinates.adjustRectToDisplayScale(rect) - - if keepTransform { - /* - To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the - view's transform (UIView.transform). - By setting the view's center and bounds we really set the frame of the non-transformed view, and this keep - the view's transform. So view's transforms won't be affected/altered by PinLayout. - */ - - // NOTE: The center is offset by the layer.anchorPoint, so we have to take it into account. - center = CGPoint(x: adjustedRect.origin.x + (adjustedRect.width * layer.anchorPoint.x), - y: adjustedRect.origin.y + (adjustedRect.height * layer.anchorPoint.y)) - // NOTE: We must set only the bounds's size and keep the origin. - bounds.size = adjustedRect.size - } else { - frame = adjustedRect - } - } -} -#else - -import AppKit - -extension NSView { - func getRect(keepTransform: Bool) -> CGRect { - if let superview = superview, !superview.isFlipped { - var flippedRect = frame - flippedRect.origin.y = superview.frame.height - flippedRect.height - flippedRect.origin.y - return flippedRect - } else { - return frame - } - } - - func setRect(_ rect: CGRect, keepTransform: Bool) { - let adjustedRect = Coordinates.adjustRectToDisplayScale(rect) - - if let superview = superview, !superview.isFlipped { - var flippedRect = adjustedRect - flippedRect.origin.y = superview.frame.height - flippedRect.height - flippedRect.origin.y - frame = flippedRect - } else { - frame = adjustedRect - } - } -} -#endif diff --git a/Tests/BasicView.swift b/Tests/BasicView.swift index 261e7b92..4a8f2312 100644 --- a/Tests/BasicView.swift +++ b/Tests/BasicView.swift @@ -23,6 +23,8 @@ import UIKit import AppKit #endif +import PinLayout + class BasicView: PView { #if os(macOS) fileprivate var _isFlipped: Bool = true @@ -53,10 +55,6 @@ class BasicView: PView { override func sizeThatFits(_ size: CGSize) -> CGSize { return _sizeThatFits(size) } - #else - func sizeThatFits(_ size: CGSize) -> CGSize { - return _sizeThatFits(size) - } #endif fileprivate func _sizeThatFits(_ size: CGSize) -> CGSize { @@ -75,3 +73,15 @@ class BasicView: PView { return newSize } } + +#if os(macOS) +extension BasicView: SizeCalculable { + func sizeThatFits(_ size: CGSize) -> CGSize { + return _sizeThatFits(size) + } + + func sizeToFit() { + // Do nothing + } +} +#endif diff --git a/Tests/Common/AdjustSizeSpec.swift b/Tests/Common/AdjustSizeSpec.swift index 5f684c7b..98d34d36 100644 --- a/Tests/Common/AdjustSizeSpec.swift +++ b/Tests/Common/AdjustSizeSpec.swift @@ -45,7 +45,7 @@ class AdjustSizeSpec: QuickSpec { */ beforeSuite { - _pinlayoutSetUnitTest(displayScale: 2) + _pinlayoutSetUnitTest(scale: 2) } beforeEach { diff --git a/Tests/Common/AspectRatioTests.swift b/Tests/Common/AspectRatioTests.swift index 45ca9506..4c0f8553 100644 --- a/Tests/Common/AspectRatioTests.swift +++ b/Tests/Common/AspectRatioTests.swift @@ -41,7 +41,7 @@ class AspectRatioTests: QuickSpec { */ beforeSuite { - _pinlayoutSetUnitTest(displayScale: 2) + _pinlayoutSetUnitTest(scale: 2) } beforeEach { diff --git a/Tests/Common/JustifyAlignSpec.swift b/Tests/Common/JustifyAlignSpec.swift index 05b6ac53..1f4a29c5 100644 --- a/Tests/Common/JustifyAlignSpec.swift +++ b/Tests/Common/JustifyAlignSpec.swift @@ -34,7 +34,7 @@ class JustifyAlignSpec: QuickSpec { */ beforeSuite { - _pinlayoutSetUnitTest(displayScale: 2) + _pinlayoutSetUnitTest(scale: 2) } beforeEach { diff --git a/Tests/Common/LayoutMethodSpec.swift b/Tests/Common/LayoutMethodSpec.swift index a38fe2eb..9867aef1 100644 --- a/Tests/Common/LayoutMethodSpec.swift +++ b/Tests/Common/LayoutMethodSpec.swift @@ -34,7 +34,7 @@ class LayoutMethodSpec: QuickSpec { */ beforeSuite { - _pinlayoutSetUnitTest(displayScale: 2) + _pinlayoutSetUnitTest(scale: 2) } beforeEach { diff --git a/Tests/Common/MinMaxWidthHeightSpec.swift b/Tests/Common/MinMaxWidthHeightSpec.swift index 8b6c86df..83c863fe 100644 --- a/Tests/Common/MinMaxWidthHeightSpec.swift +++ b/Tests/Common/MinMaxWidthHeightSpec.swift @@ -34,7 +34,7 @@ class MinMaxWidthHeightSpec: QuickSpec { */ beforeSuite { - _pinlayoutSetUnitTest(displayScale: 2) + _pinlayoutSetUnitTest(scale: 2) } beforeEach { diff --git a/Tests/Common/WarningSpec.swift b/Tests/Common/WarningSpec.swift index aafecc55..92767598 100644 --- a/Tests/Common/WarningSpec.swift +++ b/Tests/Common/WarningSpec.swift @@ -34,7 +34,7 @@ class WarningSpec: QuickSpec { */ beforeSuite { - _pinlayoutSetUnitTest(displayScale: 2) + _pinlayoutSetUnitTest(scale: 2) } beforeEach { diff --git a/Tests/Common/WrapContentSpec.swift b/Tests/Common/WrapContentSpec.swift index ff56ae01..3dc44b49 100644 --- a/Tests/Common/WrapContentSpec.swift +++ b/Tests/Common/WrapContentSpec.swift @@ -41,7 +41,7 @@ class WrapContentSpec: QuickSpec { var aViewChild3: BasicView! beforeSuite { - _pinlayoutSetUnitTest(displayScale: 2) + _pinlayoutSetUnitTest(scale: 2) } beforeEach {