├── .gitignore ├── Auto Layout Demo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── Auto Layout Demo ├── Supporting Files ├── Auto Layout Demo-Info.plist ├── Auto Layout Demo-Prefix.pch ├── Base.lproj │ └── Main.storyboard ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── PureLayout │ ├── LICENSE │ └── Source │ │ ├── ALView+PureLayout.h │ │ ├── ALView+PureLayout.m │ │ ├── NSArray+PureLayout.h │ │ ├── NSArray+PureLayout.m │ │ ├── NSLayoutConstraint+PureLayout.h │ │ ├── NSLayoutConstraint+PureLayout.m │ │ ├── PureLayout+Internal.h │ │ ├── PureLayout.h │ │ └── PureLayoutDefines.h ├── VSAppDelegate.h ├── VSAppDelegate.m ├── VSViewController.h ├── en.lproj │ └── InfoPlist.strings └── main.m ├── VSLabel.h ├── VSLabel.m ├── VSLayoutExample1.h ├── VSLayoutExample1.m └── VSViewController.m /.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/ 27 | 28 | -------------------------------------------------------------------------------- /Auto Layout Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4522B9431987792200C769A5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4522B9421987792200C769A5 /* Foundation.framework */; }; 11 | 4522B9451987792200C769A5 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4522B9441987792200C769A5 /* CoreGraphics.framework */; }; 12 | 4522B9471987792200C769A5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4522B9461987792200C769A5 /* UIKit.framework */; }; 13 | 4522B94D1987792200C769A5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4522B94B1987792200C769A5 /* InfoPlist.strings */; }; 14 | 4522B94F1987792200C769A5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4522B94E1987792200C769A5 /* main.m */; }; 15 | 4522B9531987792200C769A5 /* VSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4522B9521987792200C769A5 /* VSAppDelegate.m */; }; 16 | 4522B9561987792200C769A5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4522B9541987792200C769A5 /* Main.storyboard */; }; 17 | 4522B9591987792200C769A5 /* VSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4522B9581987792200C769A5 /* VSViewController.m */; }; 18 | 4522B95B1987792200C769A5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4522B95A1987792200C769A5 /* Images.xcassets */; }; 19 | 9389D8A419F250B500EF974B /* VSLayoutExample1.m in Sources */ = {isa = PBXBuildFile; fileRef = 9389D8A319F250B500EF974B /* VSLayoutExample1.m */; }; 20 | 939BCF9F19F279E900B5BAF8 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 939BCF9319F279E900B5BAF8 /* LICENSE */; }; 21 | 939BCFA119F279E900B5BAF8 /* ALView+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 939BCF9719F279E900B5BAF8 /* ALView+PureLayout.m */; }; 22 | 939BCFA219F279E900B5BAF8 /* NSArray+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 939BCF9919F279E900B5BAF8 /* NSArray+PureLayout.m */; }; 23 | 939BCFA319F279E900B5BAF8 /* NSLayoutConstraint+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 939BCF9B19F279E900B5BAF8 /* NSLayoutConstraint+PureLayout.m */; }; 24 | 93D268AE198E5DB800CD96D0 /* VSLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D268AD198E5DB800CD96D0 /* VSLabel.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 4522B93F1987792200C769A5 /* Auto Layout Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Auto Layout Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 4522B9421987792200C769A5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 30 | 4522B9441987792200C769A5 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 31 | 4522B9461987792200C769A5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 32 | 4522B94A1987792200C769A5 /* Auto Layout Demo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Auto Layout Demo-Info.plist"; sourceTree = ""; }; 33 | 4522B94C1987792200C769A5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 34 | 4522B94E1987792200C769A5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 4522B9501987792200C769A5 /* Auto Layout Demo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Auto Layout Demo-Prefix.pch"; sourceTree = ""; }; 36 | 4522B9511987792200C769A5 /* VSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VSAppDelegate.h; sourceTree = ""; }; 37 | 4522B9521987792200C769A5 /* VSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VSAppDelegate.m; sourceTree = ""; }; 38 | 4522B9551987792200C769A5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 39 | 4522B9571987792200C769A5 /* VSViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VSViewController.h; sourceTree = ""; }; 40 | 4522B9581987792200C769A5 /* VSViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VSViewController.m; sourceTree = ""; }; 41 | 4522B95A1987792200C769A5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 42 | 9389D8A219F250B500EF974B /* VSLayoutExample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VSLayoutExample1.h; sourceTree = ""; }; 43 | 9389D8A319F250B500EF974B /* VSLayoutExample1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VSLayoutExample1.m; sourceTree = ""; }; 44 | 939BCF9319F279E900B5BAF8 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 45 | 939BCF9619F279E900B5BAF8 /* ALView+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ALView+PureLayout.h"; sourceTree = ""; }; 46 | 939BCF9719F279E900B5BAF8 /* ALView+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ALView+PureLayout.m"; sourceTree = ""; }; 47 | 939BCF9819F279E900B5BAF8 /* NSArray+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+PureLayout.h"; sourceTree = ""; }; 48 | 939BCF9919F279E900B5BAF8 /* NSArray+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+PureLayout.m"; sourceTree = ""; }; 49 | 939BCF9A19F279E900B5BAF8 /* NSLayoutConstraint+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PureLayout.h"; sourceTree = ""; }; 50 | 939BCF9B19F279E900B5BAF8 /* NSLayoutConstraint+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PureLayout.m"; sourceTree = ""; }; 51 | 939BCF9C19F279E900B5BAF8 /* PureLayout+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PureLayout+Internal.h"; sourceTree = ""; }; 52 | 939BCF9D19F279E900B5BAF8 /* PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureLayout.h; sourceTree = ""; }; 53 | 939BCF9E19F279E900B5BAF8 /* PureLayoutDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureLayoutDefines.h; sourceTree = ""; }; 54 | 93D268AC198E5DB800CD96D0 /* VSLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VSLabel.h; sourceTree = ""; }; 55 | 93D268AD198E5DB800CD96D0 /* VSLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VSLabel.m; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 4522B93C1987792200C769A5 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | 4522B9451987792200C769A5 /* CoreGraphics.framework in Frameworks */, 64 | 4522B9471987792200C769A5 /* UIKit.framework in Frameworks */, 65 | 4522B9431987792200C769A5 /* Foundation.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | 4522B9361987792200C769A5 = { 73 | isa = PBXGroup; 74 | children = ( 75 | 4522B9481987792200C769A5 /* Auto Layout Demo */, 76 | 4522B9411987792200C769A5 /* Frameworks */, 77 | 4522B9401987792200C769A5 /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | 4522B9401987792200C769A5 /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 4522B93F1987792200C769A5 /* Auto Layout Demo.app */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | 4522B9411987792200C769A5 /* Frameworks */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 4522B9421987792200C769A5 /* Foundation.framework */, 93 | 4522B9441987792200C769A5 /* CoreGraphics.framework */, 94 | 4522B9461987792200C769A5 /* UIKit.framework */, 95 | ); 96 | name = Frameworks; 97 | sourceTree = ""; 98 | }; 99 | 4522B9481987792200C769A5 /* Auto Layout Demo */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 4522B9581987792200C769A5 /* VSViewController.m */, 103 | 93D268AC198E5DB800CD96D0 /* VSLabel.h */, 104 | 93D268AD198E5DB800CD96D0 /* VSLabel.m */, 105 | 9389D8A219F250B500EF974B /* VSLayoutExample1.h */, 106 | 9389D8A319F250B500EF974B /* VSLayoutExample1.m */, 107 | 4522B9491987792200C769A5 /* Supporting Files */, 108 | ); 109 | path = "Auto Layout Demo"; 110 | sourceTree = ""; 111 | }; 112 | 4522B9491987792200C769A5 /* Supporting Files */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 4522B9571987792200C769A5 /* VSViewController.h */, 116 | 4522B9511987792200C769A5 /* VSAppDelegate.h */, 117 | 4522B9521987792200C769A5 /* VSAppDelegate.m */, 118 | 4522B9541987792200C769A5 /* Main.storyboard */, 119 | 4522B95A1987792200C769A5 /* Images.xcassets */, 120 | 939BCF9219F279E900B5BAF8 /* PureLayout */, 121 | 4522B94A1987792200C769A5 /* Auto Layout Demo-Info.plist */, 122 | 4522B94B1987792200C769A5 /* InfoPlist.strings */, 123 | 4522B94E1987792200C769A5 /* main.m */, 124 | 4522B9501987792200C769A5 /* Auto Layout Demo-Prefix.pch */, 125 | ); 126 | path = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | 939BCF9219F279E900B5BAF8 /* PureLayout */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 939BCF9319F279E900B5BAF8 /* LICENSE */, 133 | 939BCF9519F279E900B5BAF8 /* Source */, 134 | ); 135 | path = PureLayout; 136 | sourceTree = ""; 137 | }; 138 | 939BCF9519F279E900B5BAF8 /* Source */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 939BCF9619F279E900B5BAF8 /* ALView+PureLayout.h */, 142 | 939BCF9719F279E900B5BAF8 /* ALView+PureLayout.m */, 143 | 939BCF9819F279E900B5BAF8 /* NSArray+PureLayout.h */, 144 | 939BCF9919F279E900B5BAF8 /* NSArray+PureLayout.m */, 145 | 939BCF9A19F279E900B5BAF8 /* NSLayoutConstraint+PureLayout.h */, 146 | 939BCF9B19F279E900B5BAF8 /* NSLayoutConstraint+PureLayout.m */, 147 | 939BCF9C19F279E900B5BAF8 /* PureLayout+Internal.h */, 148 | 939BCF9D19F279E900B5BAF8 /* PureLayout.h */, 149 | 939BCF9E19F279E900B5BAF8 /* PureLayoutDefines.h */, 150 | ); 151 | path = Source; 152 | sourceTree = ""; 153 | }; 154 | /* End PBXGroup section */ 155 | 156 | /* Begin PBXNativeTarget section */ 157 | 4522B93E1987792200C769A5 /* Auto Layout Demo */ = { 158 | isa = PBXNativeTarget; 159 | buildConfigurationList = 4522B9711987792200C769A5 /* Build configuration list for PBXNativeTarget "Auto Layout Demo" */; 160 | buildPhases = ( 161 | 4522B93B1987792200C769A5 /* Sources */, 162 | 4522B93C1987792200C769A5 /* Frameworks */, 163 | 4522B93D1987792200C769A5 /* Resources */, 164 | ); 165 | buildRules = ( 166 | ); 167 | dependencies = ( 168 | ); 169 | name = "Auto Layout Demo"; 170 | productName = "Auto Layout Demo"; 171 | productReference = 4522B93F1987792200C769A5 /* Auto Layout Demo.app */; 172 | productType = "com.apple.product-type.application"; 173 | }; 174 | /* End PBXNativeTarget section */ 175 | 176 | /* Begin PBXProject section */ 177 | 4522B9371987792200C769A5 /* Project object */ = { 178 | isa = PBXProject; 179 | attributes = { 180 | CLASSPREFIX = VS; 181 | LastUpgradeCheck = 0510; 182 | ORGANIZATIONNAME = "Vincent Sit"; 183 | }; 184 | buildConfigurationList = 4522B93A1987792200C769A5 /* Build configuration list for PBXProject "Auto Layout Demo" */; 185 | compatibilityVersion = "Xcode 3.2"; 186 | developmentRegion = English; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | en, 190 | Base, 191 | "zh-Hans", 192 | ); 193 | mainGroup = 4522B9361987792200C769A5; 194 | productRefGroup = 4522B9401987792200C769A5 /* Products */; 195 | projectDirPath = ""; 196 | projectRoot = ""; 197 | targets = ( 198 | 4522B93E1987792200C769A5 /* Auto Layout Demo */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 4522B93D1987792200C769A5 /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | 4522B95B1987792200C769A5 /* Images.xcassets in Resources */, 209 | 4522B94D1987792200C769A5 /* InfoPlist.strings in Resources */, 210 | 939BCF9F19F279E900B5BAF8 /* LICENSE in Resources */, 211 | 4522B9561987792200C769A5 /* Main.storyboard in Resources */, 212 | ); 213 | runOnlyForDeploymentPostprocessing = 0; 214 | }; 215 | /* End PBXResourcesBuildPhase section */ 216 | 217 | /* Begin PBXSourcesBuildPhase section */ 218 | 4522B93B1987792200C769A5 /* Sources */ = { 219 | isa = PBXSourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 9389D8A419F250B500EF974B /* VSLayoutExample1.m in Sources */, 223 | 4522B9591987792200C769A5 /* VSViewController.m in Sources */, 224 | 939BCFA119F279E900B5BAF8 /* ALView+PureLayout.m in Sources */, 225 | 939BCFA219F279E900B5BAF8 /* NSArray+PureLayout.m in Sources */, 226 | 939BCFA319F279E900B5BAF8 /* NSLayoutConstraint+PureLayout.m in Sources */, 227 | 93D268AE198E5DB800CD96D0 /* VSLabel.m in Sources */, 228 | 4522B94F1987792200C769A5 /* main.m in Sources */, 229 | 4522B9531987792200C769A5 /* VSAppDelegate.m in Sources */, 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXSourcesBuildPhase section */ 234 | 235 | /* Begin PBXVariantGroup section */ 236 | 4522B94B1987792200C769A5 /* InfoPlist.strings */ = { 237 | isa = PBXVariantGroup; 238 | children = ( 239 | 4522B94C1987792200C769A5 /* en */, 240 | ); 241 | name = InfoPlist.strings; 242 | sourceTree = ""; 243 | }; 244 | 4522B9541987792200C769A5 /* Main.storyboard */ = { 245 | isa = PBXVariantGroup; 246 | children = ( 247 | 4522B9551987792200C769A5 /* Base */, 248 | ); 249 | name = Main.storyboard; 250 | sourceTree = ""; 251 | }; 252 | /* End PBXVariantGroup section */ 253 | 254 | /* Begin XCBuildConfiguration section */ 255 | 4522B96F1987792200C769A5 /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_EMPTY_BODY = YES; 267 | CLANG_WARN_ENUM_CONVERSION = YES; 268 | CLANG_WARN_INT_CONVERSION = YES; 269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 270 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 271 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 272 | COPY_PHASE_STRIP = NO; 273 | GCC_C_LANGUAGE_STANDARD = gnu99; 274 | GCC_DYNAMIC_NO_PIC = NO; 275 | GCC_OPTIMIZATION_LEVEL = 0; 276 | GCC_PREPROCESSOR_DEFINITIONS = ( 277 | "DEBUG=1", 278 | "$(inherited)", 279 | ); 280 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 281 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 282 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 283 | GCC_WARN_UNDECLARED_SELECTOR = YES; 284 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 285 | GCC_WARN_UNUSED_FUNCTION = YES; 286 | GCC_WARN_UNUSED_VARIABLE = YES; 287 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 288 | ONLY_ACTIVE_ARCH = YES; 289 | SDKROOT = iphoneos; 290 | }; 291 | name = Debug; 292 | }; 293 | 4522B9701987792200C769A5 /* Release */ = { 294 | isa = XCBuildConfiguration; 295 | buildSettings = { 296 | ALWAYS_SEARCH_USER_PATHS = NO; 297 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 298 | CLANG_CXX_LIBRARY = "libc++"; 299 | CLANG_ENABLE_MODULES = YES; 300 | CLANG_ENABLE_OBJC_ARC = YES; 301 | CLANG_WARN_BOOL_CONVERSION = YES; 302 | CLANG_WARN_CONSTANT_CONVERSION = YES; 303 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 304 | CLANG_WARN_EMPTY_BODY = YES; 305 | CLANG_WARN_ENUM_CONVERSION = YES; 306 | CLANG_WARN_INT_CONVERSION = YES; 307 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 309 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 310 | COPY_PHASE_STRIP = YES; 311 | ENABLE_NS_ASSERTIONS = NO; 312 | GCC_C_LANGUAGE_STANDARD = gnu99; 313 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 314 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 315 | GCC_WARN_UNDECLARED_SELECTOR = YES; 316 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 317 | GCC_WARN_UNUSED_FUNCTION = YES; 318 | GCC_WARN_UNUSED_VARIABLE = YES; 319 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 320 | SDKROOT = iphoneos; 321 | VALIDATE_PRODUCT = YES; 322 | }; 323 | name = Release; 324 | }; 325 | 4522B9721987792200C769A5 /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 329 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 330 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 331 | GCC_PREFIX_HEADER = "Auto Layout Demo/Supporting Files/Auto Layout Demo-Prefix.pch"; 332 | INFOPLIST_FILE = "Auto Layout Demo/Supporting Files/Auto Layout Demo-Info.plist"; 333 | PRODUCT_NAME = "$(TARGET_NAME)"; 334 | WRAPPER_EXTENSION = app; 335 | }; 336 | name = Debug; 337 | }; 338 | 4522B9731987792200C769A5 /* Release */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 342 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 343 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 344 | GCC_PREFIX_HEADER = "Auto Layout Demo/Supporting Files/Auto Layout Demo-Prefix.pch"; 345 | INFOPLIST_FILE = "Auto Layout Demo/Supporting Files/Auto Layout Demo-Info.plist"; 346 | PRODUCT_NAME = "$(TARGET_NAME)"; 347 | WRAPPER_EXTENSION = app; 348 | }; 349 | name = Release; 350 | }; 351 | /* End XCBuildConfiguration section */ 352 | 353 | /* Begin XCConfigurationList section */ 354 | 4522B93A1987792200C769A5 /* Build configuration list for PBXProject "Auto Layout Demo" */ = { 355 | isa = XCConfigurationList; 356 | buildConfigurations = ( 357 | 4522B96F1987792200C769A5 /* Debug */, 358 | 4522B9701987792200C769A5 /* Release */, 359 | ); 360 | defaultConfigurationIsVisible = 0; 361 | defaultConfigurationName = Release; 362 | }; 363 | 4522B9711987792200C769A5 /* Build configuration list for PBXNativeTarget "Auto Layout Demo" */ = { 364 | isa = XCConfigurationList; 365 | buildConfigurations = ( 366 | 4522B9721987792200C769A5 /* Debug */, 367 | 4522B9731987792200C769A5 /* Release */, 368 | ); 369 | defaultConfigurationIsVisible = 0; 370 | defaultConfigurationName = Release; 371 | }; 372 | /* End XCConfigurationList section */ 373 | }; 374 | rootObject = 4522B9371987792200C769A5 /* Project object */; 375 | } 376 | -------------------------------------------------------------------------------- /Auto Layout Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/Auto Layout Demo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.vincentsit.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/Auto Layout Demo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #import "PureLayout.h" 17 | #endif 18 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/LICENSE: -------------------------------------------------------------------------------- 1 | This code is distributed under the terms and conditions of the MIT license. 2 | 3 | Copyright (c) 2014 Tyler Fox 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/ALView+PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // ALView+PureLayout.h 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2012 Richard Turton 7 | // Copyright (c) 2013-2014 Tyler Fox 8 | // 9 | // This code is distributed under the terms and conditions of the MIT license. 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to 13 | // deal in the Software without restriction, including without limitation the 14 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 15 | // sell copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 27 | // IN THE SOFTWARE. 28 | // 29 | 30 | #import "PureLayoutDefines.h" 31 | 32 | 33 | #pragma mark - ALView+PureLayout 34 | 35 | /** 36 | A category on UIView/NSView that provides a simple yet powerful interface for creating Auto Layout constraints. 37 | */ 38 | @interface ALView (PureLayout) 39 | 40 | 41 | #pragma mark Factory & Initializer Methods 42 | 43 | /** Creates and returns a new view that does not convert the autoresizing mask into constraints. */ 44 | + (instancetype)newAutoLayoutView; 45 | 46 | /** Initializes and returns a new view that does not convert the autoresizing mask into constraints. */ 47 | - (instancetype)initForAutoLayout; 48 | 49 | 50 | #pragma mark Create Constraints Without Installing 51 | 52 | /** Prevents constraints created in the given constraints block from being automatically installed (activated). 53 | The created constraints returned from each PureLayout API call must be stored, as they are not retained. */ 54 | + (void)autoCreateConstraintsWithoutInstalling:(ALConstraintsBlock)block; 55 | 56 | 57 | #pragma mark Set Priority For Constraints 58 | 59 | /** Sets the constraint priority to the given value for all constraints created using the PureLayout API within the given constraints block. 60 | NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added without using the PureLayout API! */ 61 | + (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(ALConstraintsBlock)block; 62 | 63 | 64 | #pragma mark Set Identifier For Constraints 65 | 66 | #if __PureLayout_MinBaseSDK_iOS8 67 | 68 | /** Sets the identifier for all constraints created using the PureLayout API within the given constraints block. 69 | NOTE: This method will have no effect (and will NOT set the identifier) on constraints created or added without using the PureLayout API! */ 70 | + (void)autoSetIdentifier:(NSString *)identifer forConstraints:(ALConstraintsBlock)block; 71 | 72 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 73 | 74 | 75 | #pragma mark Center & Align in Superview 76 | 77 | /** Centers the view in its superview. */ 78 | - (NSArray *)autoCenterInSuperview; 79 | 80 | /** Aligns the view to the same axis of its superview. */ 81 | - (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis; 82 | 83 | #if __PureLayout_MinBaseSDK_iOS8 84 | 85 | /** Centers the view in its superview's margins. Available in iOS 8.0 and later. */ 86 | - (NSArray *)autoCenterInSuperviewMargins; 87 | 88 | /** Aligns the view to the corresponding margin axis of its superview. Available in iOS 8.0 and later. */ 89 | - (NSLayoutConstraint *)autoAlignAxisToSuperviewMarginAxis:(ALAxis)axis; 90 | 91 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 92 | 93 | 94 | #pragma mark Pin Edges to Superview 95 | 96 | /** Pins the given edge of the view to the same edge of its superview. */ 97 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge; 98 | 99 | /** Pins the given edge of the view to the same edge of its superview with an inset. */ 100 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset; 101 | 102 | /** Pins the given edge of the view to the same edge of its superview with an inset as a maximum or minimum. */ 103 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation; 104 | 105 | /** Pins the edges of the view to the edges of its superview with the given edge insets. */ 106 | - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets; 107 | 108 | /** Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge. */ 109 | - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge; 110 | 111 | #if __PureLayout_MinBaseSDK_iOS8 112 | 113 | /** Pins the given edge of the view to the corresponding margin of its superview. Available in iOS 8.0 and later. */ 114 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge; 115 | 116 | /** Pins the given edge of the view to the corresponding margin of its superview as a maximum or minimum. Available in iOS 8.0 and later. */ 117 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge relation:(NSLayoutRelation)relation; 118 | 119 | /** Pins the edges of the view to the margins of its superview. Available in iOS 8.0 and later. */ 120 | - (NSArray *)autoPinEdgesToSuperviewMargins; 121 | 122 | /** Pins 3 of the 4 edges of the view to the margins of its superview excluding one edge. Available in iOS 8.0 and later. */ 123 | - (NSArray *)autoPinEdgesToSuperviewMarginsExcludingEdge:(ALEdge)edge; 124 | 125 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 126 | 127 | 128 | #pragma mark Pin Edges 129 | 130 | /** Pins an edge of the view to a given edge of another view. */ 131 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView; 132 | 133 | /** Pins an edge of the view to a given edge of another view with an offset. */ 134 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset; 135 | 136 | /** Pins an edge of the view to a given edge of another view with an offset as a maximum or minimum. */ 137 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; 138 | 139 | 140 | #pragma mark Align Axes 141 | 142 | /** Aligns an axis of the view to the same axis of another view. */ 143 | - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView; 144 | 145 | /** Aligns an axis of the view to the same axis of another view with an offset. */ 146 | - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView withOffset:(CGFloat)offset; 147 | 148 | 149 | #pragma mark Match Dimensions 150 | 151 | /** Matches a dimension of the view to a given dimension of another view. */ 152 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView; 153 | 154 | /** Matches a dimension of the view to a given dimension of another view with an offset. */ 155 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset; 156 | 157 | /** Matches a dimension of the view to a given dimension of another view with an offset as a maximum or minimum. */ 158 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; 159 | 160 | /** Matches a dimension of the view to a multiple of a given dimension of another view. */ 161 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier; 162 | 163 | /** Matches a dimension of the view to a multiple of a given dimension of another view as a maximum or minimum. */ 164 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation; 165 | 166 | 167 | #pragma mark Set Dimensions 168 | 169 | /** Sets the view to a specific size. */ 170 | - (NSArray *)autoSetDimensionsToSize:(CGSize)size; 171 | 172 | /** Sets the given dimension of the view to a specific size. */ 173 | - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size; 174 | 175 | /** Sets the given dimension of the view to a specific size as a maximum or minimum. */ 176 | - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size relation:(NSLayoutRelation)relation; 177 | 178 | 179 | #pragma mark Set Content Compression Resistance & Hugging 180 | 181 | /** Sets the priority of content compression resistance for an axis. 182 | NOTE: This method must be called from within the block passed into the method +[UIView autoSetPriority:forConstraints:] */ 183 | - (void)autoSetContentCompressionResistancePriorityForAxis:(ALAxis)axis; 184 | 185 | /** Sets the priority of content hugging for an axis. 186 | NOTE: This method must be called from within the block passed into the method +[UIView autoSetPriority:forConstraints:] */ 187 | - (void)autoSetContentHuggingPriorityForAxis:(ALAxis)axis; 188 | 189 | 190 | #pragma mark Constrain Any Attributes 191 | 192 | /** Constrains an attribute of the view to a given attribute of another view. */ 193 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView; 194 | 195 | /** Constrains an attribute of the view to a given attribute of another view with an offset. */ 196 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset; 197 | 198 | /** Constrains an attribute of the view to a given attribute of another view with an offset as a maximum or minimum. */ 199 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; 200 | 201 | /** Constrains an attribute of the view to a given attribute of another view with a multiplier. */ 202 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier; 203 | 204 | /** Constrains an attribute of the view to a given attribute of another view with a multiplier as a maximum or minimum. */ 205 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation; 206 | 207 | 208 | #pragma mark Pin to Layout Guides (iOS only) 209 | 210 | #if TARGET_OS_IPHONE 211 | 212 | /** Pins the top edge of the view to the top layout guide of the given view controller with an inset. Available on iOS only. */ 213 | - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset; 214 | 215 | /** Pins the top edge of the view to the top layout guide of the given view controller with an inset as a maximum or minimum. Available on iOS only. */ 216 | - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation; 217 | 218 | /** Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset. Available on iOS only. */ 219 | - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset; 220 | 221 | /** Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset as a maximum or minimum. Available on iOS only. */ 222 | - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation; 223 | 224 | #endif /* TARGET_OS_IPHONE */ 225 | 226 | 227 | #pragma mark Deprecated Methods 228 | 229 | /** DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 230 | Removes all explicit constraints that affect the view. 231 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 232 | NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove. */ 233 | - (void)autoRemoveConstraintsAffectingView __attribute__((deprecated)); 234 | 235 | /** DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 236 | Removes all constraints that affect the view, optionally including implicit constraints. 237 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 238 | NOTE: Implicit constraints are auto-generated lower priority constraints, and you usually do not want to remove these. */ 239 | - (void)autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints __attribute__((deprecated)); 240 | 241 | /** DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 242 | Recursively removes all explicit constraints that affect the view and its subviews. 243 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 244 | NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove. */ 245 | - (void)autoRemoveConstraintsAffectingViewAndSubviews __attribute__((deprecated)); 246 | 247 | /** DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 248 | Recursively removes all constraints from the view and its subviews, optionally including implicit constraints. 249 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 250 | NOTE: Implicit constraints are auto-generated lower priority constraints, and you usually do not want to remove these. */ 251 | - (void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints __attribute__((deprecated)); 252 | 253 | @end 254 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/ALView+PureLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // ALView+PureLayout.m 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2012 Richard Turton 7 | // Copyright (c) 2013-2014 Tyler Fox 8 | // 9 | // This code is distributed under the terms and conditions of the MIT license. 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to 13 | // deal in the Software without restriction, including without limitation the 14 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 15 | // sell copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 27 | // IN THE SOFTWARE. 28 | // 29 | 30 | #import "ALView+PureLayout.h" 31 | #import "NSLayoutConstraint+PureLayout.h" 32 | #import "NSArray+PureLayout.h" 33 | #import "PureLayout+Internal.h" 34 | 35 | 36 | #pragma mark - ALView+PureLayout 37 | 38 | @implementation ALView (PureLayout) 39 | 40 | 41 | #pragma mark Factory & Initializer Methods 42 | 43 | /** 44 | Creates and returns a new view that does not convert the autoresizing mask into constraints. 45 | */ 46 | + (instancetype)newAutoLayoutView 47 | { 48 | ALView *view = [self new]; 49 | view.translatesAutoresizingMaskIntoConstraints = NO; 50 | return view; 51 | } 52 | 53 | /** 54 | Initializes and returns a new view that does not convert the autoresizing mask into constraints. 55 | */ 56 | - (instancetype)initForAutoLayout 57 | { 58 | self = [self init]; 59 | if (self) { 60 | self.translatesAutoresizingMaskIntoConstraints = NO; 61 | } 62 | return self; 63 | } 64 | 65 | 66 | #pragma mark Create Constraints Without Installing 67 | 68 | /** 69 | A global variable that is set to YES while the constraints block passed in to the 70 | +[autoCreateConstraintsWithoutInstalling:] method is executing. 71 | NOTE: Access to this variable is not synchronized (and should only be done on the main thread). 72 | */ 73 | static BOOL _al_preventAutomaticConstraintInstallation = NO; 74 | 75 | /** 76 | Public accessor for the global variable that determines whether automatic constraint installation should be prevented. 77 | */ 78 | + (BOOL)al_preventAutomaticConstraintInstallation 79 | { 80 | return _al_preventAutomaticConstraintInstallation; 81 | } 82 | 83 | /** 84 | Prevents constraints created in the given constraints block from being automatically installed (activated). 85 | The created constraints returned from each PureLayout API call must be stored, as they are not retained. 86 | 87 | @param block A block of method calls to the PureLayout API that create constraints. 88 | */ 89 | + (void)autoCreateConstraintsWithoutInstalling:(ALConstraintsBlock)block 90 | { 91 | NSAssert(block, @"The constraints block cannot be nil."); 92 | if (block) { 93 | _al_preventAutomaticConstraintInstallation = YES; 94 | block(); 95 | _al_preventAutomaticConstraintInstallation = NO; 96 | } 97 | } 98 | 99 | 100 | #pragma mark Set Priority For Constraints 101 | 102 | /** 103 | A global variable that determines the priority of all constraints created and added by this library. 104 | Defaults to Required; will only be a different value while executing a constraints block passed into the 105 | +[autoSetPriority:forConstraints:] method (as that method will reset the value back to Required 106 | before returning). 107 | NOTE: Access to this variable is not synchronized (and should only be done on the main thread). 108 | */ 109 | static ALLayoutPriority _al_globalConstraintPriority = ALLayoutPriorityRequired; 110 | 111 | /** 112 | A global variable that is set to YES while the constraints block passed in to the 113 | +[autoSetPriority:forConstraints:] method is executing. 114 | NOTE: Access to this variable is not synchronized (and should only be done on the main thread). 115 | */ 116 | static BOOL _al_isExecutingPriorityConstraintsBlock = NO; 117 | 118 | /** 119 | Sets the constraint priority to the given value for all constraints created using the PureLayout 120 | API within the given constraints block. 121 | 122 | NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added 123 | without using the PureLayout API! 124 | 125 | @param priority The layout priority to be set on all constraints created in the constraints block. 126 | @param block A block of method calls to the PureLayout API that create and install constraints. 127 | */ 128 | + (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(ALConstraintsBlock)block 129 | { 130 | NSAssert(block, @"The constraints block cannot be nil."); 131 | if (block) { 132 | _al_globalConstraintPriority = priority; 133 | _al_isExecutingPriorityConstraintsBlock = YES; 134 | block(); 135 | _al_isExecutingPriorityConstraintsBlock = NO; 136 | _al_globalConstraintPriority = ALLayoutPriorityRequired; 137 | } 138 | } 139 | 140 | 141 | #pragma mark Set Identifier For Constraints 142 | 143 | #if __PureLayout_MinBaseSDK_iOS8 144 | 145 | /** 146 | A global variable that determines the identifier for all constraints created and added by this library. 147 | Defaults to nil; will only be a different value while executing a constraints block passed into the 148 | +[autoSetIdentifier:forConstraints:] method (as that method will reset the value back to nil before 149 | returning). 150 | NOTE: Access to this variable is not synchronized (and should only be done on the main thread). 151 | */ 152 | static NSString *_al_globalConstraintIdentifier = nil; 153 | 154 | /** 155 | Sets the identifier for all constraints created using the PureLayout API within the given constraints block. 156 | 157 | NOTE: This method will have no effect (and will NOT set the identifier) on constraints created or added 158 | without using the PureLayout API! 159 | 160 | @param identifer A string used to identify all constraints created in the constraints block. 161 | @param block A block of method calls to the PureLayout API that create and install constraints. 162 | */ 163 | + (void)autoSetIdentifier:(NSString *)identifer forConstraints:(ALConstraintsBlock)block 164 | { 165 | NSAssert(block, @"The constraints block cannot be nil."); 166 | if (block) { 167 | _al_globalConstraintIdentifier = identifer; 168 | block(); 169 | _al_globalConstraintIdentifier = nil; 170 | } 171 | } 172 | 173 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 174 | 175 | 176 | #pragma mark Center in Superview 177 | 178 | /** 179 | Centers the view in its superview. 180 | 181 | @return An array of constraints added. 182 | */ 183 | - (NSArray *)autoCenterInSuperview 184 | { 185 | NSMutableArray *constraints = [NSMutableArray new]; 186 | [constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisHorizontal]]; 187 | [constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisVertical]]; 188 | return constraints; 189 | } 190 | 191 | /** 192 | Aligns the view to the same axis of its superview. 193 | 194 | @param axis The axis of this view and of its superview to align. 195 | @return The constraint added. 196 | */ 197 | - (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis 198 | { 199 | self.translatesAutoresizingMaskIntoConstraints = NO; 200 | ALView *superview = self.superview; 201 | NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); 202 | return [self autoConstrainAttribute:(ALAttribute)axis toAttribute:(ALAttribute)axis ofView:superview]; 203 | } 204 | 205 | #if __PureLayout_MinBaseSDK_iOS8 206 | 207 | /** 208 | Centers the view in its superview, taking into account the layout margins of both the view and its superview. 209 | 210 | @return An array of constraints added. 211 | */ 212 | - (NSArray *)autoCenterInSuperviewMargins 213 | { 214 | NSMutableArray *constraints = [NSMutableArray new]; 215 | [constraints addObject:[self autoAlignAxisToSuperviewMarginAxis:ALAxisHorizontal]]; 216 | [constraints addObject:[self autoAlignAxisToSuperviewMarginAxis:ALAxisVertical]]; 217 | return constraints; 218 | } 219 | 220 | /** 221 | Aligns the view to the corresponding margin axis of its superview. 222 | 223 | @param axis The axis of this view to align to the corresponding margin axis of its superview. 224 | @return The constraint added. 225 | */ 226 | - (NSLayoutConstraint *)autoAlignAxisToSuperviewMarginAxis:(ALAxis)axis 227 | { 228 | self.translatesAutoresizingMaskIntoConstraints = NO; 229 | ALView *superview = self.superview; 230 | NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); 231 | ALMarginAxis marginAxis = [NSLayoutConstraint al_marginAxisForAxis:axis]; 232 | return [self autoConstrainAttribute:(ALAttribute)axis toAttribute:(ALAttribute)marginAxis ofView:superview]; 233 | } 234 | 235 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 236 | 237 | 238 | #pragma mark Pin Edges to Superview 239 | 240 | /** 241 | Pins the given edge of the view to the same edge of its superview. 242 | 243 | @param edge The edge of this view and its superview to pin. 244 | @return The constraint added. 245 | */ 246 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge 247 | { 248 | return [self autoPinEdgeToSuperviewEdge:edge withInset:0.0]; 249 | } 250 | 251 | /** 252 | Pins the given edge of the view to the same edge of its superview with an inset. 253 | 254 | @param edge The edge of this view and its superview to pin. 255 | @param inset The amount to inset this view's edge from the superview's edge. 256 | @return The constraint added. 257 | */ 258 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset 259 | { 260 | return [self autoPinEdgeToSuperviewEdge:edge withInset:inset relation:NSLayoutRelationEqual]; 261 | } 262 | 263 | /** 264 | Pins the given edge of the view to the same edge of its superview with an inset as a maximum or minimum. 265 | 266 | @param edge The edge of this view and its superview to pin. 267 | @param inset The amount to inset this view's edge from the superview's edge. 268 | @param relation Whether the inset should be at least, at most, or exactly equal to the given value. 269 | @return The constraint added. 270 | */ 271 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation 272 | { 273 | self.translatesAutoresizingMaskIntoConstraints = NO; 274 | ALView *superview = self.superview; 275 | NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); 276 | if (edge == ALEdgeBottom || edge == ALEdgeRight || edge == ALEdgeTrailing) { 277 | // The bottom, right, and trailing insets (and relations, if an inequality) are inverted to become offsets 278 | inset = -inset; 279 | if (relation == NSLayoutRelationLessThanOrEqual) { 280 | relation = NSLayoutRelationGreaterThanOrEqual; 281 | } else if (relation == NSLayoutRelationGreaterThanOrEqual) { 282 | relation = NSLayoutRelationLessThanOrEqual; 283 | } 284 | } 285 | return [self autoPinEdge:edge toEdge:edge ofView:superview withOffset:inset relation:relation]; 286 | } 287 | 288 | /** 289 | Pins the edges of the view to the edges of its superview with the given edge insets. 290 | The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint. 291 | 292 | @param insets The insets for this view's edges from its superview's edges. 293 | @return An array of constraints added. 294 | */ 295 | - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets 296 | { 297 | NSMutableArray *constraints = [NSMutableArray new]; 298 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]]; 299 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]]; 300 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]]; 301 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]]; 302 | return constraints; 303 | } 304 | 305 | /** 306 | Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge. 307 | The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint. 308 | 309 | @param insets The insets for this view's edges from its superview's edges. The inset corresponding to the excluded edge 310 | will be ignored. 311 | @param edge The edge of this view to exclude in pinning to its superview; this method will not apply any constraint to it. 312 | @return An array of constraints added. 313 | */ 314 | - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge 315 | { 316 | NSMutableArray *constraints = [NSMutableArray new]; 317 | if (edge != ALEdgeTop) { 318 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]]; 319 | } 320 | if (edge != ALEdgeLeading && edge != ALEdgeLeft) { 321 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]]; 322 | } 323 | if (edge != ALEdgeBottom) { 324 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]]; 325 | } 326 | if (edge != ALEdgeTrailing && edge != ALEdgeRight) { 327 | [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]]; 328 | } 329 | return constraints; 330 | } 331 | 332 | #if __PureLayout_MinBaseSDK_iOS8 333 | 334 | /** 335 | Pins the given edge of the view to the corresponding margin of its superview. 336 | 337 | @param edge The edge of this view to pin to the corresponding margin of its superview. 338 | @return The constraint added. 339 | */ 340 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge 341 | { 342 | return [self autoPinEdgeToSuperviewMargin:edge relation:NSLayoutRelationEqual]; 343 | } 344 | 345 | /** 346 | Pins the given edge of the view to the corresponding margin of its superview as a maximum or minimum. 347 | 348 | @param edge The edge of this view to pin to the corresponding margin of its superview. 349 | @param relation Whether the edge should be inset by at least, at most, or exactly the superview's margin. 350 | @return The constraint added. 351 | */ 352 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge relation:(NSLayoutRelation)relation 353 | { 354 | self.translatesAutoresizingMaskIntoConstraints = NO; 355 | ALView *superview = self.superview; 356 | NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); 357 | if (edge == ALEdgeBottom || edge == ALEdgeRight || edge == ALEdgeTrailing) { 358 | // The bottom, right, and trailing relations are inverted 359 | if (relation == NSLayoutRelationLessThanOrEqual) { 360 | relation = NSLayoutRelationGreaterThanOrEqual; 361 | } else if (relation == NSLayoutRelationGreaterThanOrEqual) { 362 | relation = NSLayoutRelationLessThanOrEqual; 363 | } 364 | } 365 | ALMargin margin = [NSLayoutConstraint al_marginForEdge:edge]; 366 | return [self autoConstrainAttribute:(ALAttribute)edge toAttribute:(ALAttribute)margin ofView:superview withOffset:0.0 relation:relation]; 367 | } 368 | 369 | /** 370 | Pins the edges of the view to the margins of its superview. 371 | 372 | @return An array of constraints added. 373 | */ 374 | - (NSArray *)autoPinEdgesToSuperviewMargins 375 | { 376 | NSMutableArray *constraints = [NSMutableArray new]; 377 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]]; 378 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]]; 379 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]]; 380 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]]; 381 | return constraints; 382 | } 383 | 384 | /** 385 | Pins 3 of the 4 edges of the view to the margins of its superview, excluding one edge. 386 | 387 | @param edge The edge of this view to exclude in pinning to its superview; this method will not apply any constraint to it. 388 | @return An array of constraints added. 389 | */ 390 | - (NSArray *)autoPinEdgesToSuperviewMarginsExcludingEdge:(ALEdge)edge 391 | { 392 | NSMutableArray *constraints = [NSMutableArray new]; 393 | if (edge != ALEdgeTop) { 394 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]]; 395 | } 396 | if (edge != ALEdgeLeading && edge != ALEdgeLeft) { 397 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]]; 398 | } 399 | if (edge != ALEdgeBottom) { 400 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]]; 401 | } 402 | if (edge != ALEdgeTrailing && edge != ALEdgeRight) { 403 | [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]]; 404 | } 405 | return constraints; 406 | } 407 | 408 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 409 | 410 | 411 | #pragma mark Pin Edges 412 | 413 | /** 414 | Pins an edge of the view to a given edge of another view. 415 | 416 | @param edge The edge of this view to pin. 417 | @param toEdge The edge of the other view to pin to. 418 | @param otherView The other view to pin to. Must be in the same view hierarchy as this view. 419 | @return The constraint added. 420 | */ 421 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView 422 | { 423 | return [self autoPinEdge:edge toEdge:toEdge ofView:otherView withOffset:0.0]; 424 | } 425 | 426 | /** 427 | Pins an edge of the view to a given edge of another view with an offset. 428 | 429 | @param edge The edge of this view to pin. 430 | @param toEdge The edge of the other view to pin to. 431 | @param otherView The other view to pin to. Must be in the same view hierarchy as this view. 432 | @param offset The offset between the edge of this view and the edge of the other view. 433 | @return The constraint added. 434 | */ 435 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset 436 | { 437 | return [self autoPinEdge:edge toEdge:toEdge ofView:otherView withOffset:offset relation:NSLayoutRelationEqual]; 438 | } 439 | 440 | /** 441 | Pins an edge of the view to a given edge of another view with an offset as a maximum or minimum. 442 | 443 | @param edge The edge of this view to pin. 444 | @param toEdge The edge of the other view to pin to. 445 | @param otherView The other view to pin to. Must be in the same view hierarchy as this view. 446 | @param offset The offset between the edge of this view and the edge of the other view. 447 | @param relation Whether the offset should be at least, at most, or exactly equal to the given value. 448 | @return The constraint added. 449 | */ 450 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation 451 | { 452 | return [self autoConstrainAttribute:(ALAttribute)edge toAttribute:(ALAttribute)toEdge ofView:otherView withOffset:offset relation:relation]; 453 | } 454 | 455 | 456 | #pragma mark Align Axes 457 | 458 | /** 459 | Aligns an axis of the view to the same axis of another view. 460 | 461 | @param axis The axis of this view and the other view to align. 462 | @param otherView The other view to align to. Must be in the same view hierarchy as this view. 463 | @return The constraint added. 464 | */ 465 | - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView 466 | { 467 | return [self autoAlignAxis:axis toSameAxisOfView:otherView withOffset:0.0]; 468 | } 469 | 470 | /** 471 | Aligns an axis of the view to the same axis of another view with an offset. 472 | 473 | @param axis The axis of this view and the other view to align. 474 | @param otherView The other view to align to. Must be in the same view hierarchy as this view. 475 | @param offset The offset between the axis of this view and the axis of the other view. 476 | @return The constraint added. 477 | */ 478 | - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView withOffset:(CGFloat)offset 479 | { 480 | return [self autoConstrainAttribute:(ALAttribute)axis toAttribute:(ALAttribute)axis ofView:otherView withOffset:offset]; 481 | } 482 | 483 | 484 | #pragma mark Match Dimensions 485 | 486 | /** 487 | Matches a dimension of the view to a given dimension of another view. 488 | 489 | @param dimension The dimension of this view to pin. 490 | @param toDimension The dimension of the other view to pin to. 491 | @param otherView The other view to match to. Must be in the same view hierarchy as this view. 492 | @return The constraint added. 493 | */ 494 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView 495 | { 496 | return [self autoMatchDimension:dimension toDimension:toDimension ofView:otherView withOffset:0.0]; 497 | } 498 | 499 | /** 500 | Matches a dimension of the view to a given dimension of another view with an offset. 501 | 502 | @param dimension The dimension of this view to pin. 503 | @param toDimension The dimension of the other view to pin to. 504 | @param otherView The other view to match to. Must be in the same view hierarchy as this view. 505 | @param offset The offset between the dimension of this view and the dimension of the other view. 506 | @return The constraint added. 507 | */ 508 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset 509 | { 510 | return [self autoMatchDimension:dimension toDimension:toDimension ofView:otherView withOffset:offset relation:NSLayoutRelationEqual]; 511 | } 512 | 513 | /** 514 | Matches a dimension of the view to a given dimension of another view with an offset as a maximum or minimum. 515 | 516 | @param dimension The dimension of this view to pin. 517 | @param toDimension The dimension of the other view to pin to. 518 | @param otherView The other view to match to. Must be in the same view hierarchy as this view. 519 | @param offset The offset between the dimension of this view and the dimension of the other view. 520 | @param relation Whether the offset should be at least, at most, or exactly equal to the given value. 521 | @return The constraint added. 522 | */ 523 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation 524 | { 525 | return [self autoConstrainAttribute:(ALAttribute)dimension toAttribute:(ALAttribute)toDimension ofView:otherView withOffset:offset relation:relation]; 526 | } 527 | 528 | /** 529 | Matches a dimension of the view to a multiple of a given dimension of another view. 530 | 531 | @param dimension The dimension of this view to pin. 532 | @param toDimension The dimension of the other view to pin to. 533 | @param otherView The other view to match to. Must be in the same view hierarchy as this view. 534 | @param multiplier The multiple of the other view's given dimension that this view's given dimension should be. 535 | @return The constraint added. 536 | */ 537 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier 538 | { 539 | return [self autoMatchDimension:dimension toDimension:toDimension ofView:otherView withMultiplier:multiplier relation:NSLayoutRelationEqual]; 540 | } 541 | 542 | /** 543 | Matches a dimension of the view to a multiple of a given dimension of another view as a maximum or minimum. 544 | 545 | @param dimension The dimension of this view to pin. 546 | @param toDimension The dimension of the other view to pin to. 547 | @param otherView The other view to match to. Must be in the same view hierarchy as this view. 548 | @param multiplier The multiple of the other view's given dimension that this view's given dimension should be. 549 | @param relation Whether the multiple should be at least, at most, or exactly equal to the given value. 550 | @return The constraint added. 551 | */ 552 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation 553 | { 554 | return [self autoConstrainAttribute:(ALAttribute)dimension toAttribute:(ALAttribute)toDimension ofView:otherView withMultiplier:multiplier relation:relation]; 555 | } 556 | 557 | 558 | #pragma mark Set Dimensions 559 | 560 | /** 561 | Sets the view to a specific size. 562 | 563 | @param size The size to set this view's dimensions to. 564 | @return An array of constraints added. 565 | */ 566 | - (NSArray *)autoSetDimensionsToSize:(CGSize)size 567 | { 568 | NSMutableArray *constraints = [NSMutableArray new]; 569 | [constraints addObject:[self autoSetDimension:ALDimensionWidth toSize:size.width]]; 570 | [constraints addObject:[self autoSetDimension:ALDimensionHeight toSize:size.height]]; 571 | return constraints; 572 | } 573 | 574 | /** 575 | Sets the given dimension of the view to a specific size. 576 | 577 | @param dimension The dimension of this view to set. 578 | @param size The size to set the given dimension to. 579 | @return The constraint added. 580 | */ 581 | - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size 582 | { 583 | return [self autoSetDimension:dimension toSize:size relation:NSLayoutRelationEqual]; 584 | } 585 | 586 | /** 587 | Sets the given dimension of the view to a specific size as a maximum or minimum. 588 | 589 | @param dimension The dimension of this view to set. 590 | @param size The size to set the given dimension to. 591 | @param relation Whether the size should be at least, at most, or exactly equal to the given value. 592 | @return The constraint added. 593 | */ 594 | - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size relation:(NSLayoutRelation)relation 595 | { 596 | self.translatesAutoresizingMaskIntoConstraints = NO; 597 | NSLayoutAttribute layoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:(ALAttribute)dimension]; 598 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:layoutAttribute relatedBy:relation toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:size]; 599 | [constraint autoInstall]; 600 | return constraint; 601 | } 602 | 603 | 604 | #pragma mark Set Content Compression Resistance & Hugging 605 | 606 | /** 607 | Sets the priority of content compression resistance for an axis. 608 | NOTE: This method must be called from within the block passed into the method +[autoSetPriority:forConstraints:] 609 | 610 | @param axis The axis to set the content compression resistance priority for. 611 | */ 612 | - (void)autoSetContentCompressionResistancePriorityForAxis:(ALAxis)axis 613 | { 614 | NSAssert(_al_isExecutingPriorityConstraintsBlock, @"%@ should only be called from within the block passed into the method +[autoSetPriority:forConstraints:]", NSStringFromSelector(_cmd)); 615 | if (_al_isExecutingPriorityConstraintsBlock) { 616 | self.translatesAutoresizingMaskIntoConstraints = NO; 617 | ALLayoutConstraintAxis constraintAxis = [NSLayoutConstraint al_constraintAxisForAxis:axis]; 618 | #if TARGET_OS_IPHONE 619 | [self setContentCompressionResistancePriority:_al_globalConstraintPriority forAxis:constraintAxis]; 620 | #else 621 | [self setContentCompressionResistancePriority:_al_globalConstraintPriority forOrientation:constraintAxis]; 622 | #endif /* TARGET_OS_IPHONE */ 623 | } 624 | } 625 | 626 | /** 627 | Sets the priority of content hugging for an axis. 628 | NOTE: This method must be called from within the block passed into the method +[autoSetPriority:forConstraints:] 629 | 630 | @param axis The axis to set the content hugging priority for. 631 | */ 632 | - (void)autoSetContentHuggingPriorityForAxis:(ALAxis)axis 633 | { 634 | NSAssert(_al_isExecutingPriorityConstraintsBlock, @"%@ should only be called from within the block passed into the method +[autoSetPriority:forConstraints:]", NSStringFromSelector(_cmd)); 635 | if (_al_isExecutingPriorityConstraintsBlock) { 636 | self.translatesAutoresizingMaskIntoConstraints = NO; 637 | ALLayoutConstraintAxis constraintAxis = [NSLayoutConstraint al_constraintAxisForAxis:axis]; 638 | #if TARGET_OS_IPHONE 639 | [self setContentHuggingPriority:_al_globalConstraintPriority forAxis:constraintAxis]; 640 | #else 641 | [self setContentHuggingPriority:_al_globalConstraintPriority forOrientation:constraintAxis]; 642 | #endif /* TARGET_OS_IPHONE */ 643 | } 644 | } 645 | 646 | 647 | #pragma mark Constrain Any Attributes 648 | 649 | /** 650 | Constrains an attribute of the view to a given attribute of another view. 651 | This method can be used to constrain different types of attributes across two views. 652 | 653 | @param attribute Any attribute of this view to constrain. 654 | @param toAttribute Any attribute of the other view to constrain to. 655 | @param otherView The other view to constrain to. Must be in the same view hierarchy as this view. 656 | @return The constraint added. 657 | */ 658 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView 659 | { 660 | return [self autoConstrainAttribute:attribute toAttribute:toAttribute ofView:otherView withOffset:0.0]; 661 | } 662 | 663 | /** 664 | Constrains an attribute of the view to a given attribute of another view with an offset. 665 | This method can be used to constrain different types of attributes across two views. 666 | 667 | @param attribute Any attribute of this view to constrain. 668 | @param toAttribute Any attribute of the other view to constrain to. 669 | @param otherView The other view to constrain to. Must be in the same view hierarchy as this view. 670 | @param offset The offset between the attribute of this view and the attribute of the other view. 671 | @return The constraint added. 672 | */ 673 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset 674 | { 675 | return [self autoConstrainAttribute:attribute toAttribute:toAttribute ofView:otherView withOffset:offset relation:NSLayoutRelationEqual]; 676 | } 677 | 678 | /** 679 | Constrains an attribute of the view to a given attribute of another view with an offset as a maximum or minimum. 680 | This method can be used to constrain different types of attributes across two views. 681 | 682 | @param attribute Any attribute of this view to constrain. 683 | @param toAttribute Any attribute of the other view to constrain to. 684 | @param otherView The other view to constrain to. Must be in the same view hierarchy as this view. 685 | @param offset The offset between the attribute of this view and the attribute of the other view. 686 | @param relation Whether the offset should be at least, at most, or exactly equal to the given value. 687 | @return The constraint added. 688 | */ 689 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation 690 | { 691 | self.translatesAutoresizingMaskIntoConstraints = NO; 692 | NSLayoutAttribute layoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:attribute]; 693 | NSLayoutAttribute toLayoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:toAttribute]; 694 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:layoutAttribute relatedBy:relation toItem:otherView attribute:toLayoutAttribute multiplier:1.0 constant:offset]; 695 | [constraint autoInstall]; 696 | return constraint; 697 | } 698 | 699 | /** 700 | Constrains an attribute of the view to a given attribute of another view with a multiplier. 701 | This method can be used to constrain different types of attributes across two views. 702 | 703 | @param attribute Any attribute of this view to constrain. 704 | @param toAttribute Any attribute of the other view to constrain to. 705 | @param otherView The other view to constrain to. Must be in the same view hierarchy as this view. 706 | @param multiplier The multiplier between the attribute of this view and the attribute of the other view. 707 | @return The constraint added. 708 | */ 709 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier 710 | { 711 | return [self autoConstrainAttribute:attribute toAttribute:toAttribute ofView:otherView withMultiplier:multiplier relation:NSLayoutRelationEqual]; 712 | } 713 | 714 | /** 715 | Constrains an attribute of the view to a given attribute of another view with a multiplier as a maximum or minimum. 716 | This method can be used to constrain different types of attributes across two views. 717 | 718 | @param attribute Any attribute of this view to constrain. 719 | @param toAttribute Any attribute of the other view to constrain to. 720 | @param otherView The other view to constrain to. Must be in the same view hierarchy as this view. 721 | @param multiplier The multiplier between the attribute of this view and the attribute of the other view. 722 | @param relation Whether the multiplier should be at least, at most, or exactly equal to the given value. 723 | @return The constraint added. 724 | */ 725 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation 726 | { 727 | self.translatesAutoresizingMaskIntoConstraints = NO; 728 | NSLayoutAttribute layoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:attribute]; 729 | NSLayoutAttribute toLayoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:toAttribute]; 730 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:layoutAttribute relatedBy:relation toItem:otherView attribute:toLayoutAttribute multiplier:multiplier constant:0.0]; 731 | [constraint autoInstall]; 732 | return constraint; 733 | } 734 | 735 | 736 | #pragma mark Pin to Layout Guides 737 | 738 | #if TARGET_OS_IPHONE 739 | 740 | /** 741 | Pins the top edge of the view to the top layout guide of the given view controller with an inset. 742 | For compatibility with iOS 6 (where layout guides do not exist), this method will simply pin the top edge of 743 | the view to the top edge of the given view controller's view with an inset. 744 | 745 | @param viewController The view controller whose topLayoutGuide should be used to pin to. 746 | @param inset The amount to inset this view's top edge from the layout guide. 747 | @return The constraint added. 748 | */ 749 | - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset 750 | { 751 | return [self autoPinToTopLayoutGuideOfViewController:viewController withInset:inset relation:NSLayoutRelationEqual]; 752 | } 753 | 754 | - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation 755 | { 756 | if (__PureLayout_MinSysVer_iOS7) { 757 | self.translatesAutoresizingMaskIntoConstraints = NO; 758 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:relation toItem:viewController.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:inset]; 759 | [viewController.view al_addConstraint:constraint]; // Can't use autoInstall because the layout guide is not a view 760 | return constraint; 761 | } else { 762 | // iOS 6 fallback 763 | return [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:viewController.view withOffset:inset relation:relation]; 764 | } 765 | } 766 | 767 | /** 768 | Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset. 769 | For compatibility with iOS 6 (where layout guides do not exist), this method will simply pin the bottom edge of 770 | the view to the bottom edge of the given view controller's view with an inset. 771 | 772 | @param viewController The view controller whose bottomLayoutGuide should be used to pin to. 773 | @param inset The amount to inset this view's bottom edge from the layout guide. 774 | @return The constraint added. 775 | */ 776 | - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset 777 | { 778 | return [self autoPinToBottomLayoutGuideOfViewController:viewController withInset:inset relation:NSLayoutRelationEqual]; 779 | } 780 | 781 | - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation 782 | { 783 | // The bottom inset (and relation, if an inequality) is inverted to become an offset 784 | inset = -inset; 785 | if (relation == NSLayoutRelationLessThanOrEqual) { 786 | relation = NSLayoutRelationGreaterThanOrEqual; 787 | } else if (relation == NSLayoutRelationGreaterThanOrEqual) { 788 | relation = NSLayoutRelationLessThanOrEqual; 789 | } 790 | if (__PureLayout_MinSysVer_iOS7) { 791 | self.translatesAutoresizingMaskIntoConstraints = NO; 792 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:relation toItem:viewController.bottomLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:inset]; 793 | [viewController.view al_addConstraint:constraint]; // Can't use autoInstall because the layout guide is not a view 794 | return constraint; 795 | } else { 796 | // iOS 6 fallback 797 | return [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:viewController.view withOffset:inset relation:relation]; 798 | } 799 | } 800 | 801 | #endif /* TARGET_OS_IPHONE */ 802 | 803 | 804 | #pragma mark Deprecated Methods 805 | 806 | /** 807 | DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 808 | Removes all explicit constraints that affect the view. 809 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 810 | It is not recommended to use this method to "reset" a view for reuse in a different way with new constraints. Create a new view instead. 811 | NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove. 812 | */ 813 | - (void)autoRemoveConstraintsAffectingView 814 | { 815 | [self autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:NO]; 816 | } 817 | 818 | /** 819 | DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 820 | Removes all constraints that affect the view, optionally including implicit constraints. 821 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 822 | It is not recommended to use this method to "reset" a view for reuse in a different way with new constraints. Create a new view instead. 823 | NOTE: Implicit constraints are auto-generated lower priority constraints (such as those that attempt to keep a view at 824 | its intrinsic content size by hugging its content & resisting compression), and you usually do not want to remove these. 825 | 826 | @param shouldRemoveImplicitConstraints Whether implicit constraints should be removed or skipped. 827 | */ 828 | - (void)autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints 829 | { 830 | NSMutableArray *constraintsToRemove = [NSMutableArray new]; 831 | ALView *startView = self; 832 | do { 833 | for (NSLayoutConstraint *constraint in startView.constraints) { 834 | BOOL isImplicitConstraint = [NSStringFromClass([constraint class]) isEqualToString:@"NSContentSizeLayoutConstraint"]; 835 | if (shouldRemoveImplicitConstraints || !isImplicitConstraint) { 836 | if (constraint.firstItem == self || constraint.secondItem == self) { 837 | [constraintsToRemove addObject:constraint]; 838 | } 839 | } 840 | } 841 | startView = startView.superview; 842 | } while (startView); 843 | [constraintsToRemove autoRemoveConstraints]; 844 | } 845 | 846 | /** 847 | DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 848 | Recursively removes all explicit constraints that affect the view and its subviews. 849 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 850 | It is not recommended to use this method to "reset" views for reuse in a different way with new constraints. Create a new view instead. 851 | NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove. 852 | */ 853 | - (void)autoRemoveConstraintsAffectingViewAndSubviews 854 | { 855 | [self autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:NO]; 856 | } 857 | 858 | /** 859 | DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints. 860 | Recursively removes all constraints that affect the view and its subviews, optionally including implicit constraints. 861 | WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method. 862 | It is not recommended to use this method to "reset" views for reuse in a different way with new constraints. Create a new view instead. 863 | NOTE: Implicit constraints are auto-generated lower priority constraints (such as those that attempt to keep a view at 864 | its intrinsic content size by hugging its content & resisting compression), and you usually do not want to remove these. 865 | 866 | @param shouldRemoveImplicitConstraints Whether implicit constraints should be removed or skipped. 867 | */ 868 | - (void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints 869 | { 870 | [self autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:shouldRemoveImplicitConstraints]; 871 | for (ALView *subview in self.subviews) { 872 | [subview autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:shouldRemoveImplicitConstraints]; 873 | } 874 | } 875 | 876 | 877 | #pragma mark Internal Methods 878 | 879 | /** 880 | Applies the global constraint priority and identifier to the given constraint. 881 | This should be done before installing all constraints. 882 | 883 | @param constraint The constraint to set the global priority and identifier on. 884 | */ 885 | + (void)al_applyGlobalStateToConstraint:(NSLayoutConstraint *)constraint 886 | { 887 | constraint.priority = _al_globalConstraintPriority; 888 | #if __PureLayout_MinBaseSDK_iOS8 889 | [constraint autoIdentify:_al_globalConstraintIdentifier]; 890 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 891 | } 892 | 893 | /** 894 | Adds the given constraint to this view after applying the global state to the constraint. 895 | NOTE: This method is compatible with all versions of iOS, and should be used for older versions before the active 896 | property on NSLayoutConstraint was introduced. 897 | 898 | This method should be the only one that calls the UIView/NSView addConstraint: method directly. 899 | 900 | @param constraint The constraint to set the global priority on and then add to this view. 901 | */ 902 | - (void)al_addConstraint:(NSLayoutConstraint *)constraint 903 | { 904 | [ALView al_applyGlobalStateToConstraint:constraint]; 905 | if (![ALView al_preventAutomaticConstraintInstallation]) { 906 | [self addConstraint:constraint]; 907 | } 908 | } 909 | 910 | /** 911 | Returns the common superview for this view and the given other view. 912 | Raises an exception if this view and the other view do not share a common superview. 913 | 914 | @return The common superview for the two views. 915 | */ 916 | - (ALView *)al_commonSuperviewWithView:(ALView *)otherView 917 | { 918 | ALView *commonSuperview = nil; 919 | ALView *startView = self; 920 | do { 921 | #if TARGET_OS_IPHONE 922 | if ([otherView isDescendantOfView:startView]) { 923 | commonSuperview = startView; 924 | } 925 | #else 926 | if ([otherView isDescendantOf:startView]) { 927 | commonSuperview = startView; 928 | } 929 | #endif /* TARGET_OS_IPHONE */ 930 | startView = startView.superview; 931 | } while (startView && !commonSuperview); 932 | NSAssert(commonSuperview, @"Can't constrain two views that do not share a common superview. Make sure that both views have been added into the same view hierarchy."); 933 | return commonSuperview; 934 | } 935 | 936 | /** 937 | Aligns this view to another view with an alignment attribute. 938 | 939 | @param attribute The attribute to use to align the two views. 940 | @param otherView The other view to align to. 941 | @param axis The axis along which the views are distributed, used to validate the alignment attribute. 942 | @return The constraint added. 943 | */ 944 | - (NSLayoutConstraint *)al_alignAttribute:(ALAttribute)attribute toView:(ALView *)otherView forAxis:(ALAxis)axis 945 | { 946 | NSLayoutConstraint *constraint = nil; 947 | switch (attribute) { 948 | case ALAttributeVertical: 949 | NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeVertical."); 950 | constraint = [self autoAlignAxis:ALAxisVertical toSameAxisOfView:otherView]; 951 | break; 952 | case ALAttributeHorizontal: 953 | NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeHorizontal."); 954 | constraint = [self autoAlignAxis:ALAxisHorizontal toSameAxisOfView:otherView]; 955 | break; 956 | case ALAttributeBaseline: // same value as ALAttributeLastBaseline 957 | NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeBaseline."); 958 | constraint = [self autoAlignAxis:ALAxisBaseline toSameAxisOfView:otherView]; 959 | break; 960 | #if __PureLayout_MinBaseSDK_iOS8 961 | case ALAttributeFirstBaseline: 962 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALAttributeFirstBaseline is only supported on iOS 8.0 or higher."); 963 | NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeFirstBaseline."); 964 | constraint = [self autoAlignAxis:ALAxisFirstBaseline toSameAxisOfView:otherView]; 965 | break; 966 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 967 | case ALAttributeTop: 968 | NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeTop."); 969 | constraint = [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:otherView]; 970 | break; 971 | case ALAttributeLeft: 972 | NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeLeft."); 973 | constraint = [self autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:otherView]; 974 | break; 975 | case ALAttributeBottom: 976 | NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeBottom."); 977 | constraint = [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:otherView]; 978 | break; 979 | case ALAttributeRight: 980 | NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeRight."); 981 | constraint = [self autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:otherView]; 982 | break; 983 | case ALAttributeLeading: 984 | NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeLeading."); 985 | constraint = [self autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:otherView]; 986 | break; 987 | case ALAttributeTrailing: 988 | NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeTrailing."); 989 | constraint = [self autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:otherView]; 990 | break; 991 | default: 992 | NSAssert(nil, @"Unsupported alignment option."); 993 | break; 994 | } 995 | return constraint; 996 | } 997 | 998 | @end 999 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/NSArray+PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+PureLayout.h 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2012 Richard Turton 7 | // Copyright (c) 2013-2014 Tyler Fox 8 | // 9 | // This code is distributed under the terms and conditions of the MIT license. 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to 13 | // deal in the Software without restriction, including without limitation the 14 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 15 | // sell copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 27 | // IN THE SOFTWARE. 28 | // 29 | 30 | #import "PureLayoutDefines.h" 31 | 32 | 33 | #pragma mark - NSArray+PureLayout 34 | 35 | /** 36 | A category on NSArray that provides a simple yet powerful interface to: 37 | - Manage an array of Auto Layout constraints 38 | - Apply constraints to an array of views 39 | */ 40 | @interface NSArray (PureLayout) 41 | 42 | 43 | #pragma mark Array of Constraints 44 | 45 | /** Activates the constraints in this array. */ 46 | - (void)autoInstallConstraints; 47 | 48 | /** Deactivates the constraints in this array. */ 49 | - (void)autoRemoveConstraints; 50 | 51 | #if __PureLayout_MinBaseSDK_iOS8 52 | 53 | /** Sets the string as the identifier for the constraints in this array. Available in iOS 7.0 and later. */ 54 | - (instancetype)autoIdentifyConstraints:(NSString *)identifer; 55 | 56 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 57 | 58 | 59 | #pragma mark Array of Views 60 | 61 | /** Aligns views in this array to one another along a given edge. */ 62 | - (NSArray *)autoAlignViewsToEdge:(ALEdge)edge; 63 | 64 | /** Aligns views in this array to one another along a given axis. */ 65 | - (NSArray *)autoAlignViewsToAxis:(ALAxis)axis; 66 | 67 | /** Matches a given dimension of all the views in this array. */ 68 | - (NSArray *)autoMatchViewsDimension:(ALDimension)dimension; 69 | 70 | /** Sets the given dimension of all the views in this array to a given size. */ 71 | - (NSArray *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size; 72 | 73 | 74 | /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */ 75 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 76 | alignedTo:(ALAttribute)alignment 77 | withFixedSpacing:(CGFloat)spacing; 78 | 79 | /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them, with optional insets from the first and last views to their superview. */ 80 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 81 | alignedTo:(ALAttribute)alignment 82 | withFixedSpacing:(CGFloat)spacing 83 | insetSpacing:(BOOL)shouldSpaceInsets; 84 | 85 | /** Distributes the views in this array equally along the selected axis in their superview. Views will have spacing (fixed) between them, with optional insets from the first and last views to their superview, and optionally constrained to the same size in the dimension along the axis. */ 86 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 87 | alignedTo:(ALAttribute)alignment 88 | withFixedSpacing:(CGFloat)spacing 89 | insetSpacing:(BOOL)shouldSpaceInsets 90 | matchedSizes:(BOOL)shouldMatchSizes; 91 | 92 | 93 | /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */ 94 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 95 | alignedTo:(ALAttribute)alignment 96 | withFixedSize:(CGFloat)size; 97 | 98 | /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them, with optional insets from the first and last views to their superview. */ 99 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 100 | alignedTo:(ALAttribute)alignment 101 | withFixedSize:(CGFloat)size 102 | insetSpacing:(BOOL)shouldSpaceInsets; 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/NSArray+PureLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+PureLayout.m 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2012 Richard Turton 7 | // Copyright (c) 2013-2014 Tyler Fox 8 | // 9 | // This code is distributed under the terms and conditions of the MIT license. 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to 13 | // deal in the Software without restriction, including without limitation the 14 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 15 | // sell copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 27 | // IN THE SOFTWARE. 28 | // 29 | 30 | #import "NSArray+PureLayout.h" 31 | #import "ALView+PureLayout.h" 32 | #import "NSLayoutConstraint+PureLayout.h" 33 | #import "PureLayout+Internal.h" 34 | 35 | 36 | #pragma mark - NSArray+PureLayout 37 | 38 | @implementation NSArray (PureLayout) 39 | 40 | 41 | #pragma mark Array of Constraints 42 | 43 | /** 44 | Activates the constraints in this array. 45 | */ 46 | - (void)autoInstallConstraints 47 | { 48 | for (id object in self) { 49 | if ([object isKindOfClass:[NSLayoutConstraint class]]) { 50 | [((NSLayoutConstraint *)object) autoInstall]; 51 | } 52 | } 53 | } 54 | 55 | /** 56 | Deactivates the constraints in this array. 57 | */ 58 | - (void)autoRemoveConstraints 59 | { 60 | for (id object in self) { 61 | if ([object isKindOfClass:[NSLayoutConstraint class]]) { 62 | [((NSLayoutConstraint *)object) autoRemove]; 63 | } 64 | } 65 | } 66 | 67 | #if __PureLayout_MinBaseSDK_iOS8 68 | 69 | /** 70 | Sets the string as the identifier for the constraints in this array. 71 | The identifer will be printed along with each constraint's description. 72 | This is helpful to document the constraints' purpose and aid in debugging. 73 | 74 | @param identifier A string used to identify the constraints in this array. 75 | @return This array. 76 | */ 77 | - (instancetype)autoIdentifyConstraints:(NSString *)identifer 78 | { 79 | for (id object in self) { 80 | if ([object isKindOfClass:[NSLayoutConstraint class]]) { 81 | [((NSLayoutConstraint *)object) autoIdentify:identifer]; 82 | } 83 | } 84 | return self; 85 | } 86 | 87 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 88 | 89 | 90 | #pragma mark Array of Views 91 | 92 | /** 93 | Aligns views in this array to one another along a given edge. 94 | Note: This array must contain at least 2 views, and all views must share a common superview. 95 | 96 | @param edge The edge to which the subviews will be aligned. 97 | @return An array of constraints added. 98 | */ 99 | - (NSArray *)autoAlignViewsToEdge:(ALEdge)edge 100 | { 101 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views."); 102 | NSMutableArray *constraints = [NSMutableArray new]; 103 | ALView *previousView = nil; 104 | for (id object in self) { 105 | if ([object isKindOfClass:[ALView class]]) { 106 | ALView *view = (ALView *)object; 107 | view.translatesAutoresizingMaskIntoConstraints = NO; 108 | if (previousView) { 109 | [constraints addObject:[view autoPinEdge:edge toEdge:edge ofView:previousView]]; 110 | } 111 | previousView = view; 112 | } 113 | } 114 | return constraints; 115 | } 116 | 117 | /** 118 | Aligns views in this array to one another along a given axis. 119 | Note: This array must contain at least 2 views, and all views must share a common superview. 120 | 121 | @param axis The axis to which to subviews will be aligned. 122 | @return An array of constraints added. 123 | */ 124 | - (NSArray *)autoAlignViewsToAxis:(ALAxis)axis 125 | { 126 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views."); 127 | NSMutableArray *constraints = [NSMutableArray new]; 128 | ALView *previousView = nil; 129 | for (id object in self) { 130 | if ([object isKindOfClass:[ALView class]]) { 131 | ALView *view = (ALView *)object; 132 | view.translatesAutoresizingMaskIntoConstraints = NO; 133 | if (previousView) { 134 | [constraints addObject:[view autoAlignAxis:axis toSameAxisOfView:previousView]]; 135 | } 136 | previousView = view; 137 | } 138 | } 139 | return constraints; 140 | } 141 | 142 | /** 143 | Matches a given dimension of all the views in this array. 144 | Note: This array must contain at least 2 views, and all views must share a common superview. 145 | 146 | @param dimension The dimension to match for all of the subviews. 147 | @return An array of constraints added. 148 | */ 149 | - (NSArray *)autoMatchViewsDimension:(ALDimension)dimension 150 | { 151 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views."); 152 | NSMutableArray *constraints = [NSMutableArray new]; 153 | ALView *previousView = nil; 154 | for (id object in self) { 155 | if ([object isKindOfClass:[ALView class]]) { 156 | ALView *view = (ALView *)object; 157 | view.translatesAutoresizingMaskIntoConstraints = NO; 158 | if (previousView) { 159 | [constraints addObject:[view autoMatchDimension:dimension toDimension:dimension ofView:previousView]]; 160 | } 161 | previousView = view; 162 | } 163 | } 164 | return constraints; 165 | } 166 | 167 | /** 168 | Sets the given dimension of all the views in this array to a given size. 169 | Note: This array must contain at least 1 view. 170 | 171 | @param dimension The dimension of each of the subviews to set. 172 | @param size The size to set the given dimension of each subview to. 173 | @return An array of constraints added. 174 | */ 175 | - (NSArray *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size 176 | { 177 | NSAssert([self al_containsMinimumNumberOfViews:1], @"This array must contain at least 1 view."); 178 | NSMutableArray *constraints = [NSMutableArray new]; 179 | for (id object in self) { 180 | if ([object isKindOfClass:[ALView class]]) { 181 | ALView *view = (ALView *)object; 182 | view.translatesAutoresizingMaskIntoConstraints = NO; 183 | [constraints addObject:[view autoSetDimension:dimension toSize:size]]; 184 | } 185 | } 186 | return constraints; 187 | } 188 | 189 | 190 | /** 191 | Distributes the views in this array equally along the selected axis in their superview. 192 | Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them, 193 | including from the first and last views to their superview. 194 | 195 | @param axis The axis along which to distribute the views. 196 | @param alignment The attribute to use to align all the views to one another. 197 | @param spacing The fixed amount of spacing between each subview, before the first subview and after the last subview. 198 | @return An array of constraints added. 199 | */ 200 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 201 | alignedTo:(ALAttribute)alignment 202 | withFixedSpacing:(CGFloat)spacing 203 | { 204 | return [self autoDistributeViewsAlongAxis:axis 205 | alignedTo:alignment 206 | withFixedSpacing:spacing 207 | insetSpacing:YES]; 208 | } 209 | 210 | /** 211 | Distributes the views in this array equally along the selected axis in their superview. 212 | Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. 213 | The first and last views can optionally be inset from their superview by the same amount of spacing as between views. 214 | 215 | @param axis The axis along which to distribute the views. 216 | @param alignment The attribute to use to align all the views to one another. 217 | @param spacing The fixed amount of spacing between each subview. 218 | @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview. 219 | @return An array of constraints added. 220 | */ 221 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 222 | alignedTo:(ALAttribute)alignment 223 | withFixedSpacing:(CGFloat)spacing 224 | insetSpacing:(BOOL)shouldSpaceInsets 225 | { 226 | return [self autoDistributeViewsAlongAxis:axis 227 | alignedTo:alignment 228 | withFixedSpacing:spacing 229 | insetSpacing:shouldSpaceInsets 230 | matchedSizes:YES]; 231 | } 232 | 233 | /** 234 | Distributes the views in this array equally along the selected axis in their superview. 235 | Views will have fixed spacing between them, and can optionally be constrained to the same size in the dimension along the axis. 236 | The first and last views can optionally be inset from their superview by the same amount of spacing as between views. 237 | 238 | @param axis The axis along which to distribute the views. 239 | @param alignment The attribute to use to align all the views to one another. 240 | @param spacing The fixed amount of spacing between each view. 241 | @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview. 242 | @param shouldMatchSizes Whether all views will be constrained to be the same size in the dimension along the axis. 243 | NOTE: All views must specify an intrinsic content size if passing NO, otherwise the layout will be ambiguous! 244 | @return An array of constraints added. 245 | */ 246 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 247 | alignedTo:(ALAttribute)alignment 248 | withFixedSpacing:(CGFloat)spacing 249 | insetSpacing:(BOOL)shouldSpaceInsets 250 | matchedSizes:(BOOL)shouldMatchSizes 251 | { 252 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views to distribute."); 253 | ALDimension matchedDimension; 254 | ALEdge firstEdge, lastEdge; 255 | switch (axis) { 256 | case ALAxisHorizontal: 257 | case ALAxisBaseline: // same value as ALAxisLastBaseline 258 | #if __PureLayout_MinBaseSDK_iOS8 259 | case ALAxisFirstBaseline: 260 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 261 | matchedDimension = ALDimensionWidth; 262 | firstEdge = ALEdgeLeading; 263 | lastEdge = ALEdgeTrailing; 264 | break; 265 | case ALAxisVertical: 266 | matchedDimension = ALDimensionHeight; 267 | firstEdge = ALEdgeTop; 268 | lastEdge = ALEdgeBottom; 269 | break; 270 | default: 271 | NSAssert(nil, @"Not a valid ALAxis."); 272 | return nil; 273 | } 274 | CGFloat leadingSpacing = shouldSpaceInsets ? spacing : 0.0; 275 | CGFloat trailingSpacing = shouldSpaceInsets ? spacing : 0.0; 276 | 277 | NSMutableArray *constraints = [NSMutableArray new]; 278 | ALView *previousView = nil; 279 | for (id object in self) { 280 | if ([object isKindOfClass:[ALView class]]) { 281 | ALView *view = (ALView *)object; 282 | view.translatesAutoresizingMaskIntoConstraints = NO; 283 | if (previousView) { 284 | // Second, Third, ... View 285 | [constraints addObject:[view autoPinEdge:firstEdge toEdge:lastEdge ofView:previousView withOffset:spacing]]; 286 | if (shouldMatchSizes) { 287 | [constraints addObject:[view autoMatchDimension:matchedDimension toDimension:matchedDimension ofView:previousView]]; 288 | } 289 | [constraints addObject:[view al_alignAttribute:alignment toView:previousView forAxis:axis]]; 290 | } 291 | else { 292 | // First view 293 | [constraints addObject:[view autoPinEdgeToSuperviewEdge:firstEdge withInset:leadingSpacing]]; 294 | } 295 | previousView = view; 296 | } 297 | } 298 | if (previousView) { 299 | // Last View 300 | [constraints addObject:[previousView autoPinEdgeToSuperviewEdge:lastEdge withInset:trailingSpacing]]; 301 | } 302 | return constraints; 303 | } 304 | 305 | /** 306 | Distributes the views in this array equally along the selected axis in their superview. 307 | Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them, 308 | including from the first and last views to their superview. 309 | 310 | @param axis The axis along which to distribute the views. 311 | @param alignment The attribute to use to align all the views to one another. 312 | @param size The fixed size of each view in the dimension along the given axis. 313 | @return An array of constraints added. 314 | */ 315 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 316 | alignedTo:(ALAttribute)alignment 317 | withFixedSize:(CGFloat)size 318 | { 319 | return [self autoDistributeViewsAlongAxis:axis 320 | alignedTo:alignment 321 | withFixedSize:size 322 | insetSpacing:YES]; 323 | } 324 | 325 | /** 326 | Distributes the views in this array equally along the selected axis in their superview. 327 | Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. 328 | The first and last views can optionally be inset from their superview by the same amount of spacing as between views. 329 | 330 | @param axis The axis along which to distribute the views. 331 | @param alignment The attribute to use to align all the views to one another. 332 | @param size The fixed size of each view in the dimension along the given axis. 333 | @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview. 334 | @return An array of constraints added. 335 | */ 336 | - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis 337 | alignedTo:(ALAttribute)alignment 338 | withFixedSize:(CGFloat)size 339 | insetSpacing:(BOOL)shouldSpaceInsets 340 | { 341 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views to distribute."); 342 | ALDimension fixedDimension; 343 | NSLayoutAttribute attribute; 344 | switch (axis) { 345 | case ALAxisHorizontal: 346 | case ALAxisBaseline: // same value as ALAxisLastBaseline 347 | #if __PureLayout_MinBaseSDK_iOS8 348 | case ALAxisFirstBaseline: 349 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 350 | fixedDimension = ALDimensionWidth; 351 | attribute = NSLayoutAttributeCenterX; 352 | break; 353 | case ALAxisVertical: 354 | fixedDimension = ALDimensionHeight; 355 | attribute = NSLayoutAttributeCenterY; 356 | break; 357 | default: 358 | NSAssert(nil, @"Not a valid ALAxis."); 359 | return nil; 360 | } 361 | BOOL isRightToLeftLanguage = [NSLocale characterDirectionForLanguage:[[NSBundle mainBundle] preferredLocalizations][0]] == NSLocaleLanguageDirectionRightToLeft; 362 | BOOL shouldFlipOrder = isRightToLeftLanguage && (axis != ALAxisVertical); // imitate the effect of leading/trailing when distributing horizontally 363 | 364 | NSMutableArray *constraints = [NSMutableArray new]; 365 | NSArray *views = [self al_copyViewsOnly]; 366 | NSUInteger numberOfViews = [views count]; 367 | ALView *commonSuperview = [views al_commonSuperviewOfViews]; 368 | ALView *previousView = nil; 369 | for (NSUInteger i = 0; i < numberOfViews; i++) { 370 | ALView *view = shouldFlipOrder ? views[numberOfViews - i - 1] : views[i]; 371 | view.translatesAutoresizingMaskIntoConstraints = NO; 372 | [constraints addObject:[view autoSetDimension:fixedDimension toSize:size]]; 373 | CGFloat multiplier, constant; 374 | if (shouldSpaceInsets) { 375 | multiplier = (i * 2.0 + 2.0) / (numberOfViews + 1.0); 376 | constant = (multiplier - 1.0) * size / 2.0; 377 | } else { 378 | multiplier = (i * 2.0) / (numberOfViews - 1.0); 379 | constant = (-multiplier + 1.0) * size / 2.0; 380 | } 381 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view attribute:attribute relatedBy:NSLayoutRelationEqual toItem:commonSuperview attribute:attribute multiplier:multiplier constant:constant]; 382 | [constraint autoInstall]; 383 | [constraints addObject:constraint]; 384 | if (previousView) { 385 | [constraints addObject:[view al_alignAttribute:alignment toView:previousView forAxis:axis]]; 386 | } 387 | previousView = view; 388 | } 389 | return constraints; 390 | } 391 | 392 | #pragma mark Internal Helper Methods 393 | 394 | /** 395 | Returns the common superview for the views in this array. 396 | Raises an exception if the views in this array do not share a common superview. 397 | 398 | @return The common superview for the views in this array. 399 | */ 400 | - (ALView *)al_commonSuperviewOfViews 401 | { 402 | ALView *commonSuperview = nil; 403 | ALView *previousView = nil; 404 | for (id object in self) { 405 | if ([object isKindOfClass:[ALView class]]) { 406 | ALView *view = (ALView *)object; 407 | if (previousView) { 408 | commonSuperview = [view al_commonSuperviewWithView:commonSuperview]; 409 | } else { 410 | commonSuperview = view; 411 | } 412 | previousView = view; 413 | } 414 | } 415 | NSAssert(commonSuperview, @"Can't constrain views that do not share a common superview. Make sure that all the views in this array have been added into the same view hierarchy."); 416 | return commonSuperview; 417 | } 418 | 419 | /** 420 | Determines whether this array contains a minimum number of views. 421 | 422 | @param minimumNumberOfViews The minimum number of views to check for. 423 | @return YES if this array contains at least the minimum number of views, NO otherwise. 424 | */ 425 | - (BOOL)al_containsMinimumNumberOfViews:(NSUInteger)minimumNumberOfViews 426 | { 427 | NSUInteger numberOfViews = 0; 428 | for (id object in self) { 429 | if ([object isKindOfClass:[ALView class]]) { 430 | numberOfViews++; 431 | if (numberOfViews >= minimumNumberOfViews) { 432 | return YES; 433 | } 434 | } 435 | } 436 | return numberOfViews >= minimumNumberOfViews; 437 | } 438 | 439 | /** 440 | Creates a copy of this array containing only the view objects in it. 441 | 442 | @return A new array containing only the views that are in this array. 443 | */ 444 | - (NSArray *)al_copyViewsOnly 445 | { 446 | NSMutableArray *viewsOnlyArray = [NSMutableArray arrayWithCapacity:[self count]]; 447 | for (id object in self) { 448 | if ([object isKindOfClass:[ALView class]]) { 449 | [viewsOnlyArray addObject:object]; 450 | } 451 | } 452 | return viewsOnlyArray; 453 | } 454 | 455 | @end 456 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/NSLayoutConstraint+PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSLayoutConstraint+PureLayout.h 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2013-2014 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #import "PureLayoutDefines.h" 30 | 31 | 32 | #pragma mark - NSLayoutConstraint+PureLayout 33 | 34 | /** 35 | A category on NSLayoutConstraint that allows constraints to be easily installed & removed. 36 | */ 37 | @interface NSLayoutConstraint (PureLayout) 38 | 39 | 40 | #pragma mark Install & Remove Constraints 41 | 42 | /** Activates the the constraint. */ 43 | - (void)autoInstall; 44 | 45 | /** Deactivates the constraint. */ 46 | - (void)autoRemove; 47 | 48 | 49 | #pragma mark Identify Constraints 50 | 51 | #if __PureLayout_MinBaseSDK_iOS8 52 | 53 | /** Sets the string as the identifier for this constraint. Available in iOS 7.0 and later. */ 54 | - (instancetype)autoIdentify:(NSString *)identifer; 55 | 56 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/NSLayoutConstraint+PureLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSLayoutConstraint+PureLayout.m 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2013-2014 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #import "NSLayoutConstraint+PureLayout.h" 30 | #import "ALView+PureLayout.h" 31 | #import "PureLayout+Internal.h" 32 | 33 | 34 | #pragma mark - NSLayoutConstraint+PureLayout 35 | 36 | @implementation NSLayoutConstraint (PureLayout) 37 | 38 | 39 | #pragma mark Installing & Removing Constraints 40 | 41 | /** 42 | Activates the constraint. 43 | */ 44 | - (void)autoInstall 45 | { 46 | #if __PureLayout_MinBaseSDK_iOS8 47 | if ([self respondsToSelector:@selector(setActive:)]) { 48 | [ALView al_applyGlobalStateToConstraint:self]; 49 | if (![ALView al_preventAutomaticConstraintInstallation]) { 50 | self.active = YES; 51 | } 52 | return; 53 | } 54 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 55 | 56 | NSAssert(self.firstItem || self.secondItem, @"Can't install a constraint with nil firstItem and secondItem."); 57 | if (self.firstItem) { 58 | if (self.secondItem) { 59 | NSAssert([self.firstItem isKindOfClass:[ALView class]] && [self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if both items are views."); 60 | ALView *commonSuperview = [self.firstItem al_commonSuperviewWithView:self.secondItem]; 61 | [commonSuperview al_addConstraint:self]; 62 | } else { 63 | NSAssert([self.firstItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view."); 64 | [self.firstItem al_addConstraint:self]; 65 | } 66 | } else { 67 | NSAssert([self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view."); 68 | [self.secondItem al_addConstraint:self]; 69 | } 70 | } 71 | 72 | /** 73 | Deactivates the constraint. 74 | */ 75 | - (void)autoRemove 76 | { 77 | #if __PureLayout_MinBaseSDK_iOS8 78 | if ([self respondsToSelector:@selector(setActive:)]) { 79 | self.active = NO; 80 | return; 81 | } 82 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 83 | 84 | if (self.secondItem) { 85 | ALView *commonSuperview = [self.firstItem al_commonSuperviewWithView:self.secondItem]; 86 | while (commonSuperview) { 87 | if ([commonSuperview.constraints containsObject:self]) { 88 | [commonSuperview removeConstraint:self]; 89 | return; 90 | } 91 | commonSuperview = commonSuperview.superview; 92 | } 93 | } 94 | else { 95 | [self.firstItem removeConstraint:self]; 96 | return; 97 | } 98 | NSAssert(nil, @"Failed to remove constraint: %@", self); 99 | } 100 | 101 | 102 | #pragma mark Identify Constraints 103 | 104 | #if __PureLayout_MinBaseSDK_iOS8 105 | 106 | /** 107 | Sets the string as the identifier for this constraint. 108 | The identifer will be printed along with the constraint's description. 109 | This is helpful to document a constraint's purpose and aid in debugging. 110 | 111 | @param identifier A string used to identify this constraint. 112 | @return This constraint. 113 | */ 114 | - (instancetype)autoIdentify:(NSString *)identifer 115 | { 116 | if ([self respondsToSelector:@selector(setIdentifier:)]) { 117 | self.identifier = identifer; 118 | } 119 | return self; 120 | } 121 | 122 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 123 | 124 | 125 | #pragma mark Internal Methods 126 | 127 | /** 128 | Returns the corresponding NSLayoutAttribute for the given ALAttribute. 129 | 130 | @return The layout attribute for the given ALAttribute. 131 | */ 132 | + (NSLayoutAttribute)al_layoutAttributeForAttribute:(ALAttribute)attribute 133 | { 134 | NSLayoutAttribute layoutAttribute = NSLayoutAttributeNotAnAttribute; 135 | switch (attribute) { 136 | case ALEdgeLeft: 137 | layoutAttribute = NSLayoutAttributeLeft; 138 | break; 139 | case ALEdgeRight: 140 | layoutAttribute = NSLayoutAttributeRight; 141 | break; 142 | case ALEdgeTop: 143 | layoutAttribute = NSLayoutAttributeTop; 144 | break; 145 | case ALEdgeBottom: 146 | layoutAttribute = NSLayoutAttributeBottom; 147 | break; 148 | case ALEdgeLeading: 149 | layoutAttribute = NSLayoutAttributeLeading; 150 | break; 151 | case ALEdgeTrailing: 152 | layoutAttribute = NSLayoutAttributeTrailing; 153 | break; 154 | case ALDimensionWidth: 155 | layoutAttribute = NSLayoutAttributeWidth; 156 | break; 157 | case ALDimensionHeight: 158 | layoutAttribute = NSLayoutAttributeHeight; 159 | break; 160 | case ALAxisVertical: 161 | layoutAttribute = NSLayoutAttributeCenterX; 162 | break; 163 | case ALAxisHorizontal: 164 | layoutAttribute = NSLayoutAttributeCenterY; 165 | break; 166 | case ALAxisBaseline: // same value as ALAxisLastBaseline 167 | layoutAttribute = NSLayoutAttributeBaseline; 168 | break; 169 | #if __PureLayout_MinBaseSDK_iOS8 170 | case ALAxisFirstBaseline: 171 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALAxisFirstBaseline is only supported on iOS 8.0 or higher."); 172 | layoutAttribute = NSLayoutAttributeFirstBaseline; 173 | break; 174 | case ALMarginLeft: 175 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALEdgeLeftMargin is only supported on iOS 8.0 or higher."); 176 | layoutAttribute = NSLayoutAttributeLeftMargin; 177 | break; 178 | case ALMarginRight: 179 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALEdgeRightMargin is only supported on iOS 8.0 or higher."); 180 | layoutAttribute = NSLayoutAttributeRightMargin; 181 | break; 182 | case ALMarginTop: 183 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALEdgeTopMargin is only supported on iOS 8.0 or higher."); 184 | layoutAttribute = NSLayoutAttributeTopMargin; 185 | break; 186 | case ALMarginBottom: 187 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALEdgeBottomMargin is only supported on iOS 8.0 or higher."); 188 | layoutAttribute = NSLayoutAttributeBottomMargin; 189 | break; 190 | case ALMarginLeading: 191 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALEdgeLeadingMargin is only supported on iOS 8.0 or higher."); 192 | layoutAttribute = NSLayoutAttributeLeadingMargin; 193 | break; 194 | case ALMarginTrailing: 195 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALEdgeTrailingMargin is only supported on iOS 8.0 or higher."); 196 | layoutAttribute = NSLayoutAttributeTrailingMargin; 197 | break; 198 | case ALMarginAxisVertical: 199 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALAxisVerticalMargin is only supported on iOS 8.0 or higher."); 200 | layoutAttribute = NSLayoutAttributeCenterXWithinMargins; 201 | break; 202 | case ALMarginAxisHorizontal: 203 | NSAssert(__PureLayout_MinSysVer_iOS8, @"ALAxisHorizontalMargin is only supported on iOS 8.0 or higher."); 204 | layoutAttribute = NSLayoutAttributeCenterYWithinMargins; 205 | break; 206 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 207 | default: 208 | NSAssert(nil, @"Not a valid ALAttribute."); 209 | break; 210 | } 211 | return layoutAttribute; 212 | } 213 | 214 | /** 215 | Returns the corresponding ALLayoutConstraintAxis for the given ALAxis. 216 | 217 | @return The constraint axis for the given axis. 218 | */ 219 | + (ALLayoutConstraintAxis)al_constraintAxisForAxis:(ALAxis)axis 220 | { 221 | ALLayoutConstraintAxis constraintAxis; 222 | switch (axis) { 223 | case ALAxisVertical: 224 | constraintAxis = ALLayoutConstraintAxisVertical; 225 | break; 226 | case ALAxisHorizontal: 227 | case ALAxisBaseline: // same value as ALAxisLastBaseline 228 | #if __PureLayout_MinBaseSDK_iOS8 229 | case ALAxisFirstBaseline: 230 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 231 | constraintAxis = ALLayoutConstraintAxisHorizontal; 232 | break; 233 | default: 234 | NSAssert(nil, @"Not a valid ALAxis."); 235 | constraintAxis = ALLayoutConstraintAxisHorizontal; // default to a random value to satisfy the compiler 236 | break; 237 | } 238 | return constraintAxis; 239 | } 240 | 241 | #if __PureLayout_MinBaseSDK_iOS8 242 | 243 | /** 244 | Returns the corresponding margin for the given edge. 245 | 246 | @param edge The edge to convert to the corresponding margin. 247 | @return The margin for the given edge. 248 | */ 249 | + (ALMargin)al_marginForEdge:(ALEdge)edge 250 | { 251 | NSAssert(__PureLayout_MinSysVer_iOS8, @"Margin attributes are only supported on iOS 8.0 or higher."); 252 | ALMargin margin; 253 | switch (edge) { 254 | case ALEdgeLeft: 255 | margin = ALMarginLeft; 256 | break; 257 | case ALEdgeRight: 258 | margin = ALMarginRight; 259 | break; 260 | case ALEdgeTop: 261 | margin = ALMarginTop; 262 | break; 263 | case ALEdgeBottom: 264 | margin = ALMarginBottom; 265 | break; 266 | case ALEdgeLeading: 267 | margin = ALMarginLeading; 268 | break; 269 | case ALEdgeTrailing: 270 | margin = ALMarginTrailing; 271 | break; 272 | default: 273 | NSAssert(nil, @"Not a valid ALEdge."); 274 | margin = ALMarginLeft; // default to a random value to satisfy the compiler 275 | break; 276 | } 277 | return margin; 278 | } 279 | 280 | /** 281 | Returns the corresponding margin axis for the given axis. 282 | 283 | @param axis The axis to convert to the corresponding margin axis. 284 | @return The margin axis for the given axis. 285 | */ 286 | + (ALMarginAxis)al_marginAxisForAxis:(ALAxis)axis 287 | { 288 | NSAssert(__PureLayout_MinSysVer_iOS8, @"Margin attributes are only supported on iOS 8.0 or higher."); 289 | ALMarginAxis marginAxis; 290 | switch (axis) { 291 | case ALAxisVertical: 292 | marginAxis = ALMarginAxisVertical; 293 | break; 294 | case ALAxisHorizontal: 295 | marginAxis = ALMarginAxisHorizontal; 296 | break; 297 | case ALAxisBaseline: 298 | case ALAxisFirstBaseline: 299 | NSAssert(nil, @"The baseline axis attributes do not have corresponding margin axis attributes."); 300 | marginAxis = ALMarginAxisVertical; // default to a random value to satisfy the compiler 301 | break; 302 | default: 303 | NSAssert(nil, @"Not a valid ALAxis."); 304 | marginAxis = ALMarginAxisVertical; // default to a random value to satisfy the compiler 305 | break; 306 | } 307 | return marginAxis; 308 | } 309 | 310 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 311 | 312 | @end 313 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/PureLayout+Internal.h: -------------------------------------------------------------------------------- 1 | // 2 | // PureLayout+Internal.h 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2014 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #import "PureLayoutDefines.h" 30 | 31 | 32 | /** 33 | A category that exposes the internal (private) helper methods of the ALView+PureLayout category. 34 | */ 35 | @interface ALView (PureLayoutInternal) 36 | 37 | + (BOOL)al_preventAutomaticConstraintInstallation; 38 | + (void)al_applyGlobalStateToConstraint:(NSLayoutConstraint *)constraint; 39 | - (void)al_addConstraint:(NSLayoutConstraint *)constraint; 40 | - (ALView *)al_commonSuperviewWithView:(ALView *)otherView; 41 | - (NSLayoutConstraint *)al_alignAttribute:(ALAttribute)attribute toView:(ALView *)otherView forAxis:(ALAxis)axis; 42 | 43 | @end 44 | 45 | 46 | /** 47 | A category that exposes the internal (private) helper methods of the NSArray+PureLayout category. 48 | */ 49 | @interface NSArray (PureLayoutInternal) 50 | 51 | - (ALView *)al_commonSuperviewOfViews; 52 | - (BOOL)al_containsMinimumNumberOfViews:(NSUInteger)minimumNumberOfViews; 53 | - (NSArray *)al_copyViewsOnly; 54 | 55 | @end 56 | 57 | 58 | /** 59 | A category that exposes the internal (private) helper methods of the NSLayoutConstraint+PureLayout category. 60 | */ 61 | @interface NSLayoutConstraint (PureLayoutInternal) 62 | 63 | + (NSLayoutAttribute)al_layoutAttributeForAttribute:(ALAttribute)attribute; 64 | + (ALLayoutConstraintAxis)al_constraintAxisForAxis:(ALAxis)axis; 65 | #if __PureLayout_MinBaseSDK_iOS8 66 | + (ALMargin)al_marginForEdge:(ALEdge)edge; 67 | + (ALMarginAxis)al_marginAxisForAxis:(ALAxis)axis; 68 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // PureLayout.h 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2014 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #ifndef PureLayout_h 30 | #define PureLayout_h 31 | 32 | #import "ALView+PureLayout.h" 33 | #import "NSArray+PureLayout.h" 34 | #import "NSLayoutConstraint+PureLayout.h" 35 | 36 | #endif /* PureLayout_h */ -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/PureLayout/Source/PureLayoutDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // PureLayoutDefines.h 3 | // v2.0.0 4 | // https://github.com/smileyborg/PureLayout 5 | // 6 | // Copyright (c) 2014 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #ifndef PureLayoutDefines_h 30 | #define PureLayoutDefines_h 31 | 32 | #import 33 | 34 | #define __PureLayout_MinBaseSDK_iOS8 TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1 35 | #define __PureLayout_MinSysVer_iOS7 floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1 36 | #define __PureLayout_MinSysVer_iOS8 floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1 37 | 38 | #if TARGET_OS_IPHONE 39 | 40 | #import 41 | 42 | #define ALView UIView 43 | #define ALEdgeInsets UIEdgeInsets 44 | #define ALEdgeInsetsZero UIEdgeInsetsZero 45 | #define ALEdgeInsetsMake UIEdgeInsetsMake 46 | #define ALLayoutConstraintAxis UILayoutConstraintAxis 47 | #define ALLayoutConstraintOrientation ALLayoutConstraintAxis 48 | #define ALLayoutConstraintAxisHorizontal UILayoutConstraintAxisHorizontal 49 | #define ALLayoutConstraintAxisVertical UILayoutConstraintAxisVertical 50 | #define ALLayoutConstraintOrientationHorizontal ALLayoutConstraintAxisHorizontal 51 | #define ALLayoutConstraintOrientationVertical ALLayoutConstraintAxisVertical 52 | #define ALLayoutPriority UILayoutPriority 53 | #define ALLayoutPriorityRequired UILayoutPriorityRequired 54 | #define ALLayoutPriorityDefaultHigh UILayoutPriorityDefaultHigh 55 | #define ALLayoutPriorityDefaultLow UILayoutPriorityDefaultLow 56 | #define ALLayoutPriorityFittingSizeLevel UILayoutPriorityFittingSizeLevel 57 | #define ALLayoutPriorityFittingSizeCompression ALLayoutPriorityFittingSizeLevel 58 | 59 | #else 60 | 61 | #import 62 | 63 | #define ALView NSView 64 | #define ALEdgeInsets NSEdgeInsets 65 | #define ALEdgeInsetsZero NSEdgeInsetsMake(0, 0, 0, 0) 66 | #define ALEdgeInsetsMake NSEdgeInsetsMake 67 | #define ALLayoutConstraintOrientation NSLayoutConstraintOrientation 68 | #define ALLayoutConstraintAxis ALLayoutConstraintOrientation 69 | #define ALLayoutConstraintOrientationHorizontal NSLayoutConstraintOrientationHorizontal 70 | #define ALLayoutConstraintOrientationVertical NSLayoutConstraintOrientationVertical 71 | #define ALLayoutConstraintAxisHorizontal ALLayoutConstraintOrientationHorizontal 72 | #define ALLayoutConstraintAxisVertical ALLayoutConstraintOrientationVertical 73 | #define ALLayoutPriority NSLayoutPriority 74 | #define ALLayoutPriorityRequired NSLayoutPriorityRequired 75 | #define ALLayoutPriorityDefaultHigh NSLayoutPriorityDefaultHigh 76 | #define ALLayoutPriorityDefaultLow NSLayoutPriorityDefaultLow 77 | #define ALLayoutPriorityFittingSizeCompression NSLayoutPriorityFittingSizeCompression 78 | #define ALLayoutPriorityFittingSizeLevel ALLayoutPriorityFittingSizeCompression 79 | 80 | #endif /* TARGET_OS_IPHONE */ 81 | 82 | 83 | #pragma mark PureLayout Attributes 84 | 85 | /** Constants that represent edges of a view. */ 86 | typedef NS_ENUM(NSInteger, ALEdge) { 87 | /** The left edge of the view. */ 88 | ALEdgeLeft = NSLayoutAttributeLeft, 89 | /** The right edge of the view. */ 90 | ALEdgeRight = NSLayoutAttributeRight, 91 | /** The top edge of the view. */ 92 | ALEdgeTop = NSLayoutAttributeTop, 93 | /** The bottom edge of the view. */ 94 | ALEdgeBottom = NSLayoutAttributeBottom, 95 | /** The leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic). */ 96 | ALEdgeLeading = NSLayoutAttributeLeading, 97 | /** The trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic). */ 98 | ALEdgeTrailing = NSLayoutAttributeTrailing 99 | }; 100 | 101 | /** Constants that represent dimensions of a view. */ 102 | typedef NS_ENUM(NSInteger, ALDimension) { 103 | /** The width of the view. */ 104 | ALDimensionWidth = NSLayoutAttributeWidth, 105 | /** The height of the view. */ 106 | ALDimensionHeight = NSLayoutAttributeHeight 107 | }; 108 | 109 | /** Constants that represent axes of a view. */ 110 | typedef NS_ENUM(NSInteger, ALAxis) { 111 | /** A vertical line through the middle of the view's left and right edges. */ 112 | ALAxisVertical = NSLayoutAttributeCenterX, 113 | /** A horizontal line through the middle of the view's top and bottom edges. */ 114 | ALAxisHorizontal = NSLayoutAttributeCenterY, 115 | 116 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) Same as ALAxisLastBaseline. */ 117 | ALAxisBaseline = NSLayoutAttributeBaseline, 118 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) */ 119 | ALAxisLastBaseline = ALAxisBaseline, 120 | #if __PureLayout_MinBaseSDK_iOS8 121 | /** A horizontal line at the baseline of the first line of text in a view. (For views that do not draw text, will be equivalent to ALEdgeTop.) Available in iOS 8.0 and later. */ 122 | ALAxisFirstBaseline = NSLayoutAttributeFirstBaseline 123 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 124 | }; 125 | 126 | #if __PureLayout_MinBaseSDK_iOS8 127 | 128 | /** Constants that represent layout margins of a view. Available in iOS 8.0 and later. */ 129 | typedef NS_ENUM(NSInteger, ALMargin) { 130 | /** The left margin of the view, based on the view's layoutMargins left inset. */ 131 | ALMarginLeft = NSLayoutAttributeLeftMargin, 132 | /** The right margin of the view, based on the view's layoutMargins right inset. */ 133 | ALMarginRight = NSLayoutAttributeRightMargin, 134 | /** The top margin of the view, based on the view's layoutMargins top inset. */ 135 | ALMarginTop = NSLayoutAttributeTopMargin, 136 | /** The bottom margin of the view, based on the view's layoutMargins bottom inset. */ 137 | ALMarginBottom = NSLayoutAttributeBottomMargin, 138 | /** The leading margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 139 | ALMarginLeading = NSLayoutAttributeLeadingMargin, 140 | /** The trailing margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 141 | ALMarginTrailing = NSLayoutAttributeTrailingMargin 142 | }; 143 | 144 | /** Constants that represent axes of the layout margins of a view. Available in iOS 8.0 and later. */ 145 | typedef NS_ENUM(NSInteger, ALMarginAxis) { 146 | /** A vertical line through the middle of the view's left and right margins. */ 147 | ALMarginAxisVertical = NSLayoutAttributeCenterXWithinMargins, 148 | /** A horizontal line through the middle of the view's top and bottom margins. */ 149 | ALMarginAxisHorizontal = NSLayoutAttributeCenterYWithinMargins 150 | }; 151 | 152 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 153 | 154 | /** An attribute of a view that can be used in auto layout constraints. These constants are identical to the more specific enum types: 155 | ALEdge, ALAxis, ALDimension, ALMargin, ALMarginAxis. It is safe to cast a more specific enum type to the ALAttribute type. */ 156 | typedef NS_ENUM(NSInteger, ALAttribute) { 157 | /** The left edge of the view. */ 158 | ALAttributeLeft = ALEdgeLeft, 159 | /** The right edge of the view. */ 160 | ALAttributeRight = ALEdgeRight, 161 | /** The top edge of the view. */ 162 | ALAttributeTop = ALEdgeTop, 163 | /** The bottom edge of the view. */ 164 | ALAttributeBottom = ALEdgeBottom, 165 | /** The leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic). */ 166 | ALAttributeLeading = ALEdgeLeading, 167 | /** The trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic). */ 168 | ALAttributeTrailing = ALEdgeTrailing, 169 | /** The width of the view. */ 170 | ALAttributeWidth = ALDimensionWidth, 171 | /** The height of the view. */ 172 | ALAttributeHeight = ALDimensionHeight, 173 | /** A vertical line through the middle of the view's left and right edges. */ 174 | ALAttributeVertical = ALAxisVertical, 175 | /** A horizontal line through the middle of the view's top and bottom edges. */ 176 | ALAttributeHorizontal = ALAxisHorizontal, 177 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) Same as ALAxisLastBaseline. */ 178 | ALAttributeBaseline = ALAxisBaseline, 179 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) */ 180 | ALAttributeLastBaseline = ALAxisLastBaseline, 181 | #if __PureLayout_MinBaseSDK_iOS8 182 | /** A horizontal line at the baseline of the first line of text in a view. (For views that do not draw text, will be equivalent to ALEdgeTop.) Available in iOS 8.0 and later. */ 183 | ALAttributeFirstBaseline = ALAxisFirstBaseline, 184 | /** The left margin of the view, based on the view's layoutMargins left inset. */ 185 | ALAttributeMarginLeft = ALMarginLeft, 186 | /** The right margin of the view, based on the view's layoutMargins right inset. */ 187 | ALAttributeMarginRight = ALMarginRight, 188 | /** The top margin of the view, based on the view's layoutMargins top inset. */ 189 | ALAttributeMarginTop = ALMarginTop, 190 | /** The bottom margin of the view, based on the view's layoutMargins bottom inset. */ 191 | ALAttributeMarginBottom = ALMarginBottom, 192 | /** The leading margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 193 | ALAttributeMarginLeading = ALMarginLeading, 194 | /** The trailing margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 195 | ALAttributeMarginTrailing = ALMarginTrailing, 196 | /** A vertical line through the middle of the view's left and right margins. */ 197 | ALAttributeMarginAxisVertical = ALMarginAxisVertical, 198 | /** A horizontal line through the middle of the view's top and bottom margins. */ 199 | ALAttributeMarginAxisHorizontal = ALMarginAxisHorizontal 200 | #endif /* __PureLayout_MinBaseSDK_iOS8 */ 201 | }; 202 | 203 | /** A block containing method calls to the PureLayout API. Takes no arguments and has no return value. */ 204 | typedef void(^ALConstraintsBlock)(void); 205 | 206 | #endif /* PureLayoutDefines_h */ 207 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/VSAppDelegate.h: -------------------------------------------------------------------------------- 1 | 2 | @interface VSAppDelegate : UIResponder 3 | 4 | @property (strong, nonatomic) UIWindow *window; 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/VSAppDelegate.m: -------------------------------------------------------------------------------- 1 | 2 | #import "VSAppDelegate.h" 3 | 4 | @implementation VSAppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 7 | { 8 | // Override point for customization after application launch. 9 | return YES; 10 | } 11 | 12 | - (void)applicationWillResignActive:(UIApplication *)application 13 | { 14 | // 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. 15 | // 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. 16 | } 17 | 18 | - (void)applicationDidEnterBackground:(UIApplication *)application 19 | { 20 | // 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. 21 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 22 | } 23 | 24 | - (void)applicationWillEnterForeground:(UIApplication *)application 25 | { 26 | // 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. 27 | } 28 | 29 | - (void)applicationDidBecomeActive:(UIApplication *)application 30 | { 31 | // 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. 32 | } 33 | 34 | - (void)applicationWillTerminate:(UIApplication *)application 35 | { 36 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/VSViewController.h: -------------------------------------------------------------------------------- 1 | 2 | @interface VSViewController : UIViewController 3 | 4 | @end 5 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | -------------------------------------------------------------------------------- /Auto Layout Demo/Supporting Files/main.m: -------------------------------------------------------------------------------- 1 | 2 | #import "VSAppDelegate.h" 3 | 4 | int main(int argc, char * argv[]) 5 | { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([VSAppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Auto Layout Demo/VSLabel.h: -------------------------------------------------------------------------------- 1 | 2 | @interface VSLabel : UIView 3 | 4 | @property (nonatomic, copy) NSString *title; 5 | @property (nonatomic, copy) NSString *body; 6 | @property (nonatomic, strong) UIFont *bodyFont; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Auto Layout Demo/VSLabel.m: -------------------------------------------------------------------------------- 1 | 2 | #import "VSLabel.h" 3 | 4 | @interface VSLabel () 5 | 6 | @property (nonatomic, strong) UILabel *textLabel; 7 | @property (nonatomic, strong) UILabel *detailLabel; 8 | @property (nonatomic, assign) BOOL didSetupConstraints; 9 | 10 | @end 11 | 12 | @implementation VSLabel 13 | 14 | - (instancetype)initWithFrame:(CGRect)frame { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | _textLabel = [UILabel new]; 18 | _textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; 19 | _textLabel.translatesAutoresizingMaskIntoConstraints = NO; 20 | _textLabel.backgroundColor = [UIColor blueColor]; 21 | [self addSubview:_textLabel]; 22 | 23 | _detailLabel = [UILabel new]; 24 | _detailLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; 25 | _detailLabel.numberOfLines = 0; 26 | _detailLabel.textColor = [UIColor whiteColor]; 27 | _detailLabel.backgroundColor = [UIColor orangeColor]; 28 | _detailLabel.translatesAutoresizingMaskIntoConstraints = NO; 29 | [self addSubview:_detailLabel]; 30 | } 31 | return self; 32 | } 33 | 34 | - (void)setupConstraints { 35 | /** 36 | * 这里有一个常见问题,如果字典中包含 `self` 这个键,就不能包含其他以 `self.`开头的键,否则 `VFL` 会解析错误。 37 | */ 38 | NSDictionary *views = NSDictionaryOfVariableBindings(self, _textLabel, _detailLabel); 39 | NSDictionary *metrics = @{@"fontSize": @(self.textLabel.font.pointSize)}; 40 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_textLabel]-|" options:0 metrics:nil views:views]]; 41 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_detailLabel]-|" options:0 metrics:nil views:views]]; 42 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_textLabel(<=fontSize)]-[_detailLabel]-|" 43 | options:NSLayoutFormatAlignAllLeading metrics:metrics views:views]]; 44 | self.didSetupConstraints = YES; 45 | } 46 | 47 | - (void)updateConstraints { 48 | if (!self.didSetupConstraints) { 49 | [self setupConstraints]; 50 | } 51 | [super updateConstraints]; 52 | } 53 | 54 | - (void)layoutSubviews { 55 | [super layoutSubviews]; 56 | 57 | CGFloat preferredMaxLayoutWidth = CGRectGetWidth(self.frame); 58 | self.textLabel.preferredMaxLayoutWidth = preferredMaxLayoutWidth; 59 | self.detailLabel.preferredMaxLayoutWidth = preferredMaxLayoutWidth; 60 | } 61 | 62 | - (CGSize)intrinsicContentSize { 63 | CGSize textLabelIntrinsicContentSize = [self.textLabel intrinsicContentSize]; 64 | CGSize detailLabelIntrinsicContentSize = [self.detailLabel intrinsicContentSize]; 65 | 66 | CGFloat width = MAX(textLabelIntrinsicContentSize.width, detailLabelIntrinsicContentSize.width); 67 | CGFloat height = textLabelIntrinsicContentSize.height + detailLabelIntrinsicContentSize.height + CGRectGetMinY(self.textLabel.frame) * 2 + 8.f; 68 | 69 | return CGSizeMake(width, height); 70 | } 71 | 72 | 73 | #pragma mark - Custom Accessors 74 | 75 | - (void)setTitle:(NSString *)title { 76 | if (_title != title) { 77 | _title = title; 78 | self.textLabel.text = title; 79 | [self invalidateIntrinsicContentSize]; 80 | } 81 | } 82 | 83 | - (void)setBody:(NSString *)body { 84 | if (_body != body) { 85 | _body = body; 86 | self.detailLabel.text = body; 87 | [self invalidateIntrinsicContentSize]; 88 | } 89 | } 90 | 91 | - (void)setBodyFont:(UIFont *)bodyFont { 92 | if (_bodyFont != bodyFont) { 93 | _bodyFont = bodyFont; 94 | self.detailLabel.font = bodyFont; 95 | [self invalidateIntrinsicContentSize]; 96 | } 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Auto Layout Demo/VSLayoutExample1.h: -------------------------------------------------------------------------------- 1 | 2 | @interface VSLayoutExample1 : UIView 3 | 4 | @end 5 | -------------------------------------------------------------------------------- /Auto Layout Demo/VSLayoutExample1.m: -------------------------------------------------------------------------------- 1 | 2 | #import "VSLayoutExample1.h" 3 | 4 | static CGSize const kAvatarSize = {32.f, 32.f}; 5 | 6 | @interface VSLayoutExample1 () 7 | 8 | @property (nonatomic, strong) UIImageView *avatarImageView; 9 | @property (nonatomic, strong) UILabel *nicknameLabel; 10 | @property (nonatomic, strong) UIView *timestampIndicator; 11 | @property (nonatomic, strong) UILabel *timestampLabel; 12 | @property (nonatomic, strong) UIImageView *contentImageView; 13 | @property (nonatomic, strong) UIView *likeIndicator; 14 | @property (nonatomic, strong) UILabel *likesLabel; 15 | @property (nonatomic, strong) UIButton *likeButton; 16 | @property (nonatomic, strong) UIButton *commentButton; 17 | @property (nonatomic, strong) UIButton *moreButton; 18 | @property (nonatomic, assign) BOOL didSetupConstraints; 19 | 20 | @end 21 | 22 | @implementation VSLayoutExample1 23 | 24 | - (instancetype)initWithFrame:(CGRect)frame { 25 | self = [super initWithFrame:frame]; 26 | if (self) { 27 | self.backgroundColor = [UIColor whiteColor]; 28 | self.clipsToBounds = YES; 29 | 30 | _avatarImageView = [UIImageView newAutoLayoutView]; 31 | _avatarImageView.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:.3f]; 32 | _avatarImageView.layer.cornerRadius = kAvatarSize.height / 2.f; 33 | _avatarImageView.layer.masksToBounds = YES; 34 | 35 | _nicknameLabel = [UILabel newAutoLayoutView]; 36 | _nicknameLabel.text = @"iamkeyeelee"; 37 | _nicknameLabel.textColor = [[UIColor blueColor] colorWithAlphaComponent:.3f]; 38 | _nicknameLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; 39 | 40 | _timestampIndicator = [UIView newAutoLayoutView]; 41 | _timestampIndicator.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:.3f]; 42 | 43 | _timestampLabel = [UILabel newAutoLayoutView]; 44 | _timestampLabel.text = @"7小时"; 45 | _timestampLabel.textColor = [UIColor lightGrayColor]; 46 | _timestampLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; 47 | 48 | _contentImageView = [UIImageView newAutoLayoutView]; 49 | _contentImageView.backgroundColor = [[UIColor purpleColor] colorWithAlphaComponent:.3f]; 50 | 51 | _likeIndicator = [UIView newAutoLayoutView]; 52 | _likeIndicator.backgroundColor = [[UIColor orangeColor] colorWithAlphaComponent:.3f]; 53 | 54 | _likesLabel = [UILabel newAutoLayoutView]; 55 | _likesLabel.text = @"12 次赞"; 56 | _likesLabel.textColor = _nicknameLabel.textColor; 57 | _likesLabel.font = _nicknameLabel.font; 58 | 59 | _likeButton = [UIButton buttonWithType:UIButtonTypeCustom]; 60 | _likeButton.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:.3f]; 61 | _likeButton.translatesAutoresizingMaskIntoConstraints = NO; 62 | 63 | _commentButton = [UIButton buttonWithType:UIButtonTypeCustom]; 64 | _commentButton.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:.3f]; 65 | _commentButton.translatesAutoresizingMaskIntoConstraints = NO; 66 | 67 | _moreButton = [UIButton buttonWithType:UIButtonTypeCustom]; 68 | _moreButton.backgroundColor = [[UIColor magentaColor] colorWithAlphaComponent:.3f]; 69 | _moreButton.translatesAutoresizingMaskIntoConstraints = NO; 70 | 71 | [self addSubview:_avatarImageView]; 72 | [self addSubview:_nicknameLabel]; 73 | [self addSubview:_timestampIndicator]; 74 | [self addSubview:_timestampLabel]; 75 | [self addSubview:_contentImageView]; 76 | [self addSubview:_likeIndicator]; 77 | [self addSubview:_likesLabel]; 78 | [self addSubview:_likeButton]; 79 | [self addSubview:_commentButton]; 80 | [self addSubview:_moreButton]; 81 | } 82 | return self; 83 | } 84 | 85 | 86 | - (void)setupConstraints { 87 | // 头像左边距离父视图左边 10 点. 88 | [self.avatarImageView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:10.f]; 89 | 90 | // 头像顶边距离父视图顶部 10 点. 91 | [self.avatarImageView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:10.f]; 92 | 93 | // 设置头像尺寸 94 | [self.avatarImageView autoSetDimensionsToSize:kAvatarSize]; 95 | 96 | // 昵称的左边位于头像的右边 10 点的地方. 97 | [self.nicknameLabel autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:self.avatarImageView withOffset:10.f]; 98 | 99 | // 根据昵称的固有内容尺寸设置它的尺寸 100 | [self.nicknameLabel autoSetDimensionsToSize:[self.nicknameLabel intrinsicContentSize]]; 101 | 102 | // 时间标识的右边位于时间视图左边 -10 点的地方, 从右往左、从下往上布局时数值都是负的。 103 | [self.timestampIndicator autoPinEdge:ALEdgeTrailing toEdge:ALEdgeLeading ofView:self.timestampLabel withOffset:-10.f]; 104 | 105 | // 根据时间标识的固有内容尺寸设置它的尺寸 106 | [self.timestampIndicator autoSetDimensionsToSize:CGSizeMake(10.f, 10.f)]; 107 | 108 | // 时间视图的右边距离父视图的右边 10 点. 109 | [self.timestampLabel autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:10.f]; 110 | 111 | // 根据时间视图的固有内容尺寸设置它的尺寸 112 | [self.timestampLabel autoSetDimensionsToSize:[self.timestampLabel intrinsicContentSize]]; 113 | 114 | // 头像、昵称、时间标识、时间视图水平对齐。(意思就是说只需要设置其中一个的垂直约束(y)即可) 115 | [@[self.avatarImageView, self.nicknameLabel, self.timestampIndicator, self.timestampLabel] autoAlignViewsToAxis:ALAxisHorizontal]; 116 | 117 | // 内容图片视图顶部距离头像的底部 10 点. 118 | [self.contentImageView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.avatarImageView withOffset:10.f]; 119 | 120 | // 内容图片视图左边紧贴父视图左边 121 | [self.contentImageView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; 122 | 123 | // 内容图片视图的宽度等于父视图的宽度 124 | [self.contentImageView autoMatchDimension:ALDimensionWidth toDimension:ALDimensionWidth ofView:self]; 125 | 126 | // 内容图片视图的高度等于父视图的宽度 127 | [self.contentImageView autoMatchDimension:ALDimensionHeight toDimension:ALDimensionWidth ofView:self]; 128 | 129 | // 赞标识与头像左对齐 130 | [self.likeIndicator autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:self.avatarImageView]; 131 | 132 | // 赞标识的顶部距离内容图片视图底部 10 点. 133 | [self.likeIndicator autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.contentImageView withOffset:10.f]; 134 | 135 | // 设置赞标识的尺寸 136 | [self.likeIndicator autoSetDimensionsToSize:CGSizeMake(10.f, 10.f)]; 137 | 138 | // 赞数量视图与赞标识水平对齐 139 | [self.likesLabel autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.likeIndicator]; 140 | 141 | // 赞数量视图的左边距离赞标识的右边 10 点. 142 | [self.likesLabel autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:self.likeIndicator withOffset:10.f]; 143 | 144 | // 以下请自行脑补... 145 | [self.likesLabel autoSetDimensionsToSize:[self.likesLabel intrinsicContentSize]]; 146 | 147 | NSArray *buttons = @[self.likeButton, self.commentButton, self.moreButton]; 148 | [buttons autoMatchViewsDimension:ALDimensionHeight]; 149 | [buttons autoAlignViewsToEdge:ALEdgeBottom]; 150 | [self.likeButton autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:self.avatarImageView]; 151 | [self.likeButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:10.f]; 152 | [self.likeButton autoSetDimensionsToSize:CGSizeMake(50.f, 25.f)]; 153 | 154 | [self.commentButton autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:self.likeButton withOffset:5.f]; 155 | [self.commentButton autoSetDimension:ALDimensionWidth toSize:65.f]; 156 | 157 | [self.moreButton autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:10.f]; 158 | [self.moreButton autoSetDimension:ALDimensionWidth toSize:40.f]; 159 | 160 | self.didSetupConstraints = YES; 161 | } 162 | 163 | /** 164 | * `updateConstraints` 可能会多次调用, 所以使用一个布尔值防止多次添加约束. 165 | */ 166 | - (void)updateConstraints { 167 | if (!self.didSetupConstraints) { 168 | [self setupConstraints]; 169 | } 170 | [super updateConstraints]; 171 | } 172 | 173 | - (CGSize)intrinsicContentSize { 174 | return CGSizeMake(320.f, 440.f); 175 | } 176 | 177 | @end 178 | -------------------------------------------------------------------------------- /Auto Layout Demo/VSViewController.m: -------------------------------------------------------------------------------- 1 | 2 | #import "VSViewController.h" 3 | 4 | #import "VSLabel.h" 5 | #import "VSLayoutExample1.h" 6 | 7 | @implementation VSViewController 8 | 9 | - (void)viewDidLoad { 10 | [super viewDidLoad]; 11 | 12 | self.view.backgroundColor = [UIColor grayColor]; 13 | 14 | [self example1]; 15 | } 16 | 17 | /** 18 | * 最基础方式进行布局 19 | */ 20 | - (void)example1 { 21 | UIView *view = [UIView new]; 22 | [view setBackgroundColor:[UIColor redColor]]; 23 | [self.view addSubview:view]; 24 | 25 | CGRect viewFrame = CGRectMake(50.f, 100.f, 150.f, 150.f); 26 | 27 | // 使用 Auto Layout 布局 28 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 29 | 30 | // `view` 的左边距离 `self.view` 的左边 50 点. 31 | NSLayoutConstraint *viewLeft = [NSLayoutConstraint constraintWithItem:view 32 | attribute:NSLayoutAttributeLeading 33 | relatedBy:NSLayoutRelationEqual 34 | toItem:self.view 35 | attribute:NSLayoutAttributeLeading 36 | multiplier:1 37 | constant:CGRectGetMinX(viewFrame)]; 38 | // `view` 的顶部距离 `self.view` 的顶部 100 点. 39 | NSLayoutConstraint *viewTop = [NSLayoutConstraint constraintWithItem:view 40 | attribute:NSLayoutAttributeTop 41 | relatedBy:NSLayoutRelationEqual 42 | toItem:self.view 43 | attribute:NSLayoutAttributeTop 44 | multiplier:1 45 | constant:CGRectGetMinY(viewFrame)]; 46 | // `view` 的宽度 是 60 点. 47 | NSLayoutConstraint *viewWidth = [NSLayoutConstraint constraintWithItem:view 48 | attribute:NSLayoutAttributeWidth 49 | relatedBy:NSLayoutRelationGreaterThanOrEqual 50 | toItem:nil 51 | attribute:NSLayoutAttributeNotAnAttribute 52 | multiplier:1 53 | constant:CGRectGetWidth(viewFrame)]; 54 | // `view` 的高度是 60 点. 55 | NSLayoutConstraint *viewHeight = [NSLayoutConstraint constraintWithItem:view 56 | attribute:NSLayoutAttributeHeight 57 | relatedBy:NSLayoutRelationGreaterThanOrEqual 58 | toItem:nil 59 | attribute:NSLayoutAttributeNotAnAttribute 60 | multiplier:1 61 | constant:CGRectGetHeight(viewFrame)]; 62 | // 把约束添加到父视图上. 63 | [self.view addConstraints:@[viewLeft, viewTop, viewWidth, viewHeight]]; 64 | } 65 | 66 | 67 | /** 68 | * 使用 `VFL` 重构上一个布局 69 | */ 70 | - (void)example2 { 71 | UIView *view = [UIView new]; 72 | [view setBackgroundColor:[UIColor redColor]]; 73 | [self.view addSubview:view]; 74 | 75 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 76 | 77 | NSDictionary *views = NSDictionaryOfVariableBindings(view); 78 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[view(>=150)]" options:0 metrics:nil views:views]]; 79 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view(>=150)]" options:0 metrics:nil views:views]]; 80 | } 81 | 82 | /** 83 | * 在右侧添加一个视图 84 | */ 85 | - (void)example3 { 86 | UIView *view = [UIView new]; 87 | [view setBackgroundColor:[UIColor redColor]]; 88 | [self.view addSubview:view]; 89 | 90 | UIView *view2 = [UIView new]; 91 | [view2 setBackgroundColor:[UIColor blueColor]]; 92 | [self.view addSubview:view2]; 93 | 94 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 95 | [view2 setTranslatesAutoresizingMaskIntoConstraints:NO]; 96 | 97 | NSDictionary *views = NSDictionaryOfVariableBindings(view, view2); 98 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[view(>=150)]" options:0 metrics:nil views:views]]; 99 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view(>=150)]" options:0 metrics:nil views:views]]; 100 | 101 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view]-[view2(>=50)]" options:0 metrics:nil views:views]]; 102 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view2(>=50)]" options:0 metrics:nil views:views]]; 103 | } 104 | 105 | /** 106 | * 简化 `VFL` 语句 107 | */ 108 | - (void)example4 { 109 | UIView *view = [UIView new]; 110 | [view setBackgroundColor:[UIColor redColor]]; 111 | [self.view addSubview:view]; 112 | 113 | UIView *view2 = [UIView new]; 114 | [view2 setBackgroundColor:[UIColor blueColor]]; 115 | [self.view addSubview:view2]; 116 | 117 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 118 | [view2 setTranslatesAutoresizingMaskIntoConstraints:NO]; 119 | 120 | NSDictionary *views = NSDictionaryOfVariableBindings(view, view2); 121 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[view(>=150)]-[view2(>=50)]" options:0 metrics:nil views:views]]; 122 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view(>=150)]" options:0 metrics:nil views:views]]; 123 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view2(>=50)]" options:0 metrics:nil views:views]]; 124 | } 125 | 126 | /** 127 | * 添加第三个视图 128 | */ 129 | - (void)example5 { 130 | UIView *view = [UIView new]; 131 | [view setBackgroundColor:[UIColor redColor]]; 132 | [self.view addSubview:view]; 133 | 134 | UIView *view2 = [UIView new]; 135 | [view2 setBackgroundColor:[UIColor blueColor]]; 136 | [self.view addSubview:view2]; 137 | 138 | UIView *view3 = [UIView new]; 139 | [view3 setBackgroundColor:[UIColor orangeColor]]; 140 | [self.view addSubview:view3]; 141 | 142 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 143 | [view2 setTranslatesAutoresizingMaskIntoConstraints:NO]; 144 | [view3 setTranslatesAutoresizingMaskIntoConstraints:NO]; 145 | 146 | NSDictionary *views = NSDictionaryOfVariableBindings(view, view2, view3); 147 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[view(>=150)]-[view2(>=50)]" options:0 metrics:nil views:views]]; 148 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(100)-[view(>=150)]" options:0 metrics:nil views:views]]; 149 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view]-[view3(>=50)]" options:0 metrics:nil views:views]]; 150 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(100)-[view2(>=50)][view3(>=100)]" options:0 metrics:nil views:views]]; 151 | } 152 | 153 | /** 154 | * 重构上一个布局代码 155 | */ 156 | - (void)example6 { 157 | UIView *view = [UIView new]; 158 | [view setBackgroundColor:[UIColor redColor]]; 159 | [self.view addSubview:view]; 160 | 161 | UIView *view2 = [UIView new]; 162 | [view2 setBackgroundColor:[UIColor blueColor]]; 163 | [self.view addSubview:view2]; 164 | 165 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 166 | [view2 setTranslatesAutoresizingMaskIntoConstraints:NO]; 167 | 168 | NSDictionary *views = NSDictionaryOfVariableBindings(view, view2); 169 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[view(>=150)]-[view2(>=50)]" options:NSLayoutFormatAlignAllTop metrics:nil views:views]]; 170 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view(>=150)]" options:0 metrics:nil views:views]]; 171 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[view2(>=50)]" options:0 metrics:nil views:views]]; 172 | } 173 | 174 | /** 175 | * 适当地使用 `options` 参数 176 | */ 177 | - (void)example7 { 178 | UIView *view = [UIView new]; 179 | [view setBackgroundColor:[UIColor redColor]]; 180 | [self.view addSubview:view]; 181 | 182 | UIView *view2 = [UIView new]; 183 | [view2 setBackgroundColor:[UIColor blueColor]]; 184 | [self.view addSubview:view2]; 185 | 186 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 187 | [view2 setTranslatesAutoresizingMaskIntoConstraints:NO]; 188 | 189 | NSDictionary *views = NSDictionaryOfVariableBindings(view, view2); 190 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[view(>=150)]-[view2(>=50)]" 191 | options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:views]]; 192 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view(>=150)]" options:0 metrics:nil views:views]]; 193 | } 194 | 195 | /** 196 | * 使用 `metrics` 参数 197 | */ 198 | - (void)example8 { 199 | UIView *view = [UIView new]; 200 | [view setBackgroundColor:[UIColor redColor]]; 201 | [self.view addSubview:view]; 202 | 203 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 204 | 205 | CGRect viewFrame = CGRectMake(50.f, 100.f, 150.f, 150.f); 206 | 207 | NSDictionary *views = NSDictionaryOfVariableBindings(view); 208 | 209 | NSDictionary *metrics = @{@"left": @(CGRectGetMinX(viewFrame)), 210 | @"top": @(CGRectGetMinY(viewFrame)), 211 | @"width": @(CGRectGetWidth(viewFrame)), 212 | @"height": @(CGRectGetHeight(viewFrame))}; 213 | 214 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-left-[view(>=width)]" options:0 metrics:metrics views:views]]; 215 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-top-[view(>=height)]" options:0 metrics:metrics views:views]]; 216 | } 217 | 218 | /** 219 | * 使用 `metrics` 参数的另一个方式 220 | */ 221 | - (void)example9 { 222 | UIView *view = [UIView new]; 223 | [view setBackgroundColor:[UIColor redColor]]; 224 | [self.view addSubview:view]; 225 | 226 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 227 | 228 | NSNumber *left = @50.f; 229 | NSNumber *top = @100.f; 230 | NSNumber *width = @150.f; 231 | NSNumber *height = @150.f; 232 | 233 | NSDictionary *views = NSDictionaryOfVariableBindings(view); 234 | NSDictionary *metrics = NSDictionaryOfVariableBindings(left, top, width, height); 235 | 236 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-left-[view(>=width)]" options:0 metrics:metrics views:views]]; 237 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-top-[view(>=height)]" options:0 metrics:metrics views:views]]; 238 | } 239 | 240 | /** 241 | * 修改约束优先级 242 | */ 243 | - (void)example10 { 244 | UIView *view = [UIView new]; 245 | [view setBackgroundColor:[UIColor redColor]]; 246 | [self.view addSubview:view]; 247 | 248 | CGRect viewFrame = CGRectMake(50.f, 100.f, 150.f, 150.f); 249 | 250 | // 使用 Auto Layout 布局 251 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 252 | 253 | // `view` 的左边距离 `self.view` 的左边 50 点. 254 | NSLayoutConstraint *viewLeft = [NSLayoutConstraint constraintWithItem:view 255 | attribute:NSLayoutAttributeLeading 256 | relatedBy:NSLayoutRelationEqual 257 | toItem:self.view 258 | attribute:NSLayoutAttributeLeading 259 | multiplier:1 260 | constant:CGRectGetMinX(viewFrame)]; 261 | // `view` 的顶部距离 `self.view` 的顶部 100 点. 262 | NSLayoutConstraint *viewTop = [NSLayoutConstraint constraintWithItem:view 263 | attribute:NSLayoutAttributeTop 264 | relatedBy:NSLayoutRelationEqual 265 | toItem:self.view 266 | attribute:NSLayoutAttributeTop 267 | multiplier:1 268 | constant:CGRectGetMinY(viewFrame)]; 269 | // `view` 的宽度 是 60 点. 270 | NSLayoutConstraint *viewWidth = [NSLayoutConstraint constraintWithItem:view 271 | attribute:NSLayoutAttributeWidth 272 | relatedBy:NSLayoutRelationGreaterThanOrEqual 273 | toItem:nil 274 | attribute:NSLayoutAttributeNotAnAttribute 275 | multiplier:1 276 | constant:CGRectGetWidth(viewFrame)]; 277 | // `view` 的高度是 60 点. 278 | NSLayoutConstraint *viewHeight = [NSLayoutConstraint constraintWithItem:view 279 | attribute:NSLayoutAttributeHeight 280 | relatedBy:NSLayoutRelationGreaterThanOrEqual 281 | toItem:nil 282 | attribute:NSLayoutAttributeNotAnAttribute 283 | multiplier:1 284 | constant:CGRectGetHeight(viewFrame)]; 285 | // `view` 紧贴着 `self.view` 的左边. 286 | NSLayoutConstraint *marginLeft = [NSLayoutConstraint constraintWithItem:view 287 | attribute:NSLayoutAttributeLeading 288 | relatedBy:NSLayoutRelationEqual 289 | toItem:self.view 290 | attribute:NSLayoutAttributeLeading 291 | multiplier:1 292 | constant:0]; 293 | viewLeft.priority = UILayoutPriorityDefaultHigh; 294 | 295 | // 把约束添加到父视图上. 296 | [self.view addConstraints:@[viewLeft, viewTop, viewWidth, viewHeight, marginLeft]]; 297 | } 298 | 299 | /** 300 | * 布局完成后修改优先级将会得到异常 301 | */ 302 | - (void)example11 { 303 | UIView *view = [UIView new]; 304 | [view setBackgroundColor:[UIColor redColor]]; 305 | [self.view addSubview:view]; 306 | 307 | CGRect viewFrame = CGRectMake(50.f, 100.f, 150.f, 150.f); 308 | 309 | // 使用 Auto Layout 布局 310 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 311 | 312 | // `view` 的左边距离 `self.view` 的左边 50 点. 313 | NSLayoutConstraint *viewLeft = [NSLayoutConstraint constraintWithItem:view 314 | attribute:NSLayoutAttributeLeading 315 | relatedBy:NSLayoutRelationEqual 316 | toItem:self.view 317 | attribute:NSLayoutAttributeLeading 318 | multiplier:1 319 | constant:CGRectGetMinX(viewFrame)]; 320 | // `view` 的顶部距离 `self.view` 的顶部 100 点. 321 | NSLayoutConstraint *viewTop = [NSLayoutConstraint constraintWithItem:view 322 | attribute:NSLayoutAttributeTop 323 | relatedBy:NSLayoutRelationEqual 324 | toItem:self.view 325 | attribute:NSLayoutAttributeTop 326 | multiplier:1 327 | constant:CGRectGetMinY(viewFrame)]; 328 | // `view` 的宽度 是 60 点. 329 | NSLayoutConstraint *viewWidth = [NSLayoutConstraint constraintWithItem:view 330 | attribute:NSLayoutAttributeWidth 331 | relatedBy:NSLayoutRelationGreaterThanOrEqual 332 | toItem:nil 333 | attribute:NSLayoutAttributeNotAnAttribute 334 | multiplier:1 335 | constant:CGRectGetWidth(viewFrame)]; 336 | // `view` 的高度是 60 点. 337 | NSLayoutConstraint *viewHeight = [NSLayoutConstraint constraintWithItem:view 338 | attribute:NSLayoutAttributeHeight 339 | relatedBy:NSLayoutRelationGreaterThanOrEqual 340 | toItem:nil 341 | attribute:NSLayoutAttributeNotAnAttribute 342 | multiplier:1 343 | constant:CGRectGetHeight(viewFrame)]; 344 | // `view` 紧贴着 `self.view` 的左边. 345 | NSLayoutConstraint *marginLeft = [NSLayoutConstraint constraintWithItem:view 346 | attribute:NSLayoutAttributeLeading 347 | relatedBy:NSLayoutRelationEqual 348 | toItem:self.view 349 | attribute:NSLayoutAttributeLeading 350 | multiplier:1 351 | constant:0]; 352 | viewLeft.priority = UILayoutPriorityDefaultHigh; 353 | 354 | // 把约束添加到父视图上. 355 | [self.view addConstraints:@[viewLeft, viewTop, viewWidth, viewHeight, marginLeft]]; 356 | 357 | // 等待布局完成 358 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 359 | viewLeft.priority = UILayoutPriorityRequired; 360 | }); 361 | } 362 | 363 | /** 364 | * 固有内容尺寸 365 | */ 366 | - (void)example12 { 367 | NSString *text = @"Auto Layout is a system that lets you lay out your app’s user interface by creating a mathematical description of the relationships between the elements. You define these relationships in terms of constraints either on individual elements, or between sets of elements. Using Auto Layout, you can create a dynamic and versatile interface that responds appropriately to changes in screen size, device orientation, and localization."; 368 | 369 | UILabel *label = [UILabel new]; 370 | label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; 371 | label.text = text; 372 | label.numberOfLines = 0; 373 | label.preferredMaxLayoutWidth = CGRectGetWidth(self.view.frame); 374 | [self.view addSubview:label]; 375 | 376 | [label setTranslatesAutoresizingMaskIntoConstraints:NO]; 377 | 378 | CGSize size = [label intrinsicContentSize]; 379 | 380 | NSDictionary *views = NSDictionaryOfVariableBindings(label); 381 | NSDictionary *metrics = @{@"width": @(size.width), @"height": @(size.height)}; 382 | 383 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label(<=width)]" options:0 metrics:metrics views:views]]; 384 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label(>=height)]" options:0 metrics:metrics views:views]]; 385 | } 386 | 387 | /** 388 | * 自定义视图的固有内容尺寸 389 | */ 390 | - (void)example13 { 391 | NSString *title = @"Auto Layout Guide"; 392 | NSString *body = @"Auto Layout is a system that lets you lay out your app’s user interface by creating a mathematical description of the relationships between the elements. You define these relationships in terms of constraints either on individual elements, or between sets of elements. Using Auto Layout, you can create a dynamic and versatile interface that responds appropriately to changes in screen size, device orientation, and localization."; 393 | 394 | VSLabel *label = [VSLabel new]; 395 | label.backgroundColor = [UIColor redColor]; 396 | label.title = title; 397 | label.body = body; 398 | label.translatesAutoresizingMaskIntoConstraints = NO; 399 | [self.view addSubview:label]; 400 | 401 | NSDictionary *views = NSDictionaryOfVariableBindings(label); 402 | 403 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[label]-|" options:0 metrics:nil views:views]]; 404 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[label]-|" options:0 metrics:nil views:views]]; 405 | 406 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 407 | NSLog(@"Intrinsic Content Size :%@", NSStringFromCGSize([label intrinsicContentSize])); 408 | label.bodyFont = [UIFont systemFontOfSize:16]; 409 | NSLog(@"Intrinsic Content Size :%@", NSStringFromCGSize([label intrinsicContentSize])); 410 | }); 411 | } 412 | 413 | /** 414 | * 内容压缩优先级(Content Hugging Priority) 415 | */ 416 | - (void)example14 { 417 | NSString *text = @"Auto Layout is a system that lets you lay out your app’s user interface by creating a mathematical description of the relationships between the elements. You define these relationships in terms of constraints either on individual elements, or between sets of elements. Using Auto Layout, you can create a dynamic and versatile interface that responds appropriately to changes in screen size, device orientation, and localization."; 418 | 419 | UILabel *label = [UILabel new]; 420 | label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; 421 | label.text = text; 422 | label.numberOfLines = 0; 423 | label.preferredMaxLayoutWidth = CGRectGetWidth(self.view.frame); 424 | label.backgroundColor = [UIColor purpleColor]; 425 | // [label setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; 426 | [self.view addSubview:label]; 427 | 428 | [label setTranslatesAutoresizingMaskIntoConstraints:NO]; 429 | 430 | CGSize size = [label intrinsicContentSize]; 431 | CGFloat delta = 50.f; 432 | 433 | NSDictionary *views = NSDictionaryOfVariableBindings(label); 434 | NSDictionary *metrics = @{@"width": @(size.width), @"height": @(size.height + delta)}; 435 | 436 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label(<=width)]" options:0 metrics:metrics views:views]]; 437 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label(>=height@249)]" options:0 metrics:metrics views:views]]; 438 | } 439 | 440 | /** 441 | * 内容抗压缩优先级(Content Compression Resistance Priority) 442 | */ 443 | - (void)example15 { 444 | NSString *text = @"Auto Layout is a system that lets you lay out your app’s user interface by creating a mathematical description of the relationships between the elements. You define these relationships in terms of constraints either on individual elements, or between sets of elements. Using Auto Layout, you can create a dynamic and versatile interface that responds appropriately to changes in screen size, device orientation, and localization."; 445 | 446 | UILabel *label = [UILabel new]; 447 | label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; 448 | label.text = text; 449 | label.numberOfLines = 0; 450 | label.preferredMaxLayoutWidth = CGRectGetWidth(self.view.frame); 451 | label.backgroundColor = [UIColor purpleColor]; 452 | // [label setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; 453 | [self.view addSubview:label]; 454 | 455 | [label setTranslatesAutoresizingMaskIntoConstraints:NO]; 456 | 457 | CGSize size = [label intrinsicContentSize]; 458 | CGFloat delta = -50.f; 459 | 460 | NSDictionary *views = NSDictionaryOfVariableBindings(label); 461 | NSDictionary *metrics = @{@"width": @(size.width), @"height": @(size.height + delta)}; 462 | 463 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label(<=width)]" options:0 metrics:metrics views:views]]; 464 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label(<=height@749)]" options:0 metrics:metrics views:views]]; 465 | } 466 | 467 | 468 | - (void)example16 { 469 | UIView *view = [UIView new]; 470 | [view setBackgroundColor:[UIColor redColor]]; 471 | [self.view addSubview:view]; 472 | 473 | [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 474 | 475 | NSDictionary *views = NSDictionaryOfVariableBindings(view); 476 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[view(>=150)]" options:0 metrics:nil views:views]]; 477 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[view(<=150)]-|" options:0 metrics:nil views:views]]; 478 | } 479 | 480 | 481 | - (void)example17 { 482 | VSLayoutExample1 *view = [VSLayoutExample1 newAutoLayoutView]; 483 | [self.view addSubview:view]; 484 | 485 | [view autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsZero excludingEdge:ALEdgeBottom]; 486 | [view autoSetDimension:ALDimensionHeight toSize:[view intrinsicContentSize].height]; 487 | } 488 | 489 | 490 | 491 | 492 | #pragma mark - 493 | 494 | - (BOOL)prefersStatusBarHidden { 495 | return YES; 496 | } 497 | 498 | 499 | @end 500 | --------------------------------------------------------------------------------