├── .DS_Store ├── .gitignore ├── AutoLayoutMagic.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── AutoLayoutMagic ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── AutoLayout-Magic-Icon.png │ │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── Info.plist └── ViewController.swift ├── LICENSE.md └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akordadev/AutoLayoutMagic/0e95576c62484f941c07048516cc9767b85963bb/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ -------------------------------------------------------------------------------- /AutoLayoutMagic.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0EFCB33D1CD924EF00980F88 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EFCB33C1CD924EF00980F88 /* AppDelegate.swift */; }; 11 | 0EFCB33F1CD924EF00980F88 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EFCB33E1CD924EF00980F88 /* ViewController.swift */; }; 12 | 0EFCB3411CD924EF00980F88 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0EFCB3401CD924EF00980F88 /* Assets.xcassets */; }; 13 | 0EFCB3441CD924EF00980F88 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EFCB3421CD924EF00980F88 /* Main.storyboard */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXFileReference section */ 17 | 0EFCB3391CD924EF00980F88 /* AutoLayoutMagic.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoLayoutMagic.app; sourceTree = BUILT_PRODUCTS_DIR; }; 18 | 0EFCB33C1CD924EF00980F88 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 19 | 0EFCB33E1CD924EF00980F88 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 20 | 0EFCB3401CD924EF00980F88 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 21 | 0EFCB3431CD924EF00980F88 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 22 | 0EFCB3451CD924EF00980F88 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 23 | /* End PBXFileReference section */ 24 | 25 | /* Begin PBXFrameworksBuildPhase section */ 26 | 0EFCB3361CD924EF00980F88 /* Frameworks */ = { 27 | isa = PBXFrameworksBuildPhase; 28 | buildActionMask = 2147483647; 29 | files = ( 30 | ); 31 | runOnlyForDeploymentPostprocessing = 0; 32 | }; 33 | /* End PBXFrameworksBuildPhase section */ 34 | 35 | /* Begin PBXGroup section */ 36 | 0EFCB3301CD924EF00980F88 = { 37 | isa = PBXGroup; 38 | children = ( 39 | 0EFCB33B1CD924EF00980F88 /* AutoLayoutMagic */, 40 | 0EFCB33A1CD924EF00980F88 /* Products */, 41 | ); 42 | sourceTree = ""; 43 | }; 44 | 0EFCB33A1CD924EF00980F88 /* Products */ = { 45 | isa = PBXGroup; 46 | children = ( 47 | 0EFCB3391CD924EF00980F88 /* AutoLayoutMagic.app */, 48 | ); 49 | name = Products; 50 | sourceTree = ""; 51 | }; 52 | 0EFCB33B1CD924EF00980F88 /* AutoLayoutMagic */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 0EFCB33C1CD924EF00980F88 /* AppDelegate.swift */, 56 | 0EFCB33E1CD924EF00980F88 /* ViewController.swift */, 57 | 0EFCB3401CD924EF00980F88 /* Assets.xcassets */, 58 | 0EFCB3421CD924EF00980F88 /* Main.storyboard */, 59 | 0EFCB3451CD924EF00980F88 /* Info.plist */, 60 | ); 61 | path = AutoLayoutMagic; 62 | sourceTree = ""; 63 | }; 64 | /* End PBXGroup section */ 65 | 66 | /* Begin PBXNativeTarget section */ 67 | 0EFCB3381CD924EF00980F88 /* AutoLayoutMagic */ = { 68 | isa = PBXNativeTarget; 69 | buildConfigurationList = 0EFCB3481CD924EF00980F88 /* Build configuration list for PBXNativeTarget "AutoLayoutMagic" */; 70 | buildPhases = ( 71 | 0EFCB3351CD924EF00980F88 /* Sources */, 72 | 0EFCB3361CD924EF00980F88 /* Frameworks */, 73 | 0EFCB3371CD924EF00980F88 /* Resources */, 74 | ); 75 | buildRules = ( 76 | ); 77 | dependencies = ( 78 | ); 79 | name = AutoLayoutMagic; 80 | productName = AutoLayoutMagic; 81 | productReference = 0EFCB3391CD924EF00980F88 /* AutoLayoutMagic.app */; 82 | productType = "com.apple.product-type.application"; 83 | }; 84 | /* End PBXNativeTarget section */ 85 | 86 | /* Begin PBXProject section */ 87 | 0EFCB3311CD924EF00980F88 /* Project object */ = { 88 | isa = PBXProject; 89 | attributes = { 90 | LastSwiftUpdateCheck = 0730; 91 | LastUpgradeCheck = 0730; 92 | ORGANIZATIONNAME = "Matt Cielecki"; 93 | TargetAttributes = { 94 | 0EFCB3381CD924EF00980F88 = { 95 | CreatedOnToolsVersion = 7.3; 96 | DevelopmentTeam = Z677AU3RYN; 97 | LastSwiftMigration = 0810; 98 | }; 99 | }; 100 | }; 101 | buildConfigurationList = 0EFCB3341CD924EF00980F88 /* Build configuration list for PBXProject "AutoLayoutMagic" */; 102 | compatibilityVersion = "Xcode 3.2"; 103 | developmentRegion = English; 104 | hasScannedForEncodings = 0; 105 | knownRegions = ( 106 | en, 107 | Base, 108 | ); 109 | mainGroup = 0EFCB3301CD924EF00980F88; 110 | productRefGroup = 0EFCB33A1CD924EF00980F88 /* Products */; 111 | projectDirPath = ""; 112 | projectRoot = ""; 113 | targets = ( 114 | 0EFCB3381CD924EF00980F88 /* AutoLayoutMagic */, 115 | ); 116 | }; 117 | /* End PBXProject section */ 118 | 119 | /* Begin PBXResourcesBuildPhase section */ 120 | 0EFCB3371CD924EF00980F88 /* Resources */ = { 121 | isa = PBXResourcesBuildPhase; 122 | buildActionMask = 2147483647; 123 | files = ( 124 | 0EFCB3411CD924EF00980F88 /* Assets.xcassets in Resources */, 125 | 0EFCB3441CD924EF00980F88 /* Main.storyboard in Resources */, 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | /* End PBXResourcesBuildPhase section */ 130 | 131 | /* Begin PBXSourcesBuildPhase section */ 132 | 0EFCB3351CD924EF00980F88 /* Sources */ = { 133 | isa = PBXSourcesBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | 0EFCB33F1CD924EF00980F88 /* ViewController.swift in Sources */, 137 | 0EFCB33D1CD924EF00980F88 /* AppDelegate.swift in Sources */, 138 | ); 139 | runOnlyForDeploymentPostprocessing = 0; 140 | }; 141 | /* End PBXSourcesBuildPhase section */ 142 | 143 | /* Begin PBXVariantGroup section */ 144 | 0EFCB3421CD924EF00980F88 /* Main.storyboard */ = { 145 | isa = PBXVariantGroup; 146 | children = ( 147 | 0EFCB3431CD924EF00980F88 /* Base */, 148 | ); 149 | name = Main.storyboard; 150 | sourceTree = ""; 151 | }; 152 | /* End PBXVariantGroup section */ 153 | 154 | /* Begin XCBuildConfiguration section */ 155 | 0EFCB3461CD924EF00980F88 /* Debug */ = { 156 | isa = XCBuildConfiguration; 157 | buildSettings = { 158 | ALWAYS_SEARCH_USER_PATHS = NO; 159 | CLANG_ANALYZER_NONNULL = YES; 160 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 161 | CLANG_CXX_LIBRARY = "libc++"; 162 | CLANG_ENABLE_MODULES = YES; 163 | CLANG_ENABLE_OBJC_ARC = YES; 164 | CLANG_WARN_BOOL_CONVERSION = YES; 165 | CLANG_WARN_CONSTANT_CONVERSION = YES; 166 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 167 | CLANG_WARN_EMPTY_BODY = YES; 168 | CLANG_WARN_ENUM_CONVERSION = YES; 169 | CLANG_WARN_INT_CONVERSION = YES; 170 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 171 | CLANG_WARN_UNREACHABLE_CODE = YES; 172 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 173 | CODE_SIGN_IDENTITY = "-"; 174 | COPY_PHASE_STRIP = NO; 175 | DEBUG_INFORMATION_FORMAT = dwarf; 176 | ENABLE_STRICT_OBJC_MSGSEND = YES; 177 | ENABLE_TESTABILITY = YES; 178 | GCC_C_LANGUAGE_STANDARD = gnu99; 179 | GCC_DYNAMIC_NO_PIC = NO; 180 | GCC_NO_COMMON_BLOCKS = YES; 181 | GCC_OPTIMIZATION_LEVEL = 0; 182 | GCC_PREPROCESSOR_DEFINITIONS = ( 183 | "DEBUG=1", 184 | "$(inherited)", 185 | ); 186 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 187 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 188 | GCC_WARN_UNDECLARED_SELECTOR = YES; 189 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 190 | GCC_WARN_UNUSED_FUNCTION = YES; 191 | GCC_WARN_UNUSED_VARIABLE = YES; 192 | MACOSX_DEPLOYMENT_TARGET = 10.11; 193 | MTL_ENABLE_DEBUG_INFO = YES; 194 | ONLY_ACTIVE_ARCH = YES; 195 | SDKROOT = macosx; 196 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 197 | }; 198 | name = Debug; 199 | }; 200 | 0EFCB3471CD924EF00980F88 /* Release */ = { 201 | isa = XCBuildConfiguration; 202 | buildSettings = { 203 | ALWAYS_SEARCH_USER_PATHS = NO; 204 | CLANG_ANALYZER_NONNULL = YES; 205 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 206 | CLANG_CXX_LIBRARY = "libc++"; 207 | CLANG_ENABLE_MODULES = YES; 208 | CLANG_ENABLE_OBJC_ARC = YES; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_CONSTANT_CONVERSION = YES; 211 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_INT_CONVERSION = YES; 215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 216 | CLANG_WARN_UNREACHABLE_CODE = YES; 217 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 218 | CODE_SIGN_IDENTITY = "-"; 219 | COPY_PHASE_STRIP = NO; 220 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 221 | ENABLE_NS_ASSERTIONS = NO; 222 | ENABLE_STRICT_OBJC_MSGSEND = YES; 223 | GCC_C_LANGUAGE_STANDARD = gnu99; 224 | GCC_NO_COMMON_BLOCKS = YES; 225 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 226 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 227 | GCC_WARN_UNDECLARED_SELECTOR = YES; 228 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 229 | GCC_WARN_UNUSED_FUNCTION = YES; 230 | GCC_WARN_UNUSED_VARIABLE = YES; 231 | MACOSX_DEPLOYMENT_TARGET = 10.11; 232 | MTL_ENABLE_DEBUG_INFO = NO; 233 | SDKROOT = macosx; 234 | }; 235 | name = Release; 236 | }; 237 | 0EFCB3491CD924EF00980F88 /* Debug */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 241 | CODE_SIGN_IDENTITY = "Mac Developer"; 242 | COMBINE_HIDPI_IMAGES = YES; 243 | DEVELOPMENT_TEAM = Z677AU3RYN; 244 | INFOPLIST_FILE = AutoLayoutMagic/Info.plist; 245 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 246 | PRODUCT_BUNDLE_IDENTIFIER = com.akorda.AutoLayoutMagic; 247 | PRODUCT_NAME = "$(TARGET_NAME)"; 248 | SWIFT_VERSION = 3.0; 249 | }; 250 | name = Debug; 251 | }; 252 | 0EFCB34A1CD924EF00980F88 /* Release */ = { 253 | isa = XCBuildConfiguration; 254 | buildSettings = { 255 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 256 | CODE_SIGN_IDENTITY = "Mac Developer"; 257 | COMBINE_HIDPI_IMAGES = YES; 258 | DEVELOPMENT_TEAM = Z677AU3RYN; 259 | INFOPLIST_FILE = AutoLayoutMagic/Info.plist; 260 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 261 | PRODUCT_BUNDLE_IDENTIFIER = com.akorda.AutoLayoutMagic; 262 | PRODUCT_NAME = "$(TARGET_NAME)"; 263 | SWIFT_VERSION = 3.0; 264 | }; 265 | name = Release; 266 | }; 267 | /* End XCBuildConfiguration section */ 268 | 269 | /* Begin XCConfigurationList section */ 270 | 0EFCB3341CD924EF00980F88 /* Build configuration list for PBXProject "AutoLayoutMagic" */ = { 271 | isa = XCConfigurationList; 272 | buildConfigurations = ( 273 | 0EFCB3461CD924EF00980F88 /* Debug */, 274 | 0EFCB3471CD924EF00980F88 /* Release */, 275 | ); 276 | defaultConfigurationIsVisible = 0; 277 | defaultConfigurationName = Release; 278 | }; 279 | 0EFCB3481CD924EF00980F88 /* Build configuration list for PBXNativeTarget "AutoLayoutMagic" */ = { 280 | isa = XCConfigurationList; 281 | buildConfigurations = ( 282 | 0EFCB3491CD924EF00980F88 /* Debug */, 283 | 0EFCB34A1CD924EF00980F88 /* Release */, 284 | ); 285 | defaultConfigurationIsVisible = 0; 286 | defaultConfigurationName = Release; 287 | }; 288 | /* End XCConfigurationList section */ 289 | }; 290 | rootObject = 0EFCB3311CD924EF00980F88 /* Project object */; 291 | } 292 | -------------------------------------------------------------------------------- /AutoLayoutMagic.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutoLayoutMagic/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AutoLayoutMagic 4 | // 5 | // Created by Matt Cielecki on 5/3/16. 6 | // Copyright © 2016 Matt Cielecki. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | 15 | 16 | func applicationDidFinishLaunching(_ aNotification: Notification) { 17 | // Insert code here to initialize your application 18 | } 19 | 20 | func applicationWillTerminate(_ aNotification: Notification) { 21 | // Insert code here to tear down your application 22 | } 23 | 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /AutoLayoutMagic/Assets.xcassets/AppIcon.appiconset/AutoLayout-Magic-Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akordadev/AutoLayoutMagic/0e95576c62484f941c07048516cc9767b85963bb/AutoLayoutMagic/Assets.xcassets/AppIcon.appiconset/AutoLayout-Magic-Icon.png -------------------------------------------------------------------------------- /AutoLayoutMagic/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "512x512", 45 | "idiom" : "mac", 46 | "filename" : "AutoLayout-Magic-Icon.png", 47 | "scale" : "1x" 48 | }, 49 | { 50 | "idiom" : "mac", 51 | "size" : "512x512", 52 | "scale" : "2x" 53 | } 54 | ], 55 | "info" : { 56 | "version" : 1, 57 | "author" : "xcode" 58 | } 59 | } -------------------------------------------------------------------------------- /AutoLayoutMagic/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 169 | 180 | 191 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | YnBsaXN0MDDUAQIDBAUGPT5YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK4HCBMU 220 | GR4fIyQrLjE3OlUkbnVsbNUJCgsMDQ4PEBESVk5TU2l6ZVYkY2xhc3NcTlNJbWFnZUZsYWdzVk5TUmVw 221 | c1dOU0NvbG9ygAKADRIgwwAAgAOAC1Z7MSwgMX3SFQoWGFpOUy5vYmplY3RzoReABIAK0hUKGh2iGxyA 222 | BYAGgAkQANIgCiEiXxAUTlNUSUZGUmVwcmVzZW50YXRpb26AB4AITxEIrE1NACoAAAAKAAAADgEAAAMA 223 | AAABAAEAAAEBAAMAAAABAAEAAAECAAMAAAACAAgACAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAERAAQA 224 | AAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAIAAAEWAAMAAAABAAEAAAEXAAQAAAABAAAAAgEcAAMA 225 | AAABAAEAAAFSAAMAAAABAAEAAAFTAAMAAAACAAEAAYdzAAcAAAf0AAAAuAAAAAAAAAf0YXBwbAIgAABt 226 | bnRyR1JBWVhZWiAH0AACAA4ADAAAAABhY3NwQVBQTAAAAABub25lAAAAAAAAAAAAAAAAAAAAAAAA9tYA 227 | AQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVk 228 | ZXNjAAAAwAAAAG9kc2NtAAABMAAABmZjcHJ0AAAHmAAAADh3dHB0AAAH0AAAABRrVFJDAAAH5AAAAA5k 229 | ZXNjAAAAAAAAABVHZW5lcmljIEdyYXkgUHJvZmlsZQAAAAAAAAAAAAAAFUdlbmVyaWMgR3JheSBQcm9m 230 | aWxlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAA 231 | AAAfAAAADHNrU0sAAAAqAAABhGVuVVMAAAAoAAABrmNhRVMAAAAsAAAB1nZpVk4AAAAsAAACAnB0QlIA 232 | AAAqAAACLnVrVUEAAAAsAAACWGZyRlUAAAAqAAAChGh1SFUAAAAuAAACrnpoVFcAAAAQAAAC3G5iTk8A 233 | AAAsAAAC7GtvS1IAAAAYAAADGGNzQ1oAAAAkAAADMGhlSUwAAAAgAAADVHJvUk8AAAAkAAADdGRlREUA 234 | AAA6AAADmGl0SVQAAAAuAAAD0nN2U0UAAAAuAAAEAHpoQ04AAAAQAAAELmphSlAAAAAWAAAEPmVsR1IA 235 | AAAkAAAEVHB0UE8AAAA4AAAEeG5sTkwAAAAqAAAEsGVzRVMAAAAoAAAE2nRoVEgAAAAkAAAFAnRyVFIA 236 | AAAiAAAFJmZpRkkAAAAsAAAFSGhySFIAAAA6AAAFdHBsUEwAAAA2AAAFrnJ1UlUAAAAmAAAF5GFyRUcA 237 | AAAoAAAGCmRhREsAAAA0AAAGMgBWAWEAZQBvAGIAZQBjAG4A/QAgAHMAaQB2AP0AIABwAHIAbwBmAGkA 238 | bABHAGUAbgBlAHIAaQBjACAARwByAGEAeQAgAFAAcgBvAGYAaQBsAGUAUABlAHIAZgBpAGwAIABkAGUA 239 | IABnAHIAaQBzACAAZwBlAG4A6AByAGkAYwBDHqUAdQAgAGgA7ABuAGgAIABNAOAAdQAgAHgA4QBtACAA 240 | QwBoAHUAbgBnAFAAZQByAGYAaQBsACAAQwBpAG4AegBhACAARwBlAG4A6QByAGkAYwBvBBcEMAQzBDAE 241 | OwRMBD0EOAQ5ACAEPwRABD4ERAQwBDkEOwAgAEcAcgBhAHkAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIA 242 | aQBxAHUAZQAgAGcAcgBpAHMAwQBsAHQAYQBsAOEAbgBvAHMAIABzAHoA/AByAGsAZQAgAHAAcgBvAGYA 243 | aQBskBp1KHBwlo6Ccl9pY8+P8ABHAGUAbgBlAHIAaQBzAGsAIABnAHIA5QB0AG8AbgBlAHAAcgBvAGYA 244 | aQBsx3y8GAAgAEcAcgBhAHkAINUEuFzTDMd8AE8AYgBlAGMAbgD9ACABYQBlAGQA/QAgAHAAcgBvAGYA 245 | aQBsBeQF6AXVBeQF2QXcACAARwByAGEAeQAgBdsF3AXcBdkAUAByAG8AZgBpAGwAIABnAHIAaQAgAGcA 246 | ZQBuAGUAcgBpAGMAQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQAdQBmAGUAbgAtAFAA 247 | cgBvAGYAaQBsAFAAcgBvAGYAaQBsAG8AIABnAHIAaQBnAGkAbwAgAGcAZQBuAGUAcgBpAGMAbwBHAGUA 248 | bgBlAHIAaQBzAGsAIABnAHIA5QBzAGsAYQBsAGUAcAByAG8AZgBpAGxmbpAacHBepmPPj/Blh072TgCC 249 | LDCwMOwwpDDXMO0w1TChMKQw6wOTA7UDvQO5A7oDzAAgA8ADwQO/A8YDrwO7ACADswO6A8EDuQBQAGUA 250 | cgBmAGkAbAAgAGcAZQBuAOkAcgBpAGMAbwAgAGQAZQAgAGMAaQBuAHoAZQBuAHQAbwBzAEEAbABnAGUA 251 | bQBlAGUAbgAgAGcAcgBpAGoAcwBwAHIAbwBmAGkAZQBsAFAAZQByAGYAaQBsACAAZwByAGkAcwAgAGcA 252 | ZQBuAOkAcgBpAGMAbw5CDhsOIw5EDh8OJQ5MDioONQ5ADhcOMg4XDjEOSA4nDkQOGwBHAGUAbgBlAGwA 253 | IABHAHIAaQAgAFAAcgBvAGYAaQBsAGkAWQBsAGUAaQBuAGUAbgAgAGgAYQByAG0AYQBhAHAAcgBvAGYA 254 | aQBpAGwAaQBHAGUAbgBlAHIAaQENAGsAaQAgAHAAcgBvAGYAaQBsACAAcwBpAHYAaQBoACAAdABvAG4A 255 | bwB2AGEAVQBuAGkAdwBlAHIAcwBhAGwAbgB5ACAAcAByAG8AZgBpAGwAIABzAHoAYQByAG8BWwBjAGkE 256 | HgQxBEkEOAQ5ACAEQQQ1BEAESwQ5ACAEPwRABD4ERAQ4BDsETAZFBkQGQQAgBioGOQYxBkoGQQAgAEcA 257 | cgBhAHkAIAYnBkQGOQYnBkUARwBlAG4AZQByAGUAbAAgAGcAcgDlAHQAbwBuAGUAYgBlAHMAawByAGkA 258 | dgBlAGwAcwBlAAB0ZXh0AAAAAENvcHlyaWdodCAyMDA3IEFwcGxlIEluYy4sIGFsbCByaWdodHMgcmVz 259 | ZXJ2ZWQuAFhZWiAAAAAAAADzUQABAAAAARbMY3VydgAAAAAAAAABAc0AANIlJicoWiRjbGFzc25hbWVY 260 | JGNsYXNzZXNfEBBOU0JpdG1hcEltYWdlUmVwoycpKlpOU0ltYWdlUmVwWE5TT2JqZWN00iUmLC1XTlNB 261 | cnJheaIsKtIlJi8wXk5TTXV0YWJsZUFycmF5oy8sKtMyMwo0NTZXTlNXaGl0ZVxOU0NvbG9yU3BhY2VE 262 | MCAwABADgAzSJSY4OVdOU0NvbG9yojgq0iUmOzxXTlNJbWFnZaI7Kl8QD05TS2V5ZWRBcmNoaXZlctE/ 263 | QFRyb290gAEACAARABoAIwAtADIANwBGAEwAVwBeAGUAcgB5AIEAgwCFAIoAjACOAJUAmgClAKcAqQCr 264 | ALAAswC1ALcAuQC7AMAA1wDZANsJiwmQCZsJpAm3CbsJxgnPCdQJ3AnfCeQJ8wn3Cf4KBgoTChgKGgoc 265 | CiEKKQosCjEKOQo8Ck4KUQpWAAAAAAAAAgEAAAAAAAAAQQAAAAAAAAAAAAAAAAAAClg 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /AutoLayoutMagic/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.1.1 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 5 25 | LSApplicationCategoryType 26 | public.app-category.developer-tools 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | NSHumanReadableCopyright 30 | Copyright © 2016 Matt Cielecki. All rights reserved. 31 | NSMainStoryboardFile 32 | Main 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /AutoLayoutMagic/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // AutoLayoutMagic 4 | // 5 | // Created by Matt Cielecki on 5/3/16. 6 | // Copyright © 2016 Matt Cielecki. All rights reserved. 7 | // 8 | // https://github.com/akordadev/AutoLayoutMagic/ 9 | 10 | import Cocoa 11 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary. 12 | // Consider refactoring the code to use the non-optional operators. 13 | fileprivate func < (lhs: T?, rhs: T?) -> Bool { 14 | switch (lhs, rhs) { 15 | case let (l?, r?): 16 | return l < r 17 | case (nil, _?): 18 | return true 19 | default: 20 | return false 21 | } 22 | } 23 | 24 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary. 25 | // Consider refactoring the code to use the non-optional operators. 26 | fileprivate func <= (lhs: T?, rhs: T?) -> Bool { 27 | switch (lhs, rhs) { 28 | case let (l?, r?): 29 | return l <= r 30 | default: 31 | return !(rhs < lhs) 32 | } 33 | } 34 | 35 | 36 | struct Rectangle { 37 | let x: Int 38 | let y: Int 39 | let width: Int 40 | let height: Int 41 | } 42 | 43 | //Class because structs don't allow recursive pointers (View -> View) 44 | class View { 45 | let id: String 46 | var usingAspectRatio: Bool = false 47 | var rect: Rectangle? 48 | //Watch out for circular references 49 | var childViews: [View] = [] 50 | var parentView: View? 51 | 52 | init(id: String) { 53 | self.id = id 54 | } 55 | } 56 | 57 | class ViewController: NSViewController, XMLParserDelegate { 58 | 59 | @IBOutlet weak var filePathTextField: NSTextField! 60 | @IBOutlet weak var aspectRatioCheckBox: NSButton! 61 | @IBOutlet weak var widthRadioButton: NSButton! 62 | @IBOutlet weak var heightRadioButton: NSButton! 63 | 64 | //Used to assign a new parent, when encountering a 65 | var currentView: View? = nil 66 | //might not need parent, consider refactoring??? 67 | var parentView: View? = nil 68 | var currentNode = XMLElement(name: "document") 69 | var outputXml: XMLDocument! 70 | var parser = XMLParser() 71 | var aspectRatioHeight = true 72 | 73 | let supportedViews = ["view", "imageView", "label", "button"] 74 | 75 | fileprivate func beginParsing() { 76 | 77 | outputXml = XMLDocument() 78 | outputXml.version = "1.0" 79 | outputXml.characterEncoding = "UTF-8" 80 | 81 | guard let filePath = filePathTextField.accessibilityValue() else { 82 | return 83 | } 84 | guard let xmlFile = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else { 85 | let alert = NSAlert() 86 | alert.alertStyle = NSAlertStyle.critical 87 | alert.messageText = "File not found" 88 | alert.addButton(withTitle: "Let me double check") 89 | alert.runModal() 90 | return 91 | } 92 | parser = XMLParser(data: xmlFile) 93 | parser.delegate = self 94 | parser.parse() 95 | 96 | let prettyOutput = outputXml.xmlString(withOptions: Int(XMLNode.Options.nodePrettyPrint.rawValue)) 97 | 98 | //create file 99 | let fileManager = FileManager() 100 | fileManager.createFile(atPath: filePath, contents: prettyOutput.data(using: String.Encoding.utf8), attributes: nil) 101 | } 102 | 103 | // MARK: IBActions 104 | 105 | @IBAction func aspectRatioCheck(_ sender: NSButton) { 106 | widthRadioButton.isEnabled = aspectRatioCheckBox.state == NSOnState 107 | heightRadioButton.isEnabled = aspectRatioCheckBox.state == NSOnState 108 | } 109 | 110 | @IBAction func generateLayoutButtonPressed(_ sender: NSButton) { 111 | beginParsing() 112 | } 113 | 114 | @IBAction func heightRadioSelected(_ sender: NSButton) { 115 | widthRadioButton.state = NSOffState 116 | heightRadioButton.state = NSOnState 117 | aspectRatioHeight = true 118 | } 119 | 120 | @IBAction func widthRadioSelected(_ sender: NSButton) { 121 | widthRadioButton.state = NSOnState 122 | heightRadioButton.state = NSOffState 123 | aspectRatioHeight = false 124 | } 125 | 126 | fileprivate func generateConstraints(_ currentView: View, constraintParentNode: XMLElement) { 127 | // 4 constraints per child view 128 | for index in 1...4 { 129 | let constraintChild = XMLElement(name: "constraint") 130 | var attributeData: [String : String] = [:] 131 | //width 132 | switch index { 133 | case 1: 134 | //WIDTH 135 | if !currentView.usingAspectRatio || !aspectRatioHeight { 136 | attributeData["firstItem"] = currentView.id 137 | attributeData["firstAttribute"] = "width" 138 | attributeData["secondItem"] = currentView.parentView?.id 139 | attributeData["secondAttribute"] = "width" 140 | attributeData["multiplier"] = "\(currentView.rect!.width)/\(currentView.parentView!.rect!.width)" 141 | attributeData["id"] = generateGUID() 142 | } 143 | else { 144 | continue 145 | } 146 | case 2: 147 | //HEIGHT 148 | if !currentView.usingAspectRatio || aspectRatioHeight { 149 | attributeData["firstItem"] = currentView.id 150 | attributeData["firstAttribute"] = "height" 151 | attributeData["secondItem"] = currentView.parentView?.id 152 | attributeData["secondAttribute"] = "height" 153 | attributeData["multiplier"] = "\(currentView.rect!.height)/\(currentView.parentView!.rect!.height)" 154 | attributeData["id"] = generateGUID() 155 | } 156 | else { 157 | continue 158 | } 159 | case 3: 160 | //TRAILING 161 | if currentView.rect?.x <= 0 { 162 | // 163 | attributeData["firstItem"] = currentView.id 164 | attributeData["firstAttribute"] = "leading" 165 | attributeData["secondItem"] = currentView.parentView?.id 166 | attributeData["secondAttribute"] = "leading" 167 | attributeData["id"] = generateGUID() 168 | } 169 | else { 170 | attributeData["firstAttribute"] = "trailing" 171 | attributeData["secondItem"] = currentView.id 172 | attributeData["secondAttribute"] = "leading" 173 | //Using ! due to string output being "Optional(132)" instead of "132" 174 | attributeData["multiplier"] = "\(currentView.parentView!.rect!.width)/\(currentView.rect!.x)" 175 | attributeData["id"] = generateGUID() 176 | } 177 | case 4: 178 | //BOTTOM 179 | if currentView.rect?.y <= 0 { 180 | attributeData["firstItem"] = currentView.id 181 | attributeData["firstAttribute"] = "top" 182 | attributeData["secondItem"] = currentView.parentView?.id 183 | attributeData["secondAttribute"] = "top" 184 | attributeData["id"] = generateGUID() 185 | } 186 | else { 187 | attributeData["firstAttribute"] = "bottom" 188 | attributeData["secondItem"] = currentView.id 189 | attributeData["secondAttribute"] = "top" 190 | attributeData["multiplier"] = "\(currentView.parentView!.rect!.height)/\(currentView.rect!.y)" 191 | attributeData["id"] = generateGUID() 192 | } 193 | default: 194 | assert(true, "shouldn't be any other case other than 1...4") 195 | } 196 | for attribute in attributeData { 197 | let XMLattribute = XMLNode(kind: .attribute) 198 | XMLattribute.name = attribute.0 199 | XMLattribute.stringValue = attribute.1 200 | constraintChild.addAttribute(XMLattribute) 201 | } 202 | constraintParentNode.addChild(constraintChild) 203 | attributeData = [:] 204 | } 205 | } 206 | 207 | fileprivate func generateGUID() -> String { 208 | let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 209 | let allowedCharsCount = UInt32(allowedChars.characters.count) 210 | var randomString = "" 211 | 212 | for index in (1...10) { 213 | if index == 4 || index == 7 { 214 | randomString += "-" 215 | } 216 | else { 217 | let randomNum = Int(arc4random_uniform(allowedCharsCount)) 218 | let newCharacter = allowedChars[allowedChars.characters.index(allowedChars.startIndex, offsetBy: randomNum)] 219 | randomString += String(newCharacter) 220 | } 221 | } 222 | return randomString 223 | } 224 | 225 | // MARK: NSXMLParserDelegate Functions 226 | 227 | func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { 228 | 229 | let newChild = XMLElement(name: elementName) 230 | 231 | for (key, value) in attributeDict { 232 | if elementName == "label" && (key == "baselineAdjustment" || key == "adjustsFontSizeToFit") { 233 | continue 234 | } 235 | let attribute = XMLNode(kind: .attribute) 236 | attribute.name = key 237 | attribute.stringValue = value 238 | newChild.addAttribute(attribute) 239 | } 240 | // Add child to correct element node 241 | if elementName == "document" { 242 | outputXml.addChild(newChild) 243 | } 244 | else { 245 | currentNode.addChild(newChild) 246 | } 247 | 248 | // encountering a or etc... 249 | if supportedViews.contains(elementName) { 250 | if let id = attributeDict["id"] { 251 | let view = View(id: id) 252 | if let parentView = parentView { 253 | parentView.childViews.append(view) 254 | } 255 | currentView = view 256 | currentView?.parentView = parentView 257 | if elementName == "label" { 258 | let XMLattribute = XMLNode(kind: .attribute) 259 | XMLattribute.name = "minimumScaleFactor" 260 | XMLattribute.stringValue = "0.4" 261 | newChild.addAttribute(XMLattribute) 262 | if aspectRatioCheckBox.state == NSOnState { 263 | currentView?.usingAspectRatio = true 264 | } 265 | } 266 | } 267 | } 268 | else if elementName == "subviews" { 269 | //we are going deeper in the tree 270 | parentView = currentView 271 | } 272 | //should be next element right after "view" 273 | else if elementName == "rect" { 274 | if let parent = newChild.parent, 275 | let parentName = parent.name, supportedViews.contains(parentName) 276 | { 277 | //Float cast due to "0.0" in some X,Y coords in .storyboard file 278 | if let x = Float(attributeDict["x"]!), 279 | let y = Float(attributeDict["y"]!), 280 | let width = Float(attributeDict["width"]!), 281 | let height = Float(attributeDict["height"]!) 282 | { 283 | let rect = Rectangle(x: Int(x), y: Int(y), width: Int(width), height: Int(height)) 284 | currentView?.rect = rect 285 | } 286 | } 287 | } 288 | 289 | // for determining if buttons have a BG image, therefore should use aspect ratio 290 | else if elementName == "state" { 291 | if let parent = newChild.parent, 292 | let parentName = parent.name, parentName == "button" 293 | { 294 | if let _ = attributeDict["image"] { 295 | currentView?.usingAspectRatio = true 296 | } 297 | } 298 | } 299 | 300 | currentNode = newChild 301 | } 302 | 303 | func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) 304 | { 305 | if supportedViews.contains(elementName) { 306 | if let currentView = currentView, currentView.childViews.count > 0 { 307 | //add constraints 308 | let constraintParent = XMLElement(name: "constraints") 309 | currentNode.addChild(constraintParent) 310 | for childView in currentView.childViews { 311 | generateConstraints(childView, constraintParentNode: constraintParent) 312 | } 313 | } 314 | 315 | //aspect ratio 316 | else { 317 | // 318 | if let currentView = currentView, currentView.usingAspectRatio { 319 | let constraintParent = XMLElement(name: "constraints") 320 | currentNode.addChild(constraintParent) 321 | let constraintChild = XMLElement(name: "constraint") 322 | var attributeData: [String : String] = [:] 323 | attributeData["firstAttribute"] = "width" 324 | attributeData["secondItem"] = currentView.id 325 | attributeData["secondAttribute"] = "height" 326 | attributeData["multiplier"] = "\(currentView.rect!.width):\(currentView.rect!.height)" 327 | attributeData["id"] = generateGUID() 328 | 329 | for attribute in attributeData { 330 | let XMLattribute = XMLNode(kind: .attribute) 331 | XMLattribute.name = attribute.0 332 | XMLattribute.stringValue = attribute.1 333 | constraintChild.addAttribute(XMLattribute) 334 | } 335 | constraintParent.addChild(constraintChild) 336 | } 337 | } 338 | } 339 | if elementName == "subviews" { 340 | //we are going up in the tree 341 | currentView = currentView?.parentView 342 | parentView = currentView?.parentView 343 | 344 | } 345 | if let parent = currentNode.parent as? XMLElement { 346 | currentNode = parent 347 | } 348 | } 349 | } 350 | 351 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 - Auto Layout Magic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auto Layout Magic 2 | > Create 1 scene, let Auto Layout Magic generate the constraints for you 3 | 4 | ![](http://s32.postimg.org/jdq9gcbut/Auto_Layout_Magic_Icon.png) 5 | 6 | Hello friends, 7 | 8 | We've all been there. You have an app supporting iOS 8, and can't use stack views. Therefore you have to make hundreds of constraints to make your view presentable across multiple iOS devices. A very tedious task taking up hours of your time. So why not hire a magician to do it for you? 9 | 10 | This is my first open source project, which I am excited to share with you! 11 | 12 | Auto Layout Magic will enable you to design on one screen, and the tool will generate constraints for you! 13 | 14 | ![](http://s32.postimg.org/exgxcuix1/Screen_Shot_2016_05_19_at_4_46_46_PM.png) 15 | 16 | ## Swift 2 and 3 support! 17 | 18 | There is full support for Swift 3, thanks to the open source community! There is also legacy support for Swift 2 by using the Swift_2 branch! 19 | 20 | ## Usage example 21 | 22 | [Check out this video](https://www.youtube.com/watch?v=rfUpann-zG4&feature=youtu.be), for an overview of how to use the tool! 23 | 24 | Target Screen 25 | 26 | ![](http://s32.postimg.org/jme6vesxx/Target_Screen.png) 27 | 28 | Before Auto Layout Magic, your view will look like this across different devices 29 | 30 | ![](http://s32.postimg.org/eekdiueit/Before_Magic.png) 31 | 32 | After Auto Layout Magic, your constraints will be created for you, and your view looks great across all iOS devices! 33 | 34 | ![](http://s32.postimg.org/fgc6if3t1/After_Magic.png) 35 | 36 | ## Installation 37 | 38 | OS X - Requires XCode 39 | 40 | Fork or clone the repository, open the project in XCode, build and run the tool. Once it has been built you can run it at any time as an app. This app will eventually be uploaded to the app store as a Developer Tool. 41 | 42 | ## Release History 43 | 44 | * 1.1 45 | * Added support for Swift 3. Made a Swift_2 branch for legacy support 46 | * 1.0 47 | * Released Auto Layout Magic to the open source community 48 | 49 | ## Meta 50 | 51 | Akorda – [@AkordaDev](https://twitter.com/AkordaDev) – akordadev@gmail.com 52 | 53 | Distributed under the MIT license. See ``LICENSE`` for more information. 54 | 55 | [https://github.com/akordadev/AutoLayoutMagic](https://github.com/akordadev/AutoLayoutMagic) 56 | 57 | Hope you enjoy, looking forward to working with the community to make this tool great for everyone! 58 | 59 | <3 Akorda 60 | 61 | Check the Wiki for more info! 62 | --------------------------------------------------------------------------------