diff --git a/.gitignore b/.gitignore index f856ec7..e73df90 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ Carthage Relayout.framework.zip build - +.build diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..5859406 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.2.3 diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..2fdf0c9 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +DEVELOPMENT-SNAPSHOT-2016-09-10-a diff --git a/.travis.yml b/.travis.yml index 7e867e8..aa9ac02 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,28 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 xcode_project: Relayout.xcodeproj -xcode_sdk: iphonesimulator9.3 - -env: - global: - - FRAMEWORK_NAME=Relayout +xcode_sdk: iphonesimulator10.0 before_install: - brew update - brew outdated carthage || brew upgrade carthage -- gem install xcpretty --no-rdoc --no-ri --no-document --quiet +- bundle install + +install: +- eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" script: -- xctool clean build -project Relayout.xcodeproj -scheme "Relayout" -sdk iphonesimulator -- xctool test -project Relayout.xcodeproj -scheme "Relayout" -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 5s" -- xctool clean build -project Relayout.xcodeproj -scheme "Relayout" -sdk appletvsimulator -destination "platform=tvOS Simulator,name=Apple TV 1080p" -- xctool test -project Relayout.xcodeproj -scheme "Relayout" -sdk appletvsimulator -destination "platform=tvOS Simulator,name=Apple TV 1080p" -- xctool clean build -project Relayout.xcodeproj -scheme "Relayout" -sdk macosx -- xctool test -project Relayout.xcodeproj -scheme "Relayout" -sdk macosx -- xctool clean build -project Relayout.xcodeproj -scheme "Sample App" -sdk iphonesimulator +- xcodebuild clean -project Relayout.xcodeproj -scheme "Relayout" -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 5s" +- xcodebuild test -project Relayout.xcodeproj -scheme "Relayout" -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 5s" +- xcodebuild clean -project Relayout.xcodeproj -scheme "Relayout" -sdk appletvsimulator -destination "platform=tvOS Simulator,name=Apple TV 1080p" +- xcodebuild test -project Relayout.xcodeproj -scheme "Relayout" -sdk appletvsimulator -destination "platform=tvOS Simulator,name=Apple TV 1080p" +- xcodebuild clean -project Relayout.xcodeproj -scheme "Relayout" -sdk macosx +- xcodebuild test -project Relayout.xcodeproj -scheme "Relayout" -sdk macosx +- xcodebuild clean -project Relayout.xcodeproj -scheme "Sample App" -sdk iphonesimulator +- xcodebuild build -project Relayout.xcodeproj -scheme "Sample App" -sdk iphonesimulator - carthage build --no-skip-current -- pod lib lint +- bundle exec pod lib lint +- swift build before_deploy: - carthage archive Relayout diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..bcaf1ca --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +source 'https://rubygems.org' + +gem 'activesupport', +gem 'cocoapods' +gem 'xcodeproj', :git => 'https://github.com/CocoaPods/Xcodeproj.git' diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..2c85ac0 --- /dev/null +++ b/Package.swift @@ -0,0 +1,5 @@ +import PackageDescription + +let package = Package( + name: "Relayout" +) diff --git a/README.rst b/README.rst index afac1fd..71fcd0b 100644 --- a/README.rst +++ b/README.rst @@ -44,7 +44,7 @@ Finally, Relayout is not a great tool to use in conjunction with Interface Build Installing ========== -Relayout supports iOS 8.0+, tvOS 9.0+, and OS X 10.10+. You can install Relayout with Carthage, CocoaPods, or manually. +Relayout supports iOS 8.0+, tvOS 9.0+, and OS X 10.10+. You can install Relayout with Carthage, CocoaPods, the Swift package manager, or manually. With CocoaPods -------------- @@ -60,6 +60,13 @@ Add the following to your `Cartfile`:code:. :: github "stevestreza/Relayout" ~> 1.1 +With Swift Package Manager +------------------------- + +Add the following to your `Package.swift`:code: dependencies. :: + + .Package(url: "https://github.com/stevestreza/Relayout.git", majorVersion: 1) + Manually -------- diff --git a/Relayout.podspec b/Relayout.podspec index f1dd430..c991039 100644 --- a/Relayout.podspec +++ b/Relayout.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Relayout" - s.version = "1.1.0" + s.version = "2.0.0" s.summary = "Swift microframework for declaring Auto Layout constraints functionally" s.description = <<-DESC @@ -22,7 +22,7 @@ really dynamic layouts that change or react to UI state changes using Auto Layou s.tvos.deployment_target = '9.0' s.osx.deployment_target = '10.10' - s.source = { :git => "https://github.com/stevestreza/Relayout.git", :tag => "1.1.0" } + s.source = { :git => "https://github.com/stevestreza/Relayout.git", :branch => "swift-3" } s.source_files = "Framework", "Framework/**/*.swift" diff --git a/Relayout.xcodeproj/project.pbxproj b/Relayout.xcodeproj/project.pbxproj index bfafabc..cb28e3c 100644 --- a/Relayout.xcodeproj/project.pbxproj +++ b/Relayout.xcodeproj/project.pbxproj @@ -149,6 +149,7 @@ isa = PBXGroup; children = ( 9BC247281D85128400A8E79B /* Configuration */, + A7EC54FF1D51B20B00A579B9 /* Sources */, A7EC54E41D51B15200A579B9 /* Framework */, A7EC54F01D51B15300A579B9 /* Tests */, A70D4A4E1D51D29E00DD71AE /* Sample App */, @@ -169,8 +170,8 @@ A7EC54E41D51B15200A579B9 /* Framework */ = { isa = PBXGroup; children = ( - A7EC54FF1D51B20B00A579B9 /* Layout */, - A7EC54FE1D51B1FF00A579B9 /* Support Files */, + A7EC54E51D51B15200A579B9 /* Relayout.h */, + A7EC54E71D51B15300A579B9 /* Relayout-Info.plist */, ); path = Framework; sourceTree = ""; @@ -185,16 +186,7 @@ path = RelayoutTests; sourceTree = ""; }; - A7EC54FE1D51B1FF00A579B9 /* Support Files */ = { - isa = PBXGroup; - children = ( - A7EC54E51D51B15200A579B9 /* Relayout.h */, - A7EC54E71D51B15300A579B9 /* Relayout-Info.plist */, - ); - name = "Support Files"; - sourceTree = ""; - }; - A7EC54FF1D51B20B00A579B9 /* Layout */ = { + A7EC54FF1D51B20B00A579B9 /* Sources */ = { isa = PBXGroup; children = ( A7EC55021D51B24200A579B9 /* LayingOut.swift */, @@ -207,7 +199,7 @@ A782C3FE1D5311E20080701E /* ListLayout.swift */, 9BC247241D850FD500A8E79B /* PlatformSupport.swift */, ); - path = Layout; + path = Sources; sourceTree = ""; }; /* End PBXGroup section */ @@ -285,17 +277,20 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Steve Streza"; TargetAttributes = { A70D4A4C1D51D29E00DD71AE = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; }; A7EC54E11D51B15200A579B9 = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; }; A7EC54EB1D51B15300A579B9 = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; }; }; }; @@ -423,8 +418,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = "$(SRCROOT)/SampleApp/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stevestreza.TestRelayout.macOS; + PRODUCT_BUNDLE_IDENTIFIER = com.stevestreza.TestRelayout; PRODUCT_NAME = RelayoutSampleApp; + SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -434,8 +431,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = "$(SRCROOT)/SampleApp/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stevestreza.TestRelayout.macOS; + PRODUCT_BUNDLE_IDENTIFIER = com.stevestreza.TestRelayout; PRODUCT_NAME = RelayoutSampleApp; + SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -453,8 +452,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -478,6 +479,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -499,8 +501,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -518,6 +522,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MTL_ENABLE_DEBUG_INFO = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -541,6 +546,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -559,6 +565,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.stevestreza.Relayout; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -571,6 +578,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.stevestreza.RelayoutTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -583,6 +591,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.stevestreza.RelayoutTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Relayout.xcodeproj/xcshareddata/xcschemes/Relayout.xcscheme b/Relayout.xcodeproj/xcshareddata/xcschemes/Relayout.xcscheme index 7bd512e..e87bf71 100644 --- a/Relayout.xcodeproj/xcshareddata/xcschemes/Relayout.xcscheme +++ b/Relayout.xcodeproj/xcshareddata/xcschemes/Relayout.xcscheme @@ -1,6 +1,6 @@ [NSLayoutConstraint] in XCTAssertEqual(rootView, view) return [ - subview.widthAnchor.constraintEqualToConstant(40), - subview.heightAnchor.constraintEqualToConstant(40), - subview.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 20), - subview.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 20), + subview.widthAnchor.constraint(equalToConstant: 40), + subview.heightAnchor.constraint(equalToConstant: 40), + subview.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + subview.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), ] } return (view, subview, layout) @@ -68,14 +68,14 @@ class RelayoutTests: XCTestCase { XCTAssertEqual(view.constraints.count, 0) identifiedLayout.layout() - let regex = try! NSRegularExpression(pattern: "Test \\[[0-9]*\\]", options: NSRegularExpressionOptions()) + let regex = try! NSRegularExpression(pattern: "Test \\[[0-9]*\\]", options: NSRegularExpression.Options()) view.constraints.forEach { constraint in guard let identifier = constraint.identifier else { XCTAssertNotNil(constraint.identifier) return } - XCTAssertTrue(regex.matchesInString(identifier, options: NSMatchingOptions(), range: NSRange(location: 0, length: identifier.characters.count)).count == 1) + XCTAssertTrue(regex.matches(in: identifier, options: NSRegularExpression.MatchingOptions(), range: NSRange(location: 0, length: identifier.characters.count)).count == 1) } } diff --git a/SampleApp/AppDelegate.swift b/SampleApp/AppDelegate.swift index cb76b9d..c3e734c 100644 --- a/SampleApp/AppDelegate.swift +++ b/SampleApp/AppDelegate.swift @@ -13,30 +13,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json index 118c98f..b8236c6 100644 --- a/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", diff --git a/SampleApp/CrustyViewController.swift b/SampleApp/CrustyViewController.swift index aeb9f51..9438d20 100644 --- a/SampleApp/CrustyViewController.swift +++ b/SampleApp/CrustyViewController.swift @@ -30,8 +30,8 @@ class CrustyViewController: UIViewController { var constraints: [NSLayoutConstraint] = [] if self.segmentedControl.selectedSegmentIndex == 0 { constraints = [ - self.imageView.leadingAnchor.constraintEqualToAnchor(self.targetView.leadingAnchor, constant: inset), - self.imageView.topAnchor.constraintEqualToAnchor(self.targetView.topAnchor, constant: inset) + self.imageView.leadingAnchor.constraint(equalTo: self.targetView.leadingAnchor, constant: inset), + self.imageView.topAnchor.constraint(equalTo: self.targetView.topAnchor, constant: inset) ] } return constraints @@ -41,8 +41,8 @@ class CrustyViewController: UIViewController { var constraints: [NSLayoutConstraint] = [] if self.segmentedControl.selectedSegmentIndex == 1 { constraints = [ - self.imageView.trailingAnchor.constraintEqualToAnchor(self.targetView.trailingAnchor, constant: -inset), - self.imageView.topAnchor.constraintEqualToAnchor(self.targetView.topAnchor, constant: inset) + self.imageView.trailingAnchor.constraint(equalTo: self.targetView.trailingAnchor, constant: -inset), + self.imageView.topAnchor.constraint(equalTo: self.targetView.topAnchor, constant: inset) ] } return constraints @@ -52,8 +52,8 @@ class CrustyViewController: UIViewController { var constraints: [NSLayoutConstraint] = [] if self.segmentedControl.selectedSegmentIndex == 2 { constraints = [ - self.imageView.leadingAnchor.constraintEqualToAnchor(self.targetView.leadingAnchor, constant: inset), - self.imageView.bottomAnchor.constraintEqualToAnchor(self.targetView.bottomAnchor, constant: -inset) + self.imageView.leadingAnchor.constraint(equalTo: self.targetView.leadingAnchor, constant: inset), + self.imageView.bottomAnchor.constraint(equalTo: self.targetView.bottomAnchor, constant: -inset) ] } return constraints @@ -63,8 +63,8 @@ class CrustyViewController: UIViewController { var constraints: [NSLayoutConstraint] = [] if self.segmentedControl.selectedSegmentIndex == 3 { constraints = [ - self.imageView.trailingAnchor.constraintEqualToAnchor(self.targetView.trailingAnchor, constant: -inset), - self.imageView.bottomAnchor.constraintEqualToAnchor(self.targetView.bottomAnchor, constant: -inset) + self.imageView.trailingAnchor.constraint(equalTo: self.targetView.trailingAnchor, constant: -inset), + self.imageView.bottomAnchor.constraint(equalTo: self.targetView.bottomAnchor, constant: -inset) ] } return constraints @@ -73,16 +73,16 @@ class CrustyViewController: UIViewController { var constraints: [NSLayoutConstraint] = [] if self.segmentedControl.selectedSegmentIndex == 4 { constraints = [ - self.imageView.centerXAnchor.constraintEqualToAnchor(self.targetView.centerXAnchor, constant: 0), - self.imageView.centerYAnchor.constraintEqualToAnchor(self.targetView.centerYAnchor, constant: 0), + self.imageView.centerXAnchor.constraint(equalTo: self.targetView.centerXAnchor, constant: 0), + self.imageView.centerYAnchor.constraint(equalTo: self.targetView.centerYAnchor, constant: 0), ] } return constraints }, IdentifierLayout(identifier: "Sizing") { _ in return [ - self.imageView.widthAnchor.constraintEqualToAnchor(self.imageView.heightAnchor, multiplier: 1), - self.imageView.widthAnchor.constraintEqualToConstant(CGFloat(self.widthSlider.value)) + self.imageView.widthAnchor.constraint(equalTo: self.imageView.heightAnchor, multiplier: 1), + self.imageView.widthAnchor.constraint(equalToConstant: CGFloat(self.widthSlider.value)) ] }, ]) @@ -98,8 +98,8 @@ class CrustyViewController: UIViewController { // Dispose of any resources that can be recreated. } - @IBAction func updateUI(animated animated: Bool = true) { - UIView.animateWithDuration((animated ? 0.5 : 0.0), delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: { + @IBAction func updateUI(animated: Bool = true) { + UIView.animate(withDuration: (animated ? 0.5 : 0.0), delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: { self.layout?.layout() }, completion: nil) } diff --git a/SampleApp/MenuViewController.swift b/SampleApp/MenuViewController.swift index 5406cb4..b15d1b5 100644 --- a/SampleApp/MenuViewController.swift +++ b/SampleApp/MenuViewController.swift @@ -18,7 +18,7 @@ extension Array { guard let first = self.first else { return pairs } var lastThing: Element = first - for index in startIndex.advancedBy(1).stride(to: endIndex, by: 1) { + for index in stride(from: startIndex.advanced(by: 1), to: endIndex, by: 1) { let next = self[index] pairs.append((lastThing, next)) lastThing = next @@ -47,13 +47,13 @@ final class MenuViewController: UIViewController { cancelButton = button(title: "Cancel") cancelButton.layer.zPosition = 2000 cancelButton.layoutSubviews() - cancelButton.addTarget(self, action: #selector(MenuViewController.toggleMenuVisible), forControlEvents: .TouchUpInside) + cancelButton.addTarget(self, action: #selector(MenuViewController.toggleMenuVisible), for: .touchUpInside) view.addSubview(cancelButton) layout = ViewLayout(rootView: view, layouts: [ // Horizontal layout or vertical? ConditionalLayout( - condition: { view in self.buttons.count < 6 && view.traitCollection.horizontalSizeClass == .Regular }, + condition: { view in self.buttons.count < 6 && view.traitCollection.horizontalSizeClass == .regular }, // Horizontal layout: LayoutGroup(layouts: [ // Constrain each button horizontally by making the top/bottom/width equal to the next button @@ -62,39 +62,38 @@ final class MenuViewController: UIViewController { iterator: { (view, button, _, previous, next) -> [NSLayoutConstraint] in guard let next = next ?? self.cancelButton else { return [] } return [ - button.topAnchor.constraintEqualToAnchor(next.topAnchor), - button.bottomAnchor.constraintEqualToAnchor(next.bottomAnchor), - (next == self.cancelButton ? nil : button.widthAnchor.constraintEqualToAnchor(next.widthAnchor, multiplier: 1)), - button.trailingAnchor.constraintEqualToAnchor(next.leadingAnchor, constant: (next == self.cancelButton ? -20 : -4)) - ] - .flatMap { $0 } + button.topAnchor.constraint(equalTo: next.topAnchor), + button.bottomAnchor.constraint(equalTo: next.bottomAnchor), + (next == self.cancelButton ? nil : Optional.some(button.widthAnchor.constraint(equalTo: next.widthAnchor, multiplier: 1))), + button.trailingAnchor.constraint(equalTo: next.leadingAnchor, constant: (next == self.cancelButton ? -20 : -4)) + ].flatMap { $0 } } ), // Constrain the first and Layout { view -> [NSLayoutConstraint] in guard let firstButton = self.buttons.first ?? self.cancelButton else { return [] } return [ - firstButton.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 10), - self.cancelButton.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor, constant: -10) + firstButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), + self.cancelButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10) ] } ]), // Vertical elseLayout: LayoutGroup(layouts: [ ListLayout( - items: { [weak self] _ in self?.buttons.reverse() ?? [] }, + items: { [weak self] _ in self?.buttons.reversed() ?? [] }, iterator: { (view, button, _, prev, _) -> [NSLayoutConstraint] in guard let previous = (prev ?? self.cancelButton) else { return [] } return [ - button.leadingAnchor.constraintEqualToAnchor(previous.leadingAnchor), - button.trailingAnchor.constraintEqualToAnchor(previous.trailingAnchor), - button.bottomAnchor.constraintEqualToAnchor(previous.topAnchor, constant: (prev == nil ? -20 : -4)) + button.leadingAnchor.constraint(equalTo: previous.leadingAnchor), + button.trailingAnchor.constraint(equalTo: previous.trailingAnchor), + button.bottomAnchor.constraint(equalTo: previous.topAnchor, constant: (prev == nil ? -20 : -4)) ] } ), Layout(constraints: [ - cancelButton.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 10), - cancelButton.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor, constant: -10) + cancelButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), + cancelButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10) ]), ]) ), @@ -102,11 +101,11 @@ final class MenuViewController: UIViewController { condition: { [weak self] _ in self?.menuVisible ?? false}, layout: Layout { [weak self] _ in guard let strongSelf = self else { return [] } - return [strongSelf.cancelButton.bottomAnchor.constraintEqualToAnchor(strongSelf.view.bottomAnchor, constant: 0 - strongSelf.bottomLayoutGuide.length - 10)] + return [strongSelf.cancelButton.bottomAnchor.constraint(equalTo: strongSelf.view.bottomAnchor, constant: 0 - strongSelf.bottomLayoutGuide.length - 10)] }, elseLayout: Layout { [weak self] _ in guard let strongSelf = self else { return [] } - return [strongSelf.firstButton.topAnchor.constraintEqualToAnchor(strongSelf.view.bottomAnchor, constant: 10)] + return [strongSelf.firstButton.topAnchor.constraint(equalTo: strongSelf.view.bottomAnchor, constant: 10)] } ) ]) @@ -115,22 +114,22 @@ final class MenuViewController: UIViewController { layout.layout() } - private func button(title title: String) -> UIButton { - let button = UIButton(type: UIButtonType.RoundedRect) + fileprivate func button(title: String) -> UIButton { + let button = UIButton(type: UIButtonType.roundedRect) button.translatesAutoresizingMaskIntoConstraints = false - button.setTitle(title, forState: .Normal) - button.titleLabel?.font = UIFont.systemFontOfSize(17) - button.setTitleColor(UIColor.blackColor(), forState: .Normal) + button.setTitle(title, for: .normal) + button.titleLabel?.font = UIFont.systemFont(ofSize: 17) + button.setTitleColor(UIColor.black, for: .normal) button.backgroundColor = UIColor(white: 0.9, alpha: 1.0) button.layer.cornerRadius = 10 - button.layer.borderColor = UIColor.blackColor().colorWithAlphaComponent(0.2).CGColor + button.layer.borderColor = UIColor.black.withAlphaComponent(0.2).cgColor button.layer.borderWidth = 1 button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 16, bottom: 10, right: 16) return button } var buttons: [UIButton] = [] - var cancelButton: UIButton! = UIButton(type: .Custom) + var cancelButton: UIButton! = UIButton(type: .custom) var menuVisible: Bool = false @IBAction func toggleMenuVisible() { @@ -147,15 +146,15 @@ final class MenuViewController: UIViewController { newButton.frame = (buttons.last ?? cancelButton)!.frame newButton.layer.zPosition = CGFloat(1000 - buttonCount) newButton.layoutSubviews() - newButton.addTarget(self, action: #selector(MenuViewController.removeButton(_:)), forControlEvents: .TouchUpInside) + newButton.addTarget(self, action: #selector(MenuViewController.removeButton(_:)), for: .touchUpInside) view.addSubview(newButton) buttons.append(newButton) layoutMenu(animated: true) } - @IBAction func removeButton(sender: UIButton) { - UIView.animateWithDuration(0.3, animations: { + @IBAction func removeButton(_ sender: UIButton) { + UIView.animate(withDuration: 0.3, animations: { sender.alpha = 0 }) { _ in sender.removeFromSuperview() @@ -164,11 +163,11 @@ final class MenuViewController: UIViewController { } } - func layoutMenu(animated animated: Bool) { - UIView.animateWithDuration(animated ? 0.5 : 0, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: layout.layout, completion: nil) + func layoutMenu(animated: Bool) { + UIView.animate(withDuration: animated ? 0.5 : 0, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: layout.layout, completion: nil) } - override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) { + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) layout?.layout() } diff --git a/Framework/Layout/ConditionalLayout.swift b/Sources/ConditionalLayout.swift similarity index 84% rename from Framework/Layout/ConditionalLayout.swift rename to Sources/ConditionalLayout.swift index eda37b6..19a32f3 100644 --- a/Framework/Layout/ConditionalLayout.swift +++ b/Sources/ConditionalLayout.swift @@ -29,7 +29,7 @@ public struct ConditionalLayout: LayingOut { - returns: A new ConditionalLayout object with the given conditional closure and LayingOut objects. */ - public init(condition: (UIView) -> Bool, layout: LayingOut, elseLayout: LayingOut? = nil) { + public init(condition: @escaping (UIView) -> Bool, layout: LayingOut, elseLayout: LayingOut? = nil) { self.condition = condition self.layout = layout self.elseLayout = elseLayout @@ -68,7 +68,7 @@ public extension ConditionalLayout { - returns: A new ConditionalLayout object with the given conditional closure and layout closure. */ - public init(condition: (UIView) -> Bool, handler: (UIView) -> [NSLayoutConstraint]) { + public init(condition: @escaping (UIView) -> Bool, handler: @escaping (UIView) -> [NSLayoutConstraint]) { self.init(condition: condition, layout: Layout(handler: handler), elseLayout: nil) } @@ -84,7 +84,7 @@ public extension ConditionalLayout { - returns: A new ConditionalLayout object with the given conditional closure and layout closure. */ - public init(condition: (UIView) -> Bool, handler: (UIView) -> [NSLayoutConstraint], elseHandler: ((UIView) -> [NSLayoutConstraint])) { + public init(condition: @escaping (UIView) -> Bool, handler: @escaping (UIView) -> [NSLayoutConstraint], elseHandler: @escaping ((UIView) -> [NSLayoutConstraint])) { self.init(condition: condition, layout: Layout(handler: handler), elseLayout: Layout(handler: elseHandler)) } @@ -98,8 +98,8 @@ public extension ConditionalLayout { - returns: A new ConditionalLayout object with the given conditional closure and NSLayoutConstraint objects. */ - public init(condition: (UIView) -> Bool, constraints: [NSLayoutConstraint]) { - NSLayoutConstraint.deactivateConstraints(constraints) + public init(condition: @escaping (UIView) -> Bool, constraints: [NSLayoutConstraint]) { + NSLayoutConstraint.deactivate(constraints) self.init(condition: condition, layout: Layout(constraints: constraints), elseLayout: nil) } @@ -115,9 +115,9 @@ public extension ConditionalLayout { - returns: A new ConditionalLayout object with the given conditional closure and NSLayoutConstraint objects for each condition */ - public init(condition: (UIView) -> Bool, constraints: [NSLayoutConstraint], elseConstraints: [NSLayoutConstraint]) { - NSLayoutConstraint.deactivateConstraints(constraints) - NSLayoutConstraint.deactivateConstraints(elseConstraints) + public init(condition: @escaping (UIView) -> Bool, constraints: [NSLayoutConstraint], elseConstraints: [NSLayoutConstraint]) { + NSLayoutConstraint.deactivate(constraints) + NSLayoutConstraint.deactivate(elseConstraints) self.init(condition: condition, layout: Layout(constraints: constraints), elseLayout: Layout(constraints: elseConstraints) ) } } @@ -132,7 +132,7 @@ public extension LayingOut { - returns: A new ConditionalLayout object with the given conditional closure and supplied LayingOut object. */ - public func when(condition: (UIView) -> Bool) -> ConditionalLayout { + public func when(_ condition: @escaping (UIView) -> Bool) -> ConditionalLayout { return ConditionalLayout(condition: condition, layout: self) } } diff --git a/Framework/Layout/IdentifierLayout.swift b/Sources/IdentifierLayout.swift similarity index 98% rename from Framework/Layout/IdentifierLayout.swift rename to Sources/IdentifierLayout.swift index f33424f..a2f5660 100644 --- a/Framework/Layout/IdentifierLayout.swift +++ b/Sources/IdentifierLayout.swift @@ -73,7 +73,7 @@ public extension IdentifierLayout { - returns: A new IdentifierLayout with the given String identifier and closure. */ - public init(identifier: String, numbered: Bool = false, handler: (UIView) -> [NSLayoutConstraint]) { + public init(identifier: String, numbered: Bool = false, handler: @escaping (UIView) -> [NSLayoutConstraint]) { self.init(identifier: identifier, numbered: numbered, layout: Layout(handler: handler)) } } diff --git a/Framework/Layout/LayingOut.swift b/Sources/LayingOut.swift similarity index 100% rename from Framework/Layout/LayingOut.swift rename to Sources/LayingOut.swift diff --git a/Framework/Layout/Layout.swift b/Sources/Layout.swift similarity index 94% rename from Framework/Layout/Layout.swift rename to Sources/Layout.swift index 854f640..b8af6c1 100644 --- a/Framework/Layout/Layout.swift +++ b/Sources/Layout.swift @@ -19,7 +19,7 @@ public struct Layout: LayingOut { - returns: A new Layout object for the given closure. */ - public init(handler: (UIView) -> [NSLayoutConstraint]) { + public init(handler: @escaping (UIView) -> [NSLayoutConstraint]) { self.handler = handler } diff --git a/Framework/Layout/LayoutGroup.swift b/Sources/LayoutGroup.swift similarity index 94% rename from Framework/Layout/LayoutGroup.swift rename to Sources/LayoutGroup.swift index 996c694..8041d45 100644 --- a/Framework/Layout/LayoutGroup.swift +++ b/Sources/LayoutGroup.swift @@ -50,18 +50,18 @@ public struct LayoutGroup: LayingOut { public func +(lhs: LayingOut, rhs: LayingOut) -> LayoutGroup { var layouts: [LayingOut] = [] if let lhsGroup = lhs as? LayoutGroup { - layouts.appendContentsOf(lhsGroup.layouts) + layouts.append(contentsOf: lhsGroup.layouts) } else { layouts.append(lhs) } if let rhsGroup = rhs as? LayoutGroup { - layouts.appendContentsOf(rhsGroup.layouts) + layouts.append(contentsOf: rhsGroup.layouts) } else { layouts.append(rhs) } return LayoutGroup(layouts: layouts) -} \ No newline at end of file +} diff --git a/Framework/Layout/ListLayout.swift b/Sources/ListLayout.swift similarity index 84% rename from Framework/Layout/ListLayout.swift rename to Sources/ListLayout.swift index 8393456..6127137 100644 --- a/Framework/Layout/ListLayout.swift +++ b/Sources/ListLayout.swift @@ -37,7 +37,7 @@ public struct ListLayout: LayingOut { - returns: An Array to use for the given element. */ - public let itemIterator: (rootView: UIView, element: Element, index: Int, previous: Element?, next: Element?) -> [NSLayoutConstraint] + public let itemIterator: (_ rootView: UIView, _ element: Element, _ index: Int, _ previous: Element?, _ next: Element?) -> [NSLayoutConstraint] /** Creates a new ListLayout with the given items obtainer and item iterator. @@ -47,7 +47,7 @@ public struct ListLayout: LayingOut { - returns: A new ListLayout object with the given items obtainer and item iterator */ - public init(items: (UIView) -> Array, iterator: (rootView: UIView, element: Element, index: Int, previous: Element?, next: Element?) -> [NSLayoutConstraint]) { + public init(items: @escaping (UIView) -> Array, iterator: @escaping (_ rootView: UIView, _ element: Element, _ index: Int, _ previous: Element?, _ next: Element?) -> [NSLayoutConstraint]) { itemsObtainer = items itemIterator = iterator } @@ -68,8 +68,8 @@ public struct ListLayout: LayingOut { let previous: Element? = (index - 1 >= 0 ? items[index - 1] : nil) let next: Element? = (index + 1 < items.count ? items[index + 1] : nil) - let newConstraints = itemIterator(rootView: view, element: element, index: index, previous: previous, next: next) - constraints.appendContentsOf(newConstraints) + let newConstraints = itemIterator(view, element, index, previous, next) + constraints.append(contentsOf: newConstraints) } return constraints } diff --git a/Framework/Layout/PlatformSupport.swift b/Sources/PlatformSupport.swift similarity index 100% rename from Framework/Layout/PlatformSupport.swift rename to Sources/PlatformSupport.swift diff --git a/Framework/Layout/TraitCollectionLayout.swift b/Sources/TraitCollectionLayout.swift similarity index 92% rename from Framework/Layout/TraitCollectionLayout.swift rename to Sources/TraitCollectionLayout.swift index 8483f3d..2342270 100644 --- a/Framework/Layout/TraitCollectionLayout.swift +++ b/Sources/TraitCollectionLayout.swift @@ -41,7 +41,7 @@ public struct TraitCollectionLayout: LayingOut { */ public func constraints(in view: UIView) -> [NSLayoutConstraint] { let traitCollection = view.traitCollection - if traitCollection.containsTraitsInCollection(matchingTraitCollection) { + if traitCollection.containsTraits(in: matchingTraitCollection) { return layout.constraints(in: view) } else { @@ -144,67 +144,67 @@ extension LayingOut { - returns: A new TraitCollectionLayout checking against a given UITraitCollection and returning the NSLayoutConstraint objects from the called LayingOut object. */ - func when(horizontalSizeClass horizontalSizeClass: UIUserInterfaceSizeClass, verticalSizeClass: UIUserInterfaceSizeClass) -> TraitCollectionLayout { + func when(horizontalSizeClass: UIUserInterfaceSizeClass, verticalSizeClass: UIUserInterfaceSizeClass) -> TraitCollectionLayout { return TraitCollectionLayout(horizontalSizeClass: horizontalSizeClass, verticalSizeClass: verticalSizeClass, layout: self) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is a phone and /// returning the NSLayoutConstraint objects from the called LayingOut object if they match. var whenPhone: TraitCollectionLayout { - return when(userInterfaceIdiom: .Phone) + return when(userInterfaceIdiom: .phone) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is a pad and /// returning the NSLayoutConstraint objects from the called LayingOut object if they match. var whenPad: TraitCollectionLayout { - return when(userInterfaceIdiom: .Pad) + return when(userInterfaceIdiom: .pad) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is a TV and /// returning the NSLayoutConstraint objects from the called LayingOut object if they match. @available(iOS 9, *) var whenTV: TraitCollectionLayout { - return when(userInterfaceIdiom: .TV) + return when(userInterfaceIdiom: .tv) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is in CarPlay mode /// and returning the NSLayoutConstraint objects from the called LayingOut object if they match. @available(iOS 9, *) var whenCarPlay: TraitCollectionLayout { - return when(userInterfaceIdiom: .CarPlay) + return when(userInterfaceIdiom: .carPlay) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is horizontally /// compact and returning the NSLayoutConstraint objects from the called LayingOut object if /// they match. var whenHorizontallyCompact: TraitCollectionLayout { - return when(horizontalSizeClass: .Compact) + return when(horizontalSizeClass: .compact) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is horizontally /// regular and returning the NSLayoutConstraint objects from the called LayingOut object if /// they match. var whenHorizontallyRegular: TraitCollectionLayout { - return when(horizontalSizeClass: .Regular) + return when(horizontalSizeClass: .regular) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is vertically /// compact and returning the NSLayoutConstraint objects from the called LayingOut object if /// they match. var whenVerticallyCompact: TraitCollectionLayout { - return when(verticalSizeClass: .Compact) + return when(verticalSizeClass: .compact) } /// Creates a new TraitCollectionLayout checking if the user interface idiom is vertically /// regular and returning the NSLayoutConstraint objects from the called LayingOut object if /// they match. var whenVerticallyRegular: TraitCollectionLayout { - return when(verticalSizeClass: .Regular) + return when(verticalSizeClass: .regular) } } -private extension UITraitCollection { - private convenience init( +fileprivate extension UITraitCollection { + fileprivate convenience init( userInterfaceIdiom idiom: UIUserInterfaceIdiom? = nil, displayScale scale: CGFloat? = nil, horizontalSizeClass: UIUserInterfaceSizeClass? = nil, @@ -228,7 +228,7 @@ private extension UITraitCollection { collections.append(UITraitCollection(verticalSizeClass: verticalSizeClass)) } - self.init(traitsFromCollections: collections) + self.init(traitsFrom: collections) } } diff --git a/Framework/Layout/ViewLayout.swift b/Sources/ViewLayout.swift similarity index 95% rename from Framework/Layout/ViewLayout.swift rename to Sources/ViewLayout.swift index f7e1bf8..0f86a11 100644 --- a/Framework/Layout/ViewLayout.swift +++ b/Sources/ViewLayout.swift @@ -57,9 +57,9 @@ public class ViewLayout { guard isLayingOut == false else { return } isLayingOut = true - NSLayoutConstraint.deactivateConstraints(activeConstraints) + NSLayoutConstraint.deactivate(activeConstraints) activeConstraints = layouts.flatMap { $0.constraints(in: self.rootView) } - NSLayoutConstraint.activateConstraints(activeConstraints) + NSLayoutConstraint.activate(activeConstraints) #if os(OSX) rootView.needsLayout = true