diff --git a/ManualLayout.xcodeproj/project.pbxproj b/ManualLayout.xcodeproj/project.pbxproj index dbc75f6..8ef7951 100644 --- a/ManualLayout.xcodeproj/project.pbxproj +++ b/ManualLayout.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ /* Begin PBXBuildFile section */ 5F67BC0A1A9D43FE00347483 /* FastAccessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F67BC091A9D43FE00347483 /* FastAccessTests.swift */; }; 5F67BC3F1A9E970300347483 /* UIViewController+LayoutGuides.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F67BC3E1A9E970300347483 /* UIViewController+LayoutGuides.swift */; }; + 5F67BC4C1A9FAB4B00347483 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F67BC4B1A9FAB4B00347483 /* Operators.swift */; }; + 5F67BC4E1A9FB1A600347483 /* OperatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F67BC4D1A9FB1A600347483 /* OperatorTests.swift */; }; + 5F67BC501A9FDDD900347483 /* HelperFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F67BC4F1A9FDDD900347483 /* HelperFunctions.swift */; }; + 5F67BC521A9FE35C00347483 /* HelperFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F67BC511A9FE35C00347483 /* HelperFunctionTests.swift */; }; 5F875C581A9BC8BF003CACDD /* Enums.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F875C571A9BC8BF003CACDD /* Enums.swift */; }; 5F875C5B1A9BCBB2003CACDD /* UIView+ManualLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F875C5A1A9BCBB2003CACDD /* UIView+ManualLayout.swift */; }; 5F875C5F1A9BD55D003CACDD /* ManualLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F875C5E1A9BD55D003CACDD /* ManualLayout.swift */; }; @@ -34,6 +38,10 @@ /* Begin PBXFileReference section */ 5F67BC091A9D43FE00347483 /* FastAccessTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FastAccessTests.swift; sourceTree = ""; }; 5F67BC3E1A9E970300347483 /* UIViewController+LayoutGuides.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+LayoutGuides.swift"; sourceTree = ""; }; + 5F67BC4B1A9FAB4B00347483 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; + 5F67BC4D1A9FB1A600347483 /* OperatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorTests.swift; sourceTree = ""; }; + 5F67BC4F1A9FDDD900347483 /* HelperFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HelperFunctions.swift; sourceTree = ""; }; + 5F67BC511A9FE35C00347483 /* HelperFunctionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HelperFunctionTests.swift; sourceTree = ""; }; 5F875C571A9BC8BF003CACDD /* Enums.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Enums.swift; sourceTree = ""; }; 5F875C5A1A9BCBB2003CACDD /* UIView+ManualLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+ManualLayout.swift"; sourceTree = ""; }; 5F875C5E1A9BD55D003CACDD /* ManualLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManualLayout.swift; sourceTree = ""; }; @@ -91,6 +99,8 @@ children = ( 5FB4CBEE1A9BBE7500C2FB4F /* ManualLayout.h */, 5F875C571A9BC8BF003CACDD /* Enums.swift */, + 5F67BC4B1A9FAB4B00347483 /* Operators.swift */, + 5F67BC4F1A9FDDD900347483 /* HelperFunctions.swift */, 5F875C5E1A9BD55D003CACDD /* ManualLayout.swift */, 5F875C681A9BE99F003CACDD /* CALayer+FastAccess.swift */, 5F875C6E1A9BFE01003CACDD /* CALayer+ManualLayout.swift */, @@ -113,6 +123,8 @@ 5FB4CBF81A9BBE7500C2FB4F /* ManualLayoutTests */ = { isa = PBXGroup; children = ( + 5F67BC4D1A9FB1A600347483 /* OperatorTests.swift */, + 5F67BC511A9FE35C00347483 /* HelperFunctionTests.swift */, 5F67BC091A9D43FE00347483 /* FastAccessTests.swift */, 5FB4CBFB1A9BBE7500C2FB4F /* ManualLayoutTests.swift */, 5F875C641A9BE2D3003CACDD /* UIViewManualLayoutTests.swift */, @@ -238,9 +250,11 @@ files = ( 5F875C691A9BE99F003CACDD /* CALayer+FastAccess.swift in Sources */, 5F67BC3F1A9E970300347483 /* UIViewController+LayoutGuides.swift in Sources */, + 5F67BC501A9FDDD900347483 /* HelperFunctions.swift in Sources */, 5F875C5F1A9BD55D003CACDD /* ManualLayout.swift in Sources */, 5F875C5B1A9BCBB2003CACDD /* UIView+ManualLayout.swift in Sources */, 5F875C6D1A9BFC7E003CACDD /* UIView+FastAccess.swift in Sources */, + 5F67BC4C1A9FAB4B00347483 /* Operators.swift in Sources */, 5F875C581A9BC8BF003CACDD /* Enums.swift in Sources */, 5F875C6F1A9BFE01003CACDD /* CALayer+ManualLayout.swift in Sources */, ); @@ -250,7 +264,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5F67BC521A9FE35C00347483 /* HelperFunctionTests.swift in Sources */, 5F875C651A9BE2D3003CACDD /* UIViewManualLayoutTests.swift in Sources */, + 5F67BC4E1A9FB1A600347483 /* OperatorTests.swift in Sources */, 5F67BC0A1A9D43FE00347483 /* FastAccessTests.swift in Sources */, 5FB4CBFC1A9BBE7500C2FB4F /* ManualLayoutTests.swift in Sources */, ); diff --git a/ManualLayout/HelperFunctions.swift b/ManualLayout/HelperFunctions.swift new file mode 100644 index 0000000..0a92e89 --- /dev/null +++ b/ManualLayout/HelperFunctions.swift @@ -0,0 +1,77 @@ +// +// Functions.swift +// ManualLayout +// +// Created by Baris Sencan on 26/02/15. +// Copyright (c) 2015 Baris Sencan. All rights reserved. +// + +import UIKit + +//MARK: - Insetting + +public func inset(view: UIView, amount: CGFloat) -> CGRect { + return inset(view.frame, amount) +} + +public func inset(layer: CALayer, amount: CGFloat) -> CGRect { + return inset(layer.frame, amount) +} + +public func inset(rect: CGRect, amount: CGFloat) -> CGRect { + return CGRectInset(rect, amount, amount) +} + +public func inset(view: UIView, dx: CGFloat, dy: CGFloat) -> CGRect { + return inset(view.frame, dx, dy) +} + +public func inset(layer: CALayer, dx: CGFloat, dy: CGFloat) -> CGRect { + return inset(layer.frame, dx, dy) +} + +public func inset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect { + return CGRectInset(rect, dx, dy) +} + +public func inset(view: UIView, top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> CGRect { + return inset(view.frame, top, left, bottom, right) +} + +public func inset(layer: CALayer, top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> CGRect { + return inset(layer.frame, top, left, bottom, right) +} + +public func inset(rect: CGRect, top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> CGRect { + return CGRect( + x: rect.origin.x + left, + y: rect.origin.y + top, + width: rect.size.width - left - right, + height: rect.size.height - top - bottom) +} + +// MARK: - Offsetting + +public func offset(view: UIView, amount: CGFloat) -> CGRect { + return offset(view.frame, amount) +} + +public func offset(layer: CALayer, amount: CGFloat) -> CGRect { + return offset(layer.frame, amount) +} + +public func offset(rect: CGRect, amount: CGFloat) -> CGRect { + return CGRectOffset(rect, amount, amount) +} + +public func offset(view: UIView, dx: CGFloat, dy: CGFloat) -> CGRect { + return offset(view.frame, dx, dy) +} + +public func offset(layer: CALayer, dx: CGFloat, dy: CGFloat) -> CGRect { + return offset(layer.frame, dx, dy) +} + +public func offset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect { + return CGRectOffset(rect, dx, dy) +} diff --git a/ManualLayout/Info.plist b/ManualLayout/Info.plist index ba03b3a..f953bfd 100644 --- a/ManualLayout/Info.plist +++ b/ManualLayout/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.2.1 + 0.3.0 CFBundleSignature ???? CFBundleVersion diff --git a/ManualLayout/Operators.swift b/ManualLayout/Operators.swift new file mode 100644 index 0000000..77107a2 --- /dev/null +++ b/ManualLayout/Operators.swift @@ -0,0 +1,26 @@ +// +// OperatorOverloads.swift +// ManualLayout +// +// Created by Baris Sencan on 26/02/15. +// Copyright (c) 2015 Baris Sencan. All rights reserved. +// + +import UIKit + +infix operator =~ { associativity right precedence 150 } + +public func =~ (inout point: CGPoint, pointTuple: (CGFloat, CGFloat)) -> CGPoint { + point = CGPoint(x: pointTuple.0, y: pointTuple.1) + return point +} + +public func =~ (inout size: CGSize, sizeTuple: (CGFloat, CGFloat)) -> CGSize { + size = CGSize(width: sizeTuple.0, height: sizeTuple.1) + return size +} + +public func =~ (inout rect: CGRect, rectTuple: (CGFloat, CGFloat, CGFloat, CGFloat)) -> CGRect { + rect = CGRect(x: rectTuple.0, y: rectTuple.1, width: rectTuple.2, height: rectTuple.3) + return rect +} diff --git a/ManualLayout/UIViewController+LayoutGuides.swift b/ManualLayout/UIViewController+LayoutGuides.swift index 20a4b9b..128e4f9 100644 --- a/ManualLayout/UIViewController+LayoutGuides.swift +++ b/ManualLayout/UIViewController+LayoutGuides.swift @@ -14,7 +14,15 @@ public extension UIViewController { return topLayoutGuide.length } + public var right: CGFloat { // For convenience. + return view.width + } + public var bottom: CGFloat { return view.height - bottomLayoutGuide.length } + + public var left: CGFloat { // For convenience. + return 0 + } } diff --git a/ManualLayoutTests/HelperFunctionTests.swift b/ManualLayoutTests/HelperFunctionTests.swift new file mode 100644 index 0000000..64b0330 --- /dev/null +++ b/ManualLayoutTests/HelperFunctionTests.swift @@ -0,0 +1,60 @@ +// +// HelperFunctionTests.swift +// ManualLayout +// +// Created by Baris Sencan on 26/02/15. +// Copyright (c) 2015 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import ManualLayout + +class HelperFunctionTests: XCTestCase { + var view = UIView(frame: CGRectZero) + let defaultFrame = CGRect(x: 1, y: 3, width: 6, height: 8) + + override func setUp() { + view.frame = defaultFrame + } + + func testInsetSingleArg() { + view.frame = inset(view, 1) + XCTAssertEqual( + view.frame, + CGRect(x: 2, y: 4, width: 4, height: 6), + "insetting with amount should inset correctly") + } + + func testInsetTwoArg() { + view.frame = inset(view, 1, 2) + XCTAssertEqual( + view.frame, + CGRect(x: 2, y: 5, width: 4, height: 4), + "insetting with dx and dy should inset correctly") + } + + func testInsetFourArg() { + view.frame = inset(view, 1, 2, 3, 4) + XCTAssertEqual( + view.frame, + CGRect(x: 3, y: 4, width: 0, height: 4), + "insetting with four arguments should inset correctly") + } + + func testOffsetSingleArg() { + view.frame = offset(view, 1) + XCTAssertEqual( + view.frame, + CGRect(x: 2, y: 4, width: 6, height: 8), + "offsetting with amount should offset correctly") + } + + func testOffsetTwoArg() { + view.frame = offset(view, 1, 2) + XCTAssertEqual( + view.frame, + CGRect(x: 2, y: 5, width: 6, height: 8), + "offsetting with dx and dy should offset correctly") + } +} \ No newline at end of file diff --git a/ManualLayoutTests/OperatorTests.swift b/ManualLayoutTests/OperatorTests.swift new file mode 100644 index 0000000..6a2a418 --- /dev/null +++ b/ManualLayoutTests/OperatorTests.swift @@ -0,0 +1,37 @@ +// +// OperatorTests.swift +// ManualLayout +// +// Created by Baris Sencan on 26/02/15. +// Copyright (c) 2015 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import ManualLayout + +class OperatorTests: XCTestCase { + var view = UIView(frame: CGRectZero) + + override func setUp() { + view.frame = CGRectZero + } + + func testPointAssignment() { + view.origin =~ (1, 3) + XCTAssertEqual(view.origin, CGPoint(x: 1, y: 3), "origin should be at (1, 3)") + } + + func testSizeAssignment() { + view.size =~ (5, 7) + XCTAssertEqual(view.size, CGSize(width: 5, height: 7), "size should be (5, 7)") + } + + func testRectAssignment() { + view.frame =~ (1, 3, 5, 7) + XCTAssertEqual( + view.frame, + CGRect(x: 1, y: 3, width: 5, height: 7), + "frame should be at (1, 3) and of size (5, 7)") + } +} \ No newline at end of file diff --git a/README.md b/README.md index 8151089..b8de670 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,47 @@ So basically, *setting a normal edge's position drags the whole view along with ```swift var top: CGFloat // Top layout guide y coordinate. Read-only. +var right: CGFloat // Equal to the width of the controller's view. Read-only. For convenience. var bottom: CGFloat // Bottom layout guide y coordinate. Read-only. +var left: CGFloat // Always equal to 0. Read-only. For convenience. +``` + +###Helper Methods + +```swift +func inset(view: UIView, amount: CGFloat) -> CGRect +func inset(layer: CALayer, amount: CGFloat) -> CGRect +func inset(rect: CGRect, amount: CGFloat) -> CGRect + +func inset(view: UIView, dx: CGFloat, dy: CGFloat) -> CGRect +func inset(layer: CALayer, dx: CGFloat, dy: CGFloat) -> CGRect +func inset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect + +func inset(view: UIView, top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> CGRect +func inset(layer: CALayer, top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> CGRect +func inset(rect: CGRect, top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> CGRect +``` + +```swift +func offset(view: UIView, amount: CGFloat) -> CGRect +func offset(layer: CALayer, amount: CGFloat) -> CGRect +func offset(rect: CGRect, amount: CGFloat) -> CGRect + +func offset(view: UIView, dx: CGFloat, dy: CGFloat) -> CGRect +func offset(layer: CALayer, dx: CGFloat, dy: CGFloat) -> CGRect +func offset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect { +``` + +These functions never modify the view/layer/rectangle they are passed. + +###Smart Assign Operator + +The smart assign operator `=~` has only one job; to make your life easier. + +```swift +someView.origin =~ (0, 20) +anotherView.size =~ (100, 100) +yetAnotherView.frame =~ (0, 120, view.width, 100) ``` ###CALayer/UIView Methods