diff --git a/.gitignore b/.gitignore index 2c22487b..828c794e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,65 +1,10 @@ # Xcode # -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore -## Build generated build/ DerivedData/ - -## Various settings -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata/ - -## Other -*.moved-aside -*.xcuserstate - -## Obj-C/Swift specific -*.hmap -*.ipa -*.dSYM.zip -*.dSYM - -## Playgrounds -timeline.xctimeline -playground.xcworkspace - -# Swift Package Manager -# -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. -# Packages/ -.build/ - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# Pods/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - +Pods/ Carthage/Build - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output +MCSwiftLayoutSample/Pods +xcuserdata +*.xcworkspace \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..a74f243e --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +# Gemfile +source 'https://rubygems.org' + +gem 'cocoapods', '~>1.1.0' +gem 'synx', '~> 0.2.1' diff --git a/Keynote Layout presentation.key b/Keynote Layout presentation.key index c7d4b19a..26837908 100644 Binary files a/Keynote Layout presentation.key and b/Keynote Layout presentation.key differ diff --git a/MCSwiftLayout.xcodeproj/project.pbxproj b/MCSwiftLayout.xcodeproj/project.pbxproj index c4742ac2..97987461 100644 --- a/MCSwiftLayout.xcodeproj/project.pbxproj +++ b/MCSwiftLayout.xcodeproj/project.pbxproj @@ -8,9 +8,11 @@ /* Begin PBXBuildFile section */ 2439CC311E6659FA003326FB /* Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2439CC301E6659FA003326FB /* Layout.swift */; }; + 246D36481E6C46F50050F202 /* BasicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 246D36471E6C46F50050F202 /* BasicTests.swift */; }; 249EFE841E64FB4C00165E39 /* MCSwiftLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 249EFE7A1E64FB4C00165E39 /* MCSwiftLayout.framework */; }; 249EFE891E64FB4C00165E39 /* MCSwiftLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249EFE881E64FB4C00165E39 /* MCSwiftLayoutTests.swift */; }; 249EFE8B1E64FB4C00165E39 /* MCSwiftLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 249EFE7D1E64FB4C00165E39 /* MCSwiftLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E88B11042FE48DD3D4E7EB0C /* Pods_MCSwiftLayoutTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB717599553AA71EE659C312 /* Pods_MCSwiftLayoutTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -25,12 +27,16 @@ /* Begin PBXFileReference section */ 2439CC301E6659FA003326FB /* Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Layout.swift; sourceTree = ""; }; + 246D36471E6C46F50050F202 /* BasicTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicTests.swift; sourceTree = ""; }; 249EFE7A1E64FB4C00165E39 /* MCSwiftLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MCSwiftLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 249EFE7D1E64FB4C00165E39 /* MCSwiftLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MCSwiftLayout.h; sourceTree = ""; }; 249EFE7E1E64FB4C00165E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 249EFE831E64FB4C00165E39 /* MCSwiftLayoutTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MCSwiftLayoutTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 249EFE881E64FB4C00165E39 /* MCSwiftLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCSwiftLayoutTests.swift; sourceTree = ""; }; 249EFE8A1E64FB4C00165E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 657A2A825B5BD607ACB09F58 /* Pods-MCSwiftLayoutTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MCSwiftLayoutTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MCSwiftLayoutTests/Pods-MCSwiftLayoutTests.debug.xcconfig"; sourceTree = ""; }; + DB717599553AA71EE659C312 /* Pods_MCSwiftLayoutTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MCSwiftLayoutTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E8C9302287EF4331340F627C /* Pods-MCSwiftLayoutTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MCSwiftLayoutTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-MCSwiftLayoutTests/Pods-MCSwiftLayoutTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -46,18 +52,29 @@ buildActionMask = 2147483647; files = ( 249EFE841E64FB4C00165E39 /* MCSwiftLayout.framework in Frameworks */, + E88B11042FE48DD3D4E7EB0C /* Pods_MCSwiftLayoutTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 138A1F602470415292B7194B /* Frameworks */ = { + isa = PBXGroup; + children = ( + DB717599553AA71EE659C312 /* Pods_MCSwiftLayoutTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 249EFE701E64FB4C00165E39 = { isa = PBXGroup; children = ( 249EFE7C1E64FB4C00165E39 /* MCSwiftLayout */, 249EFE871E64FB4C00165E39 /* MCSwiftLayoutTests */, 249EFE7B1E64FB4C00165E39 /* Products */, + 8604B3F1C9C7A0EB2F11356F /* Pods */, + 138A1F602470415292B7194B /* Frameworks */, ); sourceTree = ""; }; @@ -84,11 +101,21 @@ isa = PBXGroup; children = ( 249EFE881E64FB4C00165E39 /* MCSwiftLayoutTests.swift */, + 246D36471E6C46F50050F202 /* BasicTests.swift */, 249EFE8A1E64FB4C00165E39 /* Info.plist */, ); path = MCSwiftLayoutTests; sourceTree = ""; }; + 8604B3F1C9C7A0EB2F11356F /* Pods */ = { + isa = PBXGroup; + children = ( + 657A2A825B5BD607ACB09F58 /* Pods-MCSwiftLayoutTests.debug.xcconfig */, + E8C9302287EF4331340F627C /* Pods-MCSwiftLayoutTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -125,9 +152,12 @@ isa = PBXNativeTarget; buildConfigurationList = 249EFE911E64FB4C00165E39 /* Build configuration list for PBXNativeTarget "MCSwiftLayoutTests" */; buildPhases = ( + DD0B0B702D32991A998E967B /* [CP] Check Pods Manifest.lock */, 249EFE7F1E64FB4C00165E39 /* Sources */, 249EFE801E64FB4C00165E39 /* Frameworks */, 249EFE811E64FB4C00165E39 /* Resources */, + 45B171B50A18EC68ECE6BBC9 /* [CP] Embed Pods Frameworks */, + 876430984866C52BFD6C79B8 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -197,6 +227,54 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 45B171B50A18EC68ECE6BBC9 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/MCSwiftLayoutSample/Pods/Target Support Files/Pods-MCSwiftLayoutTests/Pods-MCSwiftLayoutTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 876430984866C52BFD6C79B8 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/MCSwiftLayoutSample/Pods/Target Support Files/Pods-MCSwiftLayoutTests/Pods-MCSwiftLayoutTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + DD0B0B702D32991A998E967B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 249EFE751E64FB4C00165E39 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -210,6 +288,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 246D36481E6C46F50050F202 /* BasicTests.swift in Sources */, 249EFE891E64FB4C00165E39 /* MCSwiftLayoutTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -336,6 +415,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = MCSwiftLayout/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mirego.MCSwiftLayout; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -357,6 +437,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = MCSwiftLayout/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mirego.MCSwiftLayout; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -367,6 +448,7 @@ }; 249EFE921E64FB4C00165E39 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 657A2A825B5BD607ACB09F58 /* Pods-MCSwiftLayoutTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; DEVELOPMENT_TEAM = 4Q596JWQC5; @@ -380,6 +462,7 @@ }; 249EFE931E64FB4C00165E39 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E8C9302287EF4331340F627C /* Pods-MCSwiftLayoutTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; DEVELOPMENT_TEAM = 4Q596JWQC5; diff --git a/MCSwiftLayout/Layout.swift b/MCSwiftLayout/Layout.swift index e246cd2a..2ec6b424 100644 --- a/MCSwiftLayout/Layout.swift +++ b/MCSwiftLayout/Layout.swift @@ -14,6 +14,15 @@ import UIKit - Implement Layout + Layout operator + - layout.snapTopLeft(to: .bottomRight, of: view2) + - layout.snapTopLeft(to: .bottomRight, of: view2) + - layout.snapTopLeft(to: view2, .bottomRight) + - layout.topLeft(to: .bottomRight, of: view2) + - layout.topLeft(view2.bottomRight) -> Ne fonctionne pas si pas le même parent! + - layout.snapTop(to: .bottom, of: view2) + - layout.top(to: .bottom, of: view2) + + - Implement - marginHorizontal - marginVertical @@ -147,16 +156,16 @@ public extension UIView { return Layout(view: self) } -// func layout(_ positionning: Layout) { -// positionning.apply(onView: self) -// } + func layout(with layout: Layout) { + layout.apply(onView: self) + } } public class Layout { static var logConflicts = true - fileprivate let view: UIView? + fileprivate let view: UIView fileprivate var top: CGFloat? fileprivate var left: CGFloat? @@ -180,7 +189,7 @@ public class Layout { fileprivate var bottomInset: CGFloat? fileprivate var rightInset: CGFloat? - public init (view: UIView? = nil) { + public init (view: UIView/*? = nil*/) { self.view = view } @@ -219,92 +228,130 @@ public class Layout { @discardableResult public func topLeft(_ point: CGPoint) -> Layout { - return topLeft(x: point.x, y: point.y) + return setTopLeft(x: point.x, y: point.y, setterContext: "topLeft(CGPoint(\(point.x), \(point.y)))") } - @discardableResult - public func topLeft(x: CGFloat, y: CGFloat) -> Layout { - return setTopLeft(x: x, y: y, setterContext: "topLeft(\(x), \(y))") - } +// @discardableResult +// public func topLeft(x: CGFloat, y: CGFloat) -> Layout { +// return setTopLeft(x: x, y: y, setterContext: "topLeft(x: \(x), y:\(y))") +// } @discardableResult public func topCenter(_ point: CGPoint) -> Layout { - return topCenter(x: point.x, y: point.y) + return setTopCenter(x: point.x, y: point.y, setterContext: "topCenter(CGPoint(\(point.x), \(point.y)))") } +// @discardableResult +// public func topCenter(x: CGFloat, y: CGFloat) -> Layout { +// return setTopCenter(x: x, y: y, setterContext: "topCenter(x: \(x), y:\(y))") +// } + @discardableResult - public func topCenter(x: CGFloat, y: CGFloat) -> Layout { - return setTopCenter(x: x, y: y, setterContext: "topCenter(\(x), \(y))") + public func topRight(_ point: CGPoint) -> Layout { + return setTopRight(x: point.x, y: point.y, setterContext: "topRight(CGPoint(\(point.x), \(point.y)))") } +// @discardableResult +// public func topRight(x: CGFloat, y: CGFloat) -> Layout { +// return setTopRight(x: x, y: y, setterContext: "topRight(x: \(x), y:\(y))") +// } + @discardableResult - public func topRight(_ point: CGPoint) -> Layout { - return topRight(x: point.x, y: point.y) + public func leftCenter(_ point: CGPoint) -> Layout { + return setLeftCenter(x: point.x, y: point.y, setterContext: "leftCenter(CGPoint(\(point.x), \(point.y)))") } + +// @discardableResult +// public func leftCenter(x: CGFloat, y: CGFloat) -> Layout { +// return setLeftCenter(x: x, y: y, setterContext: "leftCenter(x: \(x), y:\(y))") +// } @discardableResult - public func topRight(x: CGFloat, y: CGFloat) -> Layout { - return setTopRight(x: x, y: y, setterContext: "topRight(\(x), \(y))") + public func centers(_ point: CGPoint) -> Layout { + return setCenters(x: point.x, y: point.y, setterContext: "centers(CGPoint(\(point.x), \(point.y)))") } @discardableResult - public func leftCenter(_ point: CGPoint) -> Layout { - return leftCenter(x: point.x, y: point.y) + public func centers(of relativeView: UIView) -> Layout { + if let layoutSuperview = validateLayoutSuperview(setterContext: "centers(of: \(view))") { + if let relativeSuperview = relativeView.superview { + let center: CGPoint + if layoutSuperview == relativeSuperview { + center = relativeView.centers // same parent => no coordinates conversion required. + } else { + center = relativeSuperview.convert(relativeView.centers, to: layoutSuperview) + } + setCenters(x: center.x, y: center.y, setterContext: "centers(of: \(view))") + } else { + warn("relative view's superview is nil", setterContext: "centers(of: \(view))") + } + } + return self } @discardableResult - public func leftCenter(x: CGFloat, y: CGFloat) -> Layout { - return setLeftCenter(x: x, y: y, setterContext: "leftCenter(\(x), \(y))") + public func centers() -> Layout { + if let layoutSuperview = validateLayoutSuperview(setterContext: "centers()") { + let center = layoutSuperview.center + setCenters(x: center.x, y: center.y, setterContext: "centers()") + } + return self + } + + fileprivate func validateLayoutSuperview(setterContext: @autoclosure () -> String) -> UIView? { + if let parentView = view.superview { + return parentView + } else { + warn("Layout's view must be added to a UIView before being layouted using this method.", setterContext: setterContext) + return nil + } } + - // TODO center!!! -// var centers: CGPoint { -// get { return CGPoint(x: hCenter, y: vCenter) } -// set { -// left = newValue.x - (width / 2) -// top = newValue.y - (width / 2) -// } +// @discardableResult +// public func centers(x: CGFloat, y: CGFloat) -> Layout { +// return setCenters(x: x, y: y, setterContext: "centers(x: \(x), y:\(y))") // } @discardableResult public func rightCenter(_ point: CGPoint) -> Layout { - return rightCenter(x: point.x, y: point.y) + return setRightCenter(x: point.x, y: point.y, setterContext: "rightCenter(CGPoint(\(point.x), \(point.y)))") } - @discardableResult - public func rightCenter(x: CGFloat, y: CGFloat) -> Layout { - return setRightCenter(x: x, y: y, setterContext: "rightCenter(\(x), \(y))") - } +// @discardableResult +// public func rightCenter(x: CGFloat, y: CGFloat) -> Layout { +// return setRightCenter(x: x, y: y, setterContext: "rightCenter(x: \(x), y:\(y))") +// } @discardableResult public func bottomLeft(_ point: CGPoint) -> Layout { - return bottomLeft(x: point.x, y: point.y) + return setBottomLeft(x: point.x, y: point.y, setterContext: "bottomLeft(CGPoint(\(point.x), \(point.y)))") } - @discardableResult - public func bottomLeft(x: CGFloat, y: CGFloat) -> Layout { - return setBottomLeft(x: x, y: y, setterContext: "bottomLeft(\(x), \(y))") - } +// @discardableResult +// public func bottomLeft(x: CGFloat, y: CGFloat) -> Layout { +// return setBottomLeft(x: x, y: y, setterContext: "bottomLeft(x: \(x), y:\(y))") +// } @discardableResult public func bottomCenter(_ point: CGPoint) -> Layout { - return bottomCenter(x: point.x, y: point.y) + return setBottomCenter(x: point.x, y: point.y, setterContext: "bottomCenter(CGPoint(\(point.x), \(point.y)))") } - @discardableResult - public func bottomCenter(x: CGFloat, y: CGFloat) -> Layout { - return setBottomCenter(x: x, y: y, setterContext: "bottomCenter(\(x), \(y))") - } +// @discardableResult +// public func bottomCenter(x: CGFloat, y: CGFloat) -> Layout { +// return setBottomCenter(x: x, y: y, setterContext: "bottomCenter(x: \(x), y:\(y))") +// } @discardableResult public func bottomRight(_ point: CGPoint) -> Layout { - return bottomRight(x: point.x, y: point.y) + return setBottomRight(x: point.x, y: point.y, setterContext: "bottomRight(CGPoint(\(point.x), \(point.y)))") } - @discardableResult - public func bottomRight(x: CGFloat, y: CGFloat) -> Layout { - return setBottomRight(x: x, y: y, setterContext: "bottomRight(\(x), \(y))") - } +// @discardableResult +// public func bottomRight(x: CGFloat, y: CGFloat) -> Layout { +// return setBottomRight(x: x, y: y, setterContext: "bottomRight(x: \(x), y:\(y))") +// } // RELATIVE POSITION public enum HorizontalAlignment { @@ -598,7 +645,7 @@ public class Layout { } fileprivate func apply() { - guard let view = view else { return } + //guard let view = view else { return } apply(onView: view) } @@ -623,7 +670,7 @@ public class Layout { } else if bottom != nil { // bottom is set => adjust the origin and the height newRect.origin.y = applyMarginsAndInsets(top: top) - newRect.size.height = applyTopBottomInsets(bottom! - top) + newRect.size.height = applyMarginsAndInsets(bottom: bottom! - newRect.origin.y) } else if height != nil { // height is set => adjust the origin and the height newRect.origin.y = applyMarginsAndInsets(top: top) @@ -676,7 +723,7 @@ public class Layout { } else if right != nil { // right is set => adjust the origin and the width newRect.origin.x = applyMarginsAndInsets(left: left) - newRect.size.width = right! - newRect.origin.x - (rightMargin ?? 0) - (rightInset ?? 0) + newRect.size.width = applyMarginsAndInsets(right: right!) - newRect.origin.x//! - newRect.origin.x - (rightMargin ?? 0) - (rightInset ?? 0) } else if width != nil { // width is set => adjust the origin and the height newRect.origin.x = applyMarginsAndInsets(left: left) @@ -825,6 +872,13 @@ extension Layout { return self } + @discardableResult + fileprivate func setCenters(x: CGFloat, y: CGFloat, setterContext: @autoclosure () -> String) -> Layout { + setHorizontalCenter(x, setterContext: setterContext) + setVerticalCenter(y, setterContext: setterContext) + return self + } + @discardableResult fileprivate func setRightCenter(x: CGFloat, y: CGFloat, setterContext: @autoclosure () -> String) -> Layout { setRightCoordinate(x, setterContext: setterContext) @@ -911,10 +965,18 @@ extension Layout { return top + (topMargin ?? 0) + (topInset ?? 0) } + fileprivate func applyMarginsAndInsets(bottom: CGFloat) -> CGFloat { + return bottom - (bottomMargin ?? 0) - (bottomInset ?? 0) + } + fileprivate func applyMarginsAndInsets(left: CGFloat) -> CGFloat { return left + (leftMargin ?? 0) + (leftInset ?? 0) } + fileprivate func applyMarginsAndInsets(right: CGFloat) -> CGFloat { + return right - (rightMargin ?? 0) - (rightInset ?? 0) + } + fileprivate func applyTopBottomInsets(_ height: CGFloat) -> CGFloat { return height - (topInset ?? 0) - (bottomInset ?? 0) } diff --git a/MCSwiftLayoutSample/.swiftlint.yml b/MCSwiftLayoutSample/.swiftlint.yml new file mode 100644 index 00000000..316f7348 --- /dev/null +++ b/MCSwiftLayoutSample/.swiftlint.yml @@ -0,0 +1,34 @@ +opt_in_rules: # some rules are only opt-in + - attributes + - closure_end_indentation + - closure_spacing + - empty_count + - explicit_init + - nimble_operator + - number_separator + - operator_usage_whitespace + - overridden_super_call + - private_outlet + - prohibited_super_call + - redundant_nil_coalescing + +disabled_rules: # rule identifiers to exclude from running +# - function_body_length + - trailing_whitespace + - force_cast + - type_name +# - todo +# - file_length +# - type_body_length +# - valid_docs +# - cyclomatic_complexity +# - nesting +# - function_parameter_count +# - large_tuple +# - variable_name +# - empty_parentheses_with_trailing_closure + - line_length + +excluded: # paths to ignore during linting. overridden by `included`. + - Pods + diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample.xcodeproj/project.pbxproj b/MCSwiftLayoutSample/MCSwiftLayoutSample.xcodeproj/project.pbxproj index 3f46d19b..be9e863e 100644 --- a/MCSwiftLayoutSample/MCSwiftLayoutSample.xcodeproj/project.pbxproj +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample.xcodeproj/project.pbxproj @@ -29,8 +29,11 @@ 249EFE431E64FAFE00165E39 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249EFE421E64FAFE00165E39 /* AppDelegate.swift */; }; 249EFE4A1E64FAFE00165E39 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 249EFE491E64FAFE00165E39 /* Assets.xcassets */; }; 249EFE4D1E64FAFE00165E39 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 249EFE4B1E64FAFE00165E39 /* LaunchScreen.storyboard */; }; - 249EFE581E64FAFE00165E39 /* MCSwiftLayoutSampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249EFE571E64FAFE00165E39 /* MCSwiftLayoutSampleTests.swift */; }; 249EFE631E64FAFE00165E39 /* MCSwiftLayoutSampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249EFE621E64FAFE00165E39 /* MCSwiftLayoutSampleUITests.swift */; }; + 24E6547A1E68F27D00A72A8B /* BothEdgesSnappedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E654781E68F27D00A72A8B /* BothEdgesSnappedView.swift */; }; + 24E6547B1E68F27D00A72A8B /* BothEdgesSnappedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E654791E68F27D00A72A8B /* BothEdgesSnappedViewController.swift */; }; + 24E654821E69041B00A72A8B /* Expect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E654811E69041B00A72A8B /* Expect.swift */; }; + DE6C3D736B571B80E207DF6A /* Pods_MCSwiftLayoutSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAD69688AA2A3F0994F3074E /* Pods_MCSwiftLayoutSample.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -110,11 +113,16 @@ 249EFE4C1E64FAFE00165E39 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 249EFE4E1E64FAFE00165E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 249EFE531E64FAFE00165E39 /* MCSwiftLayoutSampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MCSwiftLayoutSampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 249EFE571E64FAFE00165E39 /* MCSwiftLayoutSampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCSwiftLayoutSampleTests.swift; sourceTree = ""; }; 249EFE591E64FAFE00165E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 249EFE5E1E64FAFE00165E39 /* MCSwiftLayoutSampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MCSwiftLayoutSampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 249EFE621E64FAFE00165E39 /* MCSwiftLayoutSampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCSwiftLayoutSampleUITests.swift; sourceTree = ""; }; 249EFE641E64FAFE00165E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 24E654781E68F27D00A72A8B /* BothEdgesSnappedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BothEdgesSnappedView.swift; path = Test/BothEdgesSnapped/BothEdgesSnappedView.swift; sourceTree = ""; }; + 24E654791E68F27D00A72A8B /* BothEdgesSnappedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BothEdgesSnappedViewController.swift; path = Test/BothEdgesSnapped/BothEdgesSnappedViewController.swift; sourceTree = ""; }; + 24E654811E69041B00A72A8B /* Expect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Expect.swift; path = Domain/Expect.swift; sourceTree = ""; }; + AAD69688AA2A3F0994F3074E /* Pods_MCSwiftLayoutSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MCSwiftLayoutSample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F121E291CADD796B007C04BB /* Pods-MCSwiftLayoutSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MCSwiftLayoutSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-MCSwiftLayoutSample/Pods-MCSwiftLayoutSample.release.xcconfig"; sourceTree = ""; }; + F1ACB0EACBD84B57B50D472D /* Pods-MCSwiftLayoutSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MCSwiftLayoutSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MCSwiftLayoutSample/Pods-MCSwiftLayoutSample.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -123,6 +131,7 @@ buildActionMask = 2147483647; files = ( 2439CC2B1E6658CC003326FB /* MCSwiftLayout.framework in Frameworks */, + DE6C3D736B571B80E207DF6A /* Pods_MCSwiftLayoutSample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -143,6 +152,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 160FB83905049FCEDD18DC8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + AAD69688AA2A3F0994F3074E /* Pods_MCSwiftLayoutSample.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 2439CC1F1E665858003326FB /* Products */ = { isa = PBXGroup; children = ( @@ -165,6 +182,7 @@ 2439CC371E665C5E003326FB /* Test */ = { isa = PBXGroup; children = ( + 24E654761E68F20400A72A8B /* BothEdgesSnapped */, 2439CC601E665FDE003326FB /* ChainedLayoutView */, 2439CC621E666043003326FB /* MarginsAndPaddingsLeftWidthView */, 2439CC611E665FFD003326FB /* MarginsAndPaddingsLeftRightView */, @@ -274,6 +292,8 @@ 249EFE561E64FAFE00165E39 /* MCSwiftLayoutSampleTests */, 249EFE611E64FAFE00165E39 /* MCSwiftLayoutSampleUITests */, 249EFE401E64FAFE00165E39 /* Products */, + F143180314A617EFD07C5709 /* Pods */, + 160FB83905049FCEDD18DC8A /* Frameworks */, ); sourceTree = ""; }; @@ -290,6 +310,7 @@ 249EFE411E64FAFE00165E39 /* MCSwiftLayoutSample */ = { isa = PBXGroup; children = ( + 24E654801E69040000A72A8B /* Domain */, 249EFE421E64FAFE00165E39 /* AppDelegate.swift */, 2439CC321E665BE3003326FB /* UI */, 2439CC671E66614D003326FB /* Supporting Files */, @@ -300,7 +321,6 @@ 249EFE561E64FAFE00165E39 /* MCSwiftLayoutSampleTests */ = { isa = PBXGroup; children = ( - 249EFE571E64FAFE00165E39 /* MCSwiftLayoutSampleTests.swift */, 249EFE591E64FAFE00165E39 /* Info.plist */, ); path = MCSwiftLayoutSampleTests; @@ -315,6 +335,32 @@ path = MCSwiftLayoutSampleUITests; sourceTree = ""; }; + 24E654761E68F20400A72A8B /* BothEdgesSnapped */ = { + isa = PBXGroup; + children = ( + 24E654781E68F27D00A72A8B /* BothEdgesSnappedView.swift */, + 24E654791E68F27D00A72A8B /* BothEdgesSnappedViewController.swift */, + ); + name = BothEdgesSnapped; + sourceTree = ""; + }; + 24E654801E69040000A72A8B /* Domain */ = { + isa = PBXGroup; + children = ( + 24E654811E69041B00A72A8B /* Expect.swift */, + ); + name = Domain; + sourceTree = ""; + }; + F143180314A617EFD07C5709 /* Pods */ = { + isa = PBXGroup; + children = ( + F1ACB0EACBD84B57B50D472D /* Pods-MCSwiftLayoutSample.debug.xcconfig */, + F121E291CADD796B007C04BB /* Pods-MCSwiftLayoutSample.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -322,10 +368,14 @@ isa = PBXNativeTarget; buildConfigurationList = 249EFE671E64FAFE00165E39 /* Build configuration list for PBXNativeTarget "MCSwiftLayoutSample" */; buildPhases = ( + DDE1EE639E8C959FEBC41FDC /* [CP] Check Pods Manifest.lock */, 249EFE3B1E64FAFE00165E39 /* Sources */, 249EFE3C1E64FAFE00165E39 /* Frameworks */, 249EFE3D1E64FAFE00165E39 /* Resources */, 2460ACCE1E64FD9D000BCAC5 /* Embed Frameworks */, + 5D3C4568AFC08267110D9971 /* [CP] Embed Pods Frameworks */, + CCCCC7EE5AE16BA960D7DB4F /* [CP] Copy Pods Resources */, + 24E6547E1E68F88D00A72A8B /* Run Swiftlint */, ); buildRules = ( ); @@ -471,6 +521,68 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 24E6547E1E68F88D00A72A8B /* Run Swiftlint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Swiftlint"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = Pods/SwiftLint/swiftlint; + }; + 5D3C4568AFC08267110D9971 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MCSwiftLayoutSample/Pods-MCSwiftLayoutSample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + CCCCC7EE5AE16BA960D7DB4F /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MCSwiftLayoutSample/Pods-MCSwiftLayoutSample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + DDE1EE639E8C959FEBC41FDC /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 249EFE3B1E64FAFE00165E39 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -482,6 +594,7 @@ 2439CC551E665C6B003326FB /* RelativeViewController.swift in Sources */, 2439CC4E1E665C6B003326FB /* MarginsAndPaddingsLeftRightView.swift in Sources */, 2439CC351E665BF6003326FB /* MenuView.swift in Sources */, + 24E6547A1E68F27D00A72A8B /* BothEdgesSnappedView.swift in Sources */, 2439CC4F1E665C6B003326FB /* MarginsAndPaddingsLeftRightViewController.swift in Sources */, 2439CC4B1E665C6B003326FB /* BasicView.swift in Sources */, 2439CC561E665C6B003326FB /* ViewExtensionsPositionningView.swift in Sources */, @@ -489,7 +602,9 @@ 2439CC4C1E665C6B003326FB /* ChainedLayoutView.swift in Sources */, 2439CC501E665C6B003326FB /* MarginsAndPaddingsLeftWidthView.swift in Sources */, 2439CC361E665BF6003326FB /* MenuViewController.swift in Sources */, + 24E6547B1E68F27D00A72A8B /* BothEdgesSnappedViewController.swift in Sources */, 2439CC531E665C6B003326FB /* MultiRelativeViewController.swift in Sources */, + 24E654821E69041B00A72A8B /* Expect.swift in Sources */, 2439CC581E665C6B003326FB /* ValidateConflictsView.swift in Sources */, 2439CC4D1E665C6B003326FB /* ChainedLayoutViewController.swift in Sources */, 2439CC511E665C6B003326FB /* MarginsAndPaddingsLeftWidthViewController.swift in Sources */, @@ -501,7 +616,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 249EFE581E64FAFE00165E39 /* MCSwiftLayoutSampleTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -640,6 +754,7 @@ }; 249EFE681E64FAFE00165E39 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F1ACB0EACBD84B57B50D472D /* Pods-MCSwiftLayoutSample.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -654,6 +769,7 @@ }; 249EFE691E64FAFE00165E39 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F121E291CADD796B007C04BB /* Pods-MCSwiftLayoutSample.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/AppDelegate.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/AppDelegate.swift index 46a1ef39..b1deee38 100644 --- a/MCSwiftLayoutSample/MCSwiftLayoutSample/AppDelegate.swift +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/AppDelegate.swift @@ -19,8 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { window!.backgroundColor = UIColor.white window!.rootViewController = UINavigationController(rootViewController: MenuViewController()) window!.makeKeyAndVisible() - + return true } } - diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/BasicView.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/BasicView.swift index c5358da9..36862624 100644 --- a/MCSwiftLayoutSample/MCSwiftLayoutSample/BasicView.swift +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/BasicView.swift @@ -7,17 +7,28 @@ // import UIKit -class BasicView: UILabel { +class BasicView: UIView { + fileprivate let label = UILabel() + init(text: String? = nil, color: UIColor) { super.init(frame: .zero) - self.text = text - font = UIFont.systemFont(ofSize: 7) - textColor = .white backgroundColor = color + + label.text = text + label.font = UIFont.systemFont(ofSize: 7) + label.textColor = .white + label.sizeToFit() + addSubview(label) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + override func layoutSubviews() { + super.layoutSubviews() + + label.layout.top(0).left(0) + } } diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/Domain/Expect.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/Domain/Expect.swift new file mode 100644 index 00000000..0a9dabf4 --- /dev/null +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/Domain/Expect.swift @@ -0,0 +1,16 @@ +// +// Expect.swift +// MCSwiftLayoutSample +// +// Created by DION, Luc (MTL) on 2017-03-02. +// Copyright © 2017 mcswiftlayyout.mirego.com. All rights reserved. +// + +import UIKit + +func expect(view: UIView, toMatchRect rect: CGRect) { + if view.frame != rect { + print("Doesn't match rect") + } +} + diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/MarginsAndPaddingsLeftRightView.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/MarginsAndPaddingsLeftRightView.swift index f30a2ea1..e9fa92d0 100644 --- a/MCSwiftLayoutSample/MCSwiftLayoutSample/MarginsAndPaddingsLeftRightView.swift +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/MarginsAndPaddingsLeftRightView.swift @@ -8,11 +8,12 @@ import UIKit class MarginsAndPaddingsLeftRightView: UIView { + fileprivate let viewHeight: CGFloat = 40 private let contentScrollView = UIScrollView() private let descriptionLabel = UILabel() - private let noMarginsNoPaddings = BasicView(text: "70x30", color: .black) + private let noMarginsNoPaddings = BasicView(text: "70x40", color: .black) private let noMarginsLeftInsetView = BasicView(text: "LI", color: UIColor.red.withAlphaComponent(1.0)) private let noMarginsRightInsetView = BasicView(text: "RI", color: UIColor.red.withAlphaComponent(0.8)) @@ -32,6 +33,14 @@ class MarginsAndPaddingsLeftRightView: UIView { private let leftRightMarginsLeftInsetView = BasicView(text: "LM-RM LI", color: UIColor.purple.withAlphaComponent(0.8)) private let leftRightMarginsRightInsetView = BasicView(text: "LM-RM RI", color: UIColor.purple.withAlphaComponent(0.6)) private let leftRightMarginsLeftRightInsetView = BasicView(text: "LM-RM LI-RI", color: UIColor.purple.withAlphaComponent(0.4)) + +// TODO + private let noMarginsNoPaddings2 = BasicView(text: "70x30", color: UIColor.black) + private let topMarginView = BasicView(text: "TM", color: UIColor.orange.withAlphaComponent(1)) + private let topMarginTopPaddingView = BasicView(text: "TM TP", color: UIColor.orange.withAlphaComponent(0.8)) + private let topMarginBottomPaddingView = BasicView(text: "TM BP", color: UIColor.orange.withAlphaComponent(0.6)) + private let topMarginTopBottomPaddingView = BasicView(text: "TM TP-BP", color: UIColor.orange.withAlphaComponent(0.4)) + init() { super.init(frame: .zero) @@ -52,7 +61,7 @@ class MarginsAndPaddingsLeftRightView: UIView { addView(noMarginsLeftInsetView) addView(noMarginsRightInsetView) addView(noMarginsLeftRightInsetView) - + // Left margin addView(leftMarginView) addView(leftMarginLeftInsetView) @@ -64,7 +73,7 @@ class MarginsAndPaddingsLeftRightView: UIView { addView(rigthMarginLeftInsetView) addView(rigthMarginRightInsetView) addView(rigthMarginLeftRightInsetView) - + // Left and right margins addView(leftRightMarginsView) addView(leftRightMarginsLeftInsetView) @@ -73,7 +82,7 @@ class MarginsAndPaddingsLeftRightView: UIView { } fileprivate func addView(_ view: BasicView) { - view.layout.height(30).width(70) + view.layout.height(viewHeight).width(70) contentScrollView.addSubview(view) } @@ -93,33 +102,79 @@ class MarginsAndPaddingsLeftRightView: UIView { // No margins let rightPosition: CGFloat = 70 - //var index = 0 - //var nextBottomPosition: CGFloat = descriptionLabel.bottom + 30 - noMarginsNoPaddings.layout.topLeft(descriptionLabel.bottomLeft).bottomRight(x: descriptionLabel.bottom + 30, y: rightPosition) + var topPosition = descriptionLabel.bottom + 10 - noMarginsLeftInsetView.layout.topLeft(noMarginsNoPaddings.bottomLeft).bottomRight(x: noMarginsNoPaddings.bottom + 30, y: rightPosition).leftInset(10) - noMarginsRightInsetView.layout.topLeft(noMarginsLeftInsetView.bottomLeft).bottomRight(x: noMarginsLeftInsetView.bottom + 30, y: rightPosition).rightInset(10) - noMarginsLeftRightInsetView.layout.topLeft(noMarginsRightInsetView.bottomLeft).bottomRight(x: noMarginsRightInsetView.bottom + 30, y: rightPosition).leftInset(10).rightInset(10) -// -// // Left margin -// leftMarginView.layout2.top(noMarginsLeftRightInsetView.bottom + 5).left(leftPosition).width(70).leftMargin(10) -// leftMarginLeftPaddingView.layout2.top(leftMarginView.bottom).left(leftPosition).width(70).leftMargin(10).leftInset(10) -// leftMarginRightInsetView.layout2.top(leftMarginLeftInsetView.bottom).left(leftPosition).width(70).leftMargin(10).RightInset(10) -// leftMarginLeftRightInsetView.layout2.top(leftMarginRightInsetView.bottom).left(leftPosition).width(70).leftMargin(10).leftInset(10).RightInset(10) -// -// // Right margin -// rigthMarginView.layout2.top(leftMarginLeftRightInsetView.bottom + 5).left(leftPosition).width(70).rightMargin(10) -// rigthMarginLeftInsetView.layout2.top(rigthMarginView.bottom).left(leftPosition).width(70).rightMargin(10).leftInset(10) -// rigthMarginRightInsetView.layout2.top(rigthMarginleftInsetView.bottom).left(leftPosition).width(70).rightMargin(10).RightInset(10) -// rigthMarginLeftRightInsetView.layout2.top(rigthMarginRightInsetView.bottom).left(leftPosition).width(70).rightMargin(10).leftInset(10).RightInset(10) -// -// // Left and right margins -// leftRightMarginsView.layout2.top(rigthMarginLeftRightInsetView.bottom + 5).left(leftPosition).width(70).leftMargin(10).rightMargin(10) -// leftRightMarginsleftInsetView.layout2.top(leftRightMarginsView.bottom).left(leftPosition).width(70).leftMargin(10).rightMargin(10).leftInset(10) -// leftRightMarginsRightInsetView.layout2.top(leftRightMarginsleftInsetView.bottom).left(leftPosition).width(70).leftMargin(10).rightMargin(10).RightInset(10) -// leftRightMarginsLeftRightInsetView.layout2.top(leftRightMarginsRightInsetView.bottom).left(leftPosition).width(70).leftMargin(10).rightMargin(10).leftInset(10).RightInset(10) - - contentScrollView.contentSize = CGSize(width: width, height: leftRightMarginsLeftRightInsetView.bottom) + noMarginsNoPaddings.layout.top(topPosition).left(0).bottom(topPosition + viewHeight).right(rightPosition) + expect(view: noMarginsNoPaddings, toMatchRect: CGRect(x: 0, y: 63, width: 70, height: 40)) + topPosition += viewHeight + + noMarginsLeftInsetView.layout.top(topPosition).left(0).bottom(topPosition + viewHeight).right(rightPosition).leftInset(10) + expect(view: noMarginsLeftInsetView, toMatchRect: CGRect(x: 10, y: 103, width: 60, height: 40)) + topPosition += viewHeight + + noMarginsRightInsetView.layout.top(topPosition).left(0).bottom(topPosition + viewHeight).right(rightPosition).rightInset(10) + expect(view: noMarginsRightInsetView, toMatchRect: CGRect(x: 0, y: 143, width: 60, height: 40)) + topPosition += viewHeight + + noMarginsLeftRightInsetView.layout.top(topPosition).left(0).bottom(topPosition + viewHeight).right(rightPosition).leftInset(10).rightInset(10) + expect(view: noMarginsLeftRightInsetView, toMatchRect: CGRect(x: 10, y: 183, width: 50, height: 40)) + topPosition += viewHeight + + // Left margin + topPosition += 5 + leftMarginView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10) + expect(view: leftMarginView, toMatchRect: CGRect(x: 10, y: 228, width: 60, height: 40)) + topPosition += viewHeight + + leftMarginLeftInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10).leftInset(10) + expect(view: leftMarginLeftInsetView, toMatchRect: CGRect(x: 20, y: 268, width: 50, height: 40)) + topPosition += viewHeight + + leftMarginRightInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10).rightInset(10) + expect(view: leftMarginRightInsetView, toMatchRect: CGRect(x: 10, y: 308, width: 50, height: 40)) + topPosition += viewHeight + + leftMarginLeftRightInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10).leftInset(10).rightInset(10) + expect(view: leftMarginLeftRightInsetView, toMatchRect: CGRect(x: 20, y: 348, width: 40, height: 40)) + topPosition += viewHeight + + // Right margin + topPosition += 5 + rigthMarginView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).rightMargin(10) + expect(view: rigthMarginView, toMatchRect: CGRect(x: 0, y: 393, width: 60, height: 40)) + topPosition += viewHeight + + rigthMarginLeftInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).rightMargin(10).leftInset(10) + expect(view: rigthMarginLeftInsetView, toMatchRect: CGRect(x: 10, y: 433, width: 50, height: 40)) + topPosition += viewHeight + + rigthMarginRightInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).rightMargin(10).rightInset(10) + expect(view: rigthMarginRightInsetView, toMatchRect: CGRect(x: 0, y: 473, width: 50, height: 40)) + topPosition += viewHeight + + rigthMarginLeftRightInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).rightMargin(10).leftInset(10).rightInset(10) + expect(view: rigthMarginLeftRightInsetView, toMatchRect: CGRect(x: 10, y: 513, width: 40, height: 40)) + topPosition += viewHeight + + // Left and right margins + topPosition += 5 + leftRightMarginsView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10).rightMargin(10) + expect(view: leftRightMarginsView, toMatchRect: CGRect(x: 10, y: 558, width: 50, height: 40)) + topPosition += viewHeight + + leftRightMarginsLeftInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10).rightMargin(10).leftInset(10) + expect(view: leftRightMarginsLeftInsetView, toMatchRect: CGRect(x: 20, y: 598, width: 40, height: 40)) + topPosition += viewHeight + + leftRightMarginsRightInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10).rightMargin(10).rightInset(10) + expect(view: leftRightMarginsRightInsetView, toMatchRect: CGRect(x: 10, y: 638, width: 40, height: 40)) + topPosition += viewHeight + + leftRightMarginsLeftRightInsetView.layout.top(topPosition).left(leftPosition).bottom(topPosition + viewHeight).right(rightPosition).leftMargin(10).rightMargin(10).leftInset(10).rightInset(10) + expect(view: leftRightMarginsLeftRightInsetView, toMatchRect: CGRect(x: 20, y: 678, width: 30, height: 40)) + topPosition += viewHeight + + contentScrollView.contentSize = CGSize(width: width, height: topPosition) contentScrollView.contentInset = UIEdgeInsets.zero } } diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/MenuViewController.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/MenuViewController.swift index 4dcc1c89..258d0497 100644 --- a/MCSwiftLayoutSample/MCSwiftLayoutSample/MenuViewController.swift +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/MenuViewController.swift @@ -15,6 +15,7 @@ enum Page: Int { case chainedLayout + case bothEdgesSnapped case marginsAndPaddingLeftWidth case marginsAndPaddingLeftRight @@ -27,8 +28,9 @@ enum Page: Int { case .relativePositions: return "Test Relative" case .multiRelativePositions: return "Test Multiple Relatives" case .chainedLayout: return "Chained Layout" - case .marginsAndPaddingLeftWidth: return "Test margings and paddings - Left+Width" - case .marginsAndPaddingLeftRight: return "Test margings and paddings - Left+Right" + case .bothEdgesSnapped: return "NOT USED YET" + case .marginsAndPaddingLeftWidth: return "topLeft & width - Test margings and paddings" + case .marginsAndPaddingLeftRight: return "topLeft & bottomRight - Test margings and paddings" case .validateConflicts: return "Validate properties conflicts" case .count: return "Unknown" } @@ -68,6 +70,8 @@ extension MenuViewController: MenuViewDelegate { controller = MultiRelativeViewController() case .chainedLayout: controller = ChainedLayoutViewController() + case .bothEdgesSnapped: + controller = BothEdgesSnappedViewController() case .marginsAndPaddingLeftWidth: controller = MarginsAndPaddingsLeftWidthViewController() case .marginsAndPaddingLeftRight: diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/MultiRelativeView.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/MultiRelativeView.swift index cab31b31..8fbdf63c 100644 --- a/MCSwiftLayoutSample/MCSwiftLayoutSample/MultiRelativeView.swift +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/MultiRelativeView.swift @@ -32,7 +32,7 @@ class MultiRelativeView: UIView { override func layoutSubviews() { super.layoutSubviews() - view1.layout.topLeft(x: 10, y: 64).width(100).height(100) + view1.layout.top(64).left(10).width(100).height(100) view2.layout.right(of: view1, aligned: .top).leftMargin(150).width(100).height(100) view.layout.right(of: view1, aligned: .top).left(of: view2).height(75).leftInset(10).rightInset(10) diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/Test/BothEdgesSnapped/BothEdgesSnappedView.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/Test/BothEdgesSnapped/BothEdgesSnappedView.swift new file mode 100644 index 00000000..b38dd79e --- /dev/null +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/Test/BothEdgesSnapped/BothEdgesSnappedView.swift @@ -0,0 +1,167 @@ +// +// BothEdgesSnappedView.swift +// MCLayoutExample +// +// Created by DION, Luc (MTL) on 2017-02-21. +// Copyright (c) 2017 Mirego. All rights reserved. +// +import UIKit + +class BothEdgesSnappedView: UIView { + private let contentScrollView = UIScrollView() + + private let descriptionLabel = UILabel() + + private let noMarginsNoPaddings = BasicView(text: "70x30", color: .black) + +// private let noMarginsLeftInsetView = BasicView(text: "LI", color: UIColor.red.withAlphaComponent(1.0)) +// private let noMarginsRightInsetView = BasicView(text: "RI", color: UIColor.red.withAlphaComponent(0.8)) +// private let noMarginsLeftRightInsetView = BasicView(text: "LI-RI", color: UIColor.red.withAlphaComponent(0.6)) +// +// private let leftMarginView = BasicView(text: "LM", color: UIColor.blue.withAlphaComponent(1.0)) +// private let leftMarginLeftInsetView = BasicView(text: "LM LI", color: UIColor.blue.withAlphaComponent(0.8)) +// private let leftMarginRightInsetView = BasicView(text: "LM RI", color: UIColor.blue.withAlphaComponent(0.6)) +// private let leftMarginLeftRightInsetView = BasicView(text: "LM LI-RI", color: UIColor.blue.withAlphaComponent(0.4)) +// +// private let rigthMarginView = BasicView(text: "RM", color: UIColor.green.withAlphaComponent(1)) +// private let rigthMarginLeftInsetView = BasicView(text: "RM LI", color: UIColor.green.withAlphaComponent(0.8)) +// private let rigthMarginRightInsetView = BasicView(text: "RM RI", color: UIColor.green.withAlphaComponent(0.6)) +// private let rigthMarginLeftRightInsetView = BasicView(text: "RM LI-RI", color: UIColor.green.withAlphaComponent(0.4)) +// +// private let leftRightMarginsView = BasicView(text: "LM-RM", color: UIColor.purple.withAlphaComponent(1)) +// private let leftRightMarginsLeftInsetView = BasicView(text: "LM-RM LI", color: UIColor.purple.withAlphaComponent(0.8)) +// private let leftRightMarginsRightInsetView = BasicView(text: "LM-RM RI", color: UIColor.purple.withAlphaComponent(0.6)) +// private let leftRightMarginsLeftRightInsetView = BasicView(text: "LM-RM LI-RI", color: UIColor.purple.withAlphaComponent(0.4)) + + var childLevel1: UIView! + var anotherChildLevel1: UIView! + var childLevel2: UIView! + var anotherChildLevel2: UIView! + + init() { + super.init(frame: .zero) + + backgroundColor = .white + + childLevel1 = UIView() + childLevel1.backgroundColor = UIColor.red.withAlphaComponent(0.5) + addSubview(childLevel1) + + anotherChildLevel1 = UIView() + anotherChildLevel1.backgroundColor = UIColor.blue.withAlphaComponent(0.5) + addSubview(anotherChildLevel1) + + childLevel2 = UIView() + childLevel1.backgroundColor = UIColor.green.withAlphaComponent(0.5) + childLevel1.addSubview(childLevel2) + + anotherChildLevel2 = UIView() + anotherChildLevel2.backgroundColor = UIColor.yellow.withAlphaComponent(0.5) + anotherChildLevel1.addSubview(anotherChildLevel2) + +// contentScrollView.backgroundColor = .yellow +// addSubview(contentScrollView) +// +// descriptionLabel.text = "In this test the topLeft coordinates and the bottomRight have been set.\nMargins and Insets always have a value of 10\nL=Left, R=Right, M=Margin, I=Inset" +// descriptionLabel.numberOfLines = 0 +// descriptionLabel.font = UIFont.systemFont(ofSize: 12) +// contentScrollView.addSubview(descriptionLabel) +// +// addView(noMarginsNoPaddings) +// +// // No margins +// addView(noMarginsLeftInsetView) +// addView(noMarginsRightInsetView) +// addView(noMarginsLeftRightInsetView) +// +// // Left margin +// addView(leftMarginView) +// addView(leftMarginLeftInsetView) +// addView(leftMarginRightInsetView) +// addView(leftMarginLeftRightInsetView) +// +// // Right margin +// addView(rigthMarginView) +// addView(rigthMarginLeftInsetView) +// addView(rigthMarginRightInsetView) +// addView(rigthMarginLeftRightInsetView) +// +// // Left and right margins +// addView(leftRightMarginsView) +// addView(leftRightMarginsLeftInsetView) +// addView(leftRightMarginsRightInsetView) +// addView(leftRightMarginsLeftRightInsetView) + } + + fileprivate func addView(_ view: BasicView) { + view.layout.height(30).width(70) + contentScrollView.addSubview(view) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func layoutSubviews() { + super.layoutSubviews() + +// childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) +// childLevel2.frame = CGRect(x: 10, y: 20, width: 20, height: 40) +// anotherChildLevel1.frame = CGRect(x: 10, y: 10, width: 30, height: 50) +// childLevel2.layout.centers(of: anotherChildLevel1) + +// childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) +// childLevel2.frame = CGRect(x: 10, y: 20, width: 20, height: 40) +// anotherChildLevel1.frame = CGRect(x: 10, y: 10, width: 30, height: 50) +// +// anotherChildLevel1.layout.centers(of: childLevel2) + + childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) + childLevel2.frame = CGRect(x: 10, y: 20, width: 30, height: 40) + anotherChildLevel1.frame = CGRect(x: 10, y: 80, width: 30, height: 50) + anotherChildLevel2.frame = CGRect(x: 0, y: 0, width: 20, height: 10) + + + anotherChildLevel2.layout.centers(of: childLevel2) + + print(anotherChildLevel2.frame) + +// let leftPosition: CGFloat = 0 +// +// contentScrollView.layout.topLeft(CGPoint(x: 0, y: 0)).width(width).height(height).topInset(64) +// +// descriptionLabel.size = descriptionLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude)) +// descriptionLabel.layout.topLeft(CGPoint(x: leftPosition, y: 10)) +// +// // No margins +// let rightPosition: CGFloat = 70 +// //var index = 0 +// //var nextBottomPosition: CGFloat = descriptionLabel.bottom + 30 +// noMarginsNoPaddings.layout.topLeft(descriptionLabel.bottomLeft).bottomRight(x: descriptionLabel.bottom + 30, y: rightPosition) +// +// noMarginsLeftInsetView.layout.topLeft(noMarginsNoPaddings.bottomLeft).bottomRight(x: noMarginsNoPaddings.bottom + 30, y: rightPosition).leftInset(10) +// noMarginsRightInsetView.layout.topLeft(noMarginsLeftInsetView.bottomLeft).bottomRight(x: noMarginsLeftInsetView.bottom + 30, y: rightPosition).rightInset(10) +// noMarginsLeftRightInsetView.layout.topLeft(noMarginsRightInsetView.bottomLeft).bottomRight(x: noMarginsRightInsetView.bottom + 30, y: rightPosition).leftInset(10).rightInset(10) +// +// // Left margin +// leftMarginView.layout2.top(noMarginsLeftRightInsetView.bottom + 5).left(leftPosition).width(70).leftMargin(10) +// leftMarginLeftPaddingView.layout2.top(leftMarginView.bottom).left(leftPosition).width(70).leftMargin(10).leftInset(10) +// leftMarginRightInsetView.layout2.top(leftMarginLeftInsetView.bottom).left(leftPosition).width(70).leftMargin(10).RightInset(10) +// leftMarginLeftRightInsetView.layout2.top(leftMarginRightInsetView.bottom).left(leftPosition).width(70).leftMargin(10).leftInset(10).RightInset(10) +// +// // Right margin +// rigthMarginView.layout2.top(leftMarginLeftRightInsetView.bottom + 5).left(leftPosition).width(70).rightMargin(10) +// rigthMarginLeftInsetView.layout2.top(rigthMarginView.bottom).left(leftPosition).width(70).rightMargin(10).leftInset(10) +// rigthMarginRightInsetView.layout2.top(rigthMarginleftInsetView.bottom).left(leftPosition).width(70).rightMargin(10).RightInset(10) +// rigthMarginLeftRightInsetView.layout2.top(rigthMarginRightInsetView.bottom).left(leftPosition).width(70).rightMargin(10).leftInset(10).RightInset(10) +// +// // Left and right margins +// leftRightMarginsView.layout2.top(rigthMarginLeftRightInsetView.bottom + 5).left(leftPosition).width(70).leftMargin(10).rightMargin(10) +// leftRightMarginsleftInsetView.layout2.top(leftRightMarginsView.bottom).left(leftPosition).width(70).leftMargin(10).rightMargin(10).leftInset(10) +// leftRightMarginsRightInsetView.layout2.top(leftRightMarginsleftInsetView.bottom).left(leftPosition).width(70).leftMargin(10).rightMargin(10).RightInset(10) +// leftRightMarginsLeftRightInsetView.layout2.top(leftRightMarginsRightInsetView.bottom).left(leftPosition).width(70).leftMargin(10).rightMargin(10).leftInset(10).RightInset(10) + +// contentScrollView.contentSize = CGSize(width: width, height: leftRightMarginsLeftRightInsetView.bottom) +// contentScrollView.contentInset = UIEdgeInsets.zero + } +} diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/Test/BothEdgesSnapped/BothEdgesSnappedViewController.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/Test/BothEdgesSnapped/BothEdgesSnappedViewController.swift new file mode 100644 index 00000000..4fef2825 --- /dev/null +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/Test/BothEdgesSnapped/BothEdgesSnappedViewController.swift @@ -0,0 +1,32 @@ +// +// BothEdgesSnappedViewController.swift +// MCLayoutExample +// +// Created by DION, Luc (MTL) on 2017-02-21. +// Copyright (c) 2017 Mirego. All rights reserved. +// +import UIKit + +class BothEdgesSnappedViewController: UIViewController { + fileprivate var mainView: BothEdgesSnappedView { + return self.view as! BothEdgesSnappedView + } + + init() { + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = BothEdgesSnappedView() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(true) + + navigationController?.isNavigationBarHidden = true + } +} diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSample/ValidateConflictsView.swift b/MCSwiftLayoutSample/MCSwiftLayoutSample/ValidateConflictsView.swift index 2a9688be..3f38be5e 100644 --- a/MCSwiftLayoutSample/MCSwiftLayoutSample/ValidateConflictsView.swift +++ b/MCSwiftLayoutSample/MCSwiftLayoutSample/ValidateConflictsView.swift @@ -32,6 +32,6 @@ class ValidateConflictsView: UIView { override func layoutSubviews() { super.layoutSubviews() - topLeftView.layout.right(10).width(20).topLeft(x: 10, y: 10).left(10) + topLeftView.layout.right(10).width(20).top(10).left(10).left(10) } } diff --git a/MCSwiftLayoutSample/MCSwiftLayoutSampleTests/MCSwiftLayoutSampleTests.swift b/MCSwiftLayoutSample/MCSwiftLayoutSampleTests/MCSwiftLayoutSampleTests.swift deleted file mode 100644 index b902d786..00000000 --- a/MCSwiftLayoutSample/MCSwiftLayoutSampleTests/MCSwiftLayoutSampleTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// MCSwiftLayoutSampleTests.swift -// MCSwiftLayoutSampleTests -// -// Created by DION, Luc (MTL) on 2017-02-27. -// Copyright © 2017 mcswiftlayyout.mirego.com. All rights reserved. -// - -import XCTest -@testable import MCSwiftLayoutSample - -class MCSwiftLayoutSampleTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testExample() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/MCSwiftLayoutSample/Podfile b/MCSwiftLayoutSample/Podfile new file mode 100644 index 00000000..2879cfc3 --- /dev/null +++ b/MCSwiftLayoutSample/Podfile @@ -0,0 +1,18 @@ +use_frameworks! + +workspace 'path/to/Workspace.xcworkspace' + +target 'MCSwiftLayoutSample' do + project 'MCSwiftLayoutSample.xcodeproj' + #pod 'YogaKit', '~> 1.1' + + # Debug only + pod 'Reveal-SDK', :configurations => ['Debug'] + pod 'SwiftLint' +end + +target 'MCSwiftLayoutTests' do + project '../MCSwiftLayout.xcodeproj' + pod 'Quick' + pod 'Nimble' +end diff --git a/MCSwiftLayoutSample/Podfile.lock b/MCSwiftLayoutSample/Podfile.lock new file mode 100644 index 00000000..fad2da64 --- /dev/null +++ b/MCSwiftLayoutSample/Podfile.lock @@ -0,0 +1,21 @@ +PODS: + - Nimble (6.0.1) + - Quick (1.1.0) + - Reveal-SDK (7) + - SwiftLint (0.16.1) + +DEPENDENCIES: + - Nimble + - Quick + - Reveal-SDK + - SwiftLint + +SPEC CHECKSUMS: + Nimble: 1527fd1bd2b4cf0636251a36bc8ab37e81da8347 + Quick: dafc587e21eed9f4cab3249b9f9015b0b7a7f71d + Reveal-SDK: 564657bc66c93d2718b1c0121cdebe99d354ddab + SwiftLint: b8b683208cc09640898f16318a7a452274e91f61 + +PODFILE CHECKSUM: 2def317a86457403b59cecf0cfc91047198c8e4d + +COCOAPODS: 1.1.1 diff --git a/MCSwiftLayoutTests/BasicTests.swift b/MCSwiftLayoutTests/BasicTests.swift new file mode 100644 index 00000000..93dc2aa7 --- /dev/null +++ b/MCSwiftLayoutTests/BasicTests.swift @@ -0,0 +1,119 @@ +// +// BasicTests.swift +// MCSwiftLayout +// +// Created by DION, Luc (MTL) on 2017-03-05. +// Copyright © 2017 mcswiftlayyout.mirego.com. All rights reserved. +// +import Quick +import Nimble + +class BasicTestsSpec: QuickSpec { + override func spec() { + var viewController: UIViewController! + var rootView: UIView! + + var childLevel1: UIView! + var childLevel2: UIView! + + var anotherChildLevel1: UIView! + var anotherChildLevel2: UIView! + + /* + root + | + - childLevel1 + | | + | - childLevel2 + | + - anotherChildLevel1 + | + - anotherChildLevel2 + */ + + beforeEach { + viewController = UIViewController() + + rootView = UIView() + rootView.frame = CGRect(x: 0, y: 0, width: 100, height: 100) + viewController.view.addSubview(rootView) + + childLevel1 = UIView() + rootView.addSubview(childLevel1) + + childLevel2 = UIView() + childLevel1.addSubview(childLevel2) + + anotherChildLevel1 = UIView() + rootView.addSubview(anotherChildLevel1) + + anotherChildLevel2 = UIView() + anotherChildLevel1.addSubview(anotherChildLevel2) + } + + describe("the result of the centers(of: UIView) method") { + it("should warns that the view is not added to any view") { + let unAttachedView = UIView(frame: CGRect(x: 10, y: 10, width: 10, height: 10)) + unAttachedView.layout.centers(of: rootView) + + expect(unAttachedView.frame).to(equal(CGRect(x: 10, y: 10, width: 10, height: 10))) + } + + it("should centers the childLevel1 in the center of its parent") { + childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) + childLevel1.layout.centers(of: rootView) + + expect(childLevel1.frame).to(equal(CGRect(x: 30, y: 20, width: 40, height: 60))) + } + + it("should centers the childLevel1 in the center of its sibling anotherChildLevel1") { + anotherChildLevel1.frame = CGRect(x: 10, y: 10, width: 30, height: 50) + + childLevel1.frame = CGRect(x: 10, y: 10, width: 40, height: 60) + childLevel1.layout.centers(of: anotherChildLevel1) + + expect(childLevel1.frame).to(equal(CGRect(x: 5, y: 5, width: 40, height: 60))) + } + + it("should centers the anotherChildLevel1 in the center of its sibling (childLevel1) sub child (childLevel2)") { + childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) + childLevel2.frame = CGRect(x: 10, y: 20, width: 20, height: 40) + anotherChildLevel1.frame = CGRect(x: 10, y: 10, width: 30, height: 50) + + anotherChildLevel1.layout.centers(of: childLevel2) + + expect(anotherChildLevel1.frame).to(equal(CGRect(x: 15, y: 35, width: 30, height: 50))) + } + + it("should centers the childLevel2 in the center of anotherChildLevel1") { + childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) + childLevel2.frame = CGRect(x: 10, y: 20, width: 20, height: 40) + anotherChildLevel1.frame = CGRect(x: 10, y: 10, width: 30, height: 50) + + childLevel2.layout.centers(of: anotherChildLevel1) + + expect(childLevel2.frame).to(equal(CGRect(x: 5, y: -5, width: 20, height: 40))) + } + + it("should centers the anotherChildLevel2 in the center of its parent's sibling (childLevel1) sub child (childLevel2)") { + childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) + childLevel2.frame = CGRect(x: 10, y: 20, width: 30, height: 40) + anotherChildLevel1.frame = CGRect(x: 10, y: 80, width: 30, height: 50) + anotherChildLevel2.frame = CGRect(x: 0, y: 0, width: 20, height: 10) + + anotherChildLevel2.layout.centers(of: childLevel2) + expect(anotherChildLevel2.frame).to(equal(CGRect(x: 15, y: -25, width: 20, height: 10))) + } + } + + describe("the result of the centers() method") { + it("should centers the childLevel1 in the center of its parent") { + childLevel1.frame = CGRect(x: 10, y: 20, width: 40, height: 60) + + childLevel1.layout.centers() + + expect(childLevel1.frame).to(equal(CGRect(x: 30, y: 20, width: 40, height: 60))) + } + } + } +} diff --git a/MCSwiftLayoutTests/MCSwiftLayoutTests.swift b/MCSwiftLayoutTests/MCSwiftLayoutTests.swift index ccebb160..5d8231e9 100644 --- a/MCSwiftLayoutTests/MCSwiftLayoutTests.swift +++ b/MCSwiftLayoutTests/MCSwiftLayoutTests.swift @@ -10,20 +10,25 @@ import XCTest @testable import MCSwiftLayout class MCSwiftLayoutTests: XCTestCase { + var viewController: UIViewController! + var rootView: UIView! override func setUp() { super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() + + viewController = UIViewController() + + rootView = UIView() + rootView.frame = CGRect(x: 0, y: 0, width: 100, height: 100) + viewController.view.addSubview(rootView) } func testExample() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. + let child1 = UIView() + rootView.addSubview(child1) + + child1.layout.centers(of: rootView) + print("child1.frame: \(child1.frame)") } func testPerformanceExample() { diff --git a/Podfile b/Podfile new file mode 100644 index 00000000..8adc1b88 --- /dev/null +++ b/Podfile @@ -0,0 +1,6 @@ +use_frameworks! + +target 'MCSwiftLayoutTests' do + pod 'Quick' + pod 'Nimble' +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 00000000..badf7522 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,15 @@ +PODS: + - Nimble (6.0.1) + - Quick (1.1.0) + +DEPENDENCIES: + - Nimble + - Quick + +SPEC CHECKSUMS: + Nimble: 1527fd1bd2b4cf0636251a36bc8ab37e81da8347 + Quick: dafc587e21eed9f4cab3249b9f9015b0b7a7f71d + +PODFILE CHECKSUM: bf792fd392130a7a74fbcd6812b5af2131610dbd + +COCOAPODS: 1.1.1 diff --git a/scripts/synx.sh b/scripts/synx.sh new file mode 100755 index 00000000..20625b76 --- /dev/null +++ b/scripts/synx.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +synx --no-sort-by-name PAP.xcodeproj + +echo +echo +echo ===================================================== +echo List of empty forlders +echo ===================================================== +find ./PAP -depth -type d -empty +echo end \ No newline at end of file