├── .gitignore ├── Example ├── UILayoutBuilderApp.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── UILayoutBuilderApp.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── UILayoutBuilderApp │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── SceneDelegate.swift │ └── ViewController.swift ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── UILayoutBuilder │ ├── ConstrantGroupType.swift │ ├── Extension │ ├── UIStackViewExtension.swift │ └── ULBViewExtension.swift │ ├── Internal │ ├── Builder.swift │ ├── ConstraintUpdater.swift │ └── Context.swift │ ├── LayoutAnchorType.swift │ ├── LayoutAxes.swift │ ├── LayoutAxis.swift │ ├── LayoutDimension.swift │ ├── LayoutEdges.swift │ ├── LayoutGuideProxy.swift │ ├── LayoutRepresentable.swift │ ├── LayoutSize.swift │ ├── UILayoutBuilder.swift │ ├── ULBTypealias.swift │ └── ViewProxy.swift ├── Tests ├── LinuxMain.swift └── UILayoutBuilderTests │ ├── UILayoutBuilderTests.swift │ └── XCTestManifests.swift ├── UILayoutBuilder.podspec └── UILayoutBuilder.xcodeproj ├── UILayoutBuilderTests_Info.plist ├── UILayoutBuilder_Info.plist ├── project.pbxproj ├── project.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings └── xcshareddata └── xcschemes ├── UILayoutBuilder-Package.xcscheme └── UILayoutBuilder.xcscheme /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | .DS_Store 6 | 7 | ## User settings 8 | xcuserdata/ 9 | 10 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 11 | *.xcscmblueprint 12 | *.xccheckout 13 | 14 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 15 | build/ 16 | DerivedData/ 17 | *.moved-aside 18 | *.pbxuser 19 | !default.pbxuser 20 | *.mode1v3 21 | !default.mode1v3 22 | *.mode2v3 23 | !default.mode2v3 24 | *.perspectivev3 25 | !default.perspectivev3 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | 30 | ## App packaging 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | ## Playgrounds 36 | timeline.xctimeline 37 | playground.xcworkspace 38 | 39 | # Swift Package Manager 40 | # 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | # *.xcodeproj 46 | # 47 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 48 | # hence it is not needed unless you have added a package configuration file to your project 49 | .swiftpm 50 | 51 | .build/ 52 | 53 | # CocoaPods 54 | # 55 | # We recommend against adding the Pods directory to your .gitignore. However 56 | # you should judge for yourself, the pros and cons are mentioned at: 57 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 58 | # 59 | # Pods/ 60 | # 61 | # Add this line if you want to avoid checking in source code from the Xcode workspace 62 | # *.xcworkspace 63 | 64 | # Carthage 65 | # 66 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 67 | # Carthage/Checkouts 68 | 69 | Carthage/Build/ 70 | 71 | # Accio dependency management 72 | Dependencies/ 73 | .accio/ 74 | 75 | # fastlane 76 | # 77 | # It is recommended to not store the screenshots in the git repo. 78 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 79 | # For more information about the recommended setup visit: 80 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 81 | 82 | fastlane/report.xml 83 | fastlane/Preview.html 84 | fastlane/screenshots/**/*.png 85 | fastlane/test_output 86 | 87 | # Code Injection 88 | # 89 | # After new code Injection tools there's a generated folder /iOSInjectionProject 90 | # https://github.com/johnno1962/injectionforxcode 91 | 92 | iOSInjectionProject/ 93 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | EDA5406A23E9DD81009A41C5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA5406923E9DD81009A41C5 /* AppDelegate.swift */; }; 11 | EDA5406C23E9DD81009A41C5 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA5406B23E9DD81009A41C5 /* SceneDelegate.swift */; }; 12 | EDA5406E23E9DD81009A41C5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA5406D23E9DD81009A41C5 /* ViewController.swift */; }; 13 | EDA5407123E9DD81009A41C5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EDA5406F23E9DD81009A41C5 /* Main.storyboard */; }; 14 | EDA5407323E9DD82009A41C5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EDA5407223E9DD82009A41C5 /* Assets.xcassets */; }; 15 | EDA5407623E9DD82009A41C5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EDA5407423E9DD82009A41C5 /* LaunchScreen.storyboard */; }; 16 | EDA5407F23E9DDD2009A41C5 /* UILayoutBuilder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDA5407E23E9DDD2009A41C5 /* UILayoutBuilder.framework */; }; 17 | EDA5408023E9DDD2009A41C5 /* UILayoutBuilder.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EDA5407E23E9DDD2009A41C5 /* UILayoutBuilder.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXCopyFilesBuildPhase section */ 21 | EDA5408123E9DDD2009A41C5 /* Embed Frameworks */ = { 22 | isa = PBXCopyFilesBuildPhase; 23 | buildActionMask = 2147483647; 24 | dstPath = ""; 25 | dstSubfolderSpec = 10; 26 | files = ( 27 | EDA5408023E9DDD2009A41C5 /* UILayoutBuilder.framework in Embed Frameworks */, 28 | ); 29 | name = "Embed Frameworks"; 30 | runOnlyForDeploymentPostprocessing = 0; 31 | }; 32 | /* End PBXCopyFilesBuildPhase section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | EDA5406623E9DD81009A41C5 /* UILayoutBuilderApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UILayoutBuilderApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | EDA5406923E9DD81009A41C5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | EDA5406B23E9DD81009A41C5 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 38 | EDA5406D23E9DD81009A41C5 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 39 | EDA5407023E9DD81009A41C5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 40 | EDA5407223E9DD82009A41C5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 41 | EDA5407523E9DD82009A41C5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 42 | EDA5407723E9DD82009A41C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | EDA5407E23E9DDD2009A41C5 /* UILayoutBuilder.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = UILayoutBuilder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | /* End PBXFileReference section */ 45 | 46 | /* Begin PBXFrameworksBuildPhase section */ 47 | EDA5406323E9DD81009A41C5 /* Frameworks */ = { 48 | isa = PBXFrameworksBuildPhase; 49 | buildActionMask = 2147483647; 50 | files = ( 51 | EDA5407F23E9DDD2009A41C5 /* UILayoutBuilder.framework in Frameworks */, 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | EDA5405D23E9DD81009A41C5 = { 59 | isa = PBXGroup; 60 | children = ( 61 | EDA5406823E9DD81009A41C5 /* UILayoutBuilderApp */, 62 | EDA5406723E9DD81009A41C5 /* Products */, 63 | EDA5407D23E9DDD2009A41C5 /* Frameworks */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | EDA5406723E9DD81009A41C5 /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | EDA5406623E9DD81009A41C5 /* UILayoutBuilderApp.app */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | EDA5406823E9DD81009A41C5 /* UILayoutBuilderApp */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | EDA5406923E9DD81009A41C5 /* AppDelegate.swift */, 79 | EDA5406B23E9DD81009A41C5 /* SceneDelegate.swift */, 80 | EDA5406D23E9DD81009A41C5 /* ViewController.swift */, 81 | EDA5406F23E9DD81009A41C5 /* Main.storyboard */, 82 | EDA5407223E9DD82009A41C5 /* Assets.xcassets */, 83 | EDA5407423E9DD82009A41C5 /* LaunchScreen.storyboard */, 84 | EDA5407723E9DD82009A41C5 /* Info.plist */, 85 | ); 86 | path = UILayoutBuilderApp; 87 | sourceTree = ""; 88 | }; 89 | EDA5407D23E9DDD2009A41C5 /* Frameworks */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | EDA5407E23E9DDD2009A41C5 /* UILayoutBuilder.framework */, 93 | ); 94 | name = Frameworks; 95 | sourceTree = ""; 96 | }; 97 | /* End PBXGroup section */ 98 | 99 | /* Begin PBXNativeTarget section */ 100 | EDA5406523E9DD81009A41C5 /* UILayoutBuilderApp */ = { 101 | isa = PBXNativeTarget; 102 | buildConfigurationList = EDA5407A23E9DD82009A41C5 /* Build configuration list for PBXNativeTarget "UILayoutBuilderApp" */; 103 | buildPhases = ( 104 | EDA5406223E9DD81009A41C5 /* Sources */, 105 | EDA5406323E9DD81009A41C5 /* Frameworks */, 106 | EDA5406423E9DD81009A41C5 /* Resources */, 107 | EDA5408123E9DDD2009A41C5 /* Embed Frameworks */, 108 | ); 109 | buildRules = ( 110 | ); 111 | dependencies = ( 112 | ); 113 | name = UILayoutBuilderApp; 114 | productName = UILayoutBuilderApp; 115 | productReference = EDA5406623E9DD81009A41C5 /* UILayoutBuilderApp.app */; 116 | productType = "com.apple.product-type.application"; 117 | }; 118 | /* End PBXNativeTarget section */ 119 | 120 | /* Begin PBXProject section */ 121 | EDA5405E23E9DD81009A41C5 /* Project object */ = { 122 | isa = PBXProject; 123 | attributes = { 124 | LastSwiftUpdateCheck = 1130; 125 | LastUpgradeCheck = 1130; 126 | ORGANIZATIONNAME = "marty-suzuki"; 127 | TargetAttributes = { 128 | EDA5406523E9DD81009A41C5 = { 129 | CreatedOnToolsVersion = 11.3.1; 130 | }; 131 | }; 132 | }; 133 | buildConfigurationList = EDA5406123E9DD81009A41C5 /* Build configuration list for PBXProject "UILayoutBuilderApp" */; 134 | compatibilityVersion = "Xcode 9.3"; 135 | developmentRegion = en; 136 | hasScannedForEncodings = 0; 137 | knownRegions = ( 138 | en, 139 | Base, 140 | ); 141 | mainGroup = EDA5405D23E9DD81009A41C5; 142 | productRefGroup = EDA5406723E9DD81009A41C5 /* Products */; 143 | projectDirPath = ""; 144 | projectRoot = ""; 145 | targets = ( 146 | EDA5406523E9DD81009A41C5 /* UILayoutBuilderApp */, 147 | ); 148 | }; 149 | /* End PBXProject section */ 150 | 151 | /* Begin PBXResourcesBuildPhase section */ 152 | EDA5406423E9DD81009A41C5 /* Resources */ = { 153 | isa = PBXResourcesBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | EDA5407623E9DD82009A41C5 /* LaunchScreen.storyboard in Resources */, 157 | EDA5407323E9DD82009A41C5 /* Assets.xcassets in Resources */, 158 | EDA5407123E9DD81009A41C5 /* Main.storyboard in Resources */, 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXResourcesBuildPhase section */ 163 | 164 | /* Begin PBXSourcesBuildPhase section */ 165 | EDA5406223E9DD81009A41C5 /* Sources */ = { 166 | isa = PBXSourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | EDA5406E23E9DD81009A41C5 /* ViewController.swift in Sources */, 170 | EDA5406A23E9DD81009A41C5 /* AppDelegate.swift in Sources */, 171 | EDA5406C23E9DD81009A41C5 /* SceneDelegate.swift in Sources */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXSourcesBuildPhase section */ 176 | 177 | /* Begin PBXVariantGroup section */ 178 | EDA5406F23E9DD81009A41C5 /* Main.storyboard */ = { 179 | isa = PBXVariantGroup; 180 | children = ( 181 | EDA5407023E9DD81009A41C5 /* Base */, 182 | ); 183 | name = Main.storyboard; 184 | sourceTree = ""; 185 | }; 186 | EDA5407423E9DD82009A41C5 /* LaunchScreen.storyboard */ = { 187 | isa = PBXVariantGroup; 188 | children = ( 189 | EDA5407523E9DD82009A41C5 /* Base */, 190 | ); 191 | name = LaunchScreen.storyboard; 192 | sourceTree = ""; 193 | }; 194 | /* End PBXVariantGroup section */ 195 | 196 | /* Begin XCBuildConfiguration section */ 197 | EDA5407823E9DD82009A41C5 /* Debug */ = { 198 | isa = XCBuildConfiguration; 199 | buildSettings = { 200 | ALWAYS_SEARCH_USER_PATHS = NO; 201 | CLANG_ANALYZER_NONNULL = YES; 202 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 203 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 204 | CLANG_CXX_LIBRARY = "libc++"; 205 | CLANG_ENABLE_MODULES = YES; 206 | CLANG_ENABLE_OBJC_ARC = YES; 207 | CLANG_ENABLE_OBJC_WEAK = YES; 208 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_COMMA = YES; 211 | CLANG_WARN_CONSTANT_CONVERSION = YES; 212 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 213 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 214 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 215 | CLANG_WARN_EMPTY_BODY = YES; 216 | CLANG_WARN_ENUM_CONVERSION = YES; 217 | CLANG_WARN_INFINITE_RECURSION = YES; 218 | CLANG_WARN_INT_CONVERSION = YES; 219 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 220 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 221 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 222 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 223 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 224 | CLANG_WARN_STRICT_PROTOTYPES = YES; 225 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 226 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 227 | CLANG_WARN_UNREACHABLE_CODE = YES; 228 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 229 | COPY_PHASE_STRIP = NO; 230 | DEBUG_INFORMATION_FORMAT = dwarf; 231 | ENABLE_STRICT_OBJC_MSGSEND = YES; 232 | ENABLE_TESTABILITY = YES; 233 | GCC_C_LANGUAGE_STANDARD = gnu11; 234 | GCC_DYNAMIC_NO_PIC = NO; 235 | GCC_NO_COMMON_BLOCKS = YES; 236 | GCC_OPTIMIZATION_LEVEL = 0; 237 | GCC_PREPROCESSOR_DEFINITIONS = ( 238 | "DEBUG=1", 239 | "$(inherited)", 240 | ); 241 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 242 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 243 | GCC_WARN_UNDECLARED_SELECTOR = YES; 244 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 245 | GCC_WARN_UNUSED_FUNCTION = YES; 246 | GCC_WARN_UNUSED_VARIABLE = YES; 247 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 248 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 249 | MTL_FAST_MATH = YES; 250 | ONLY_ACTIVE_ARCH = YES; 251 | SDKROOT = iphoneos; 252 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 253 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 254 | }; 255 | name = Debug; 256 | }; 257 | EDA5407923E9DD82009A41C5 /* Release */ = { 258 | isa = XCBuildConfiguration; 259 | buildSettings = { 260 | ALWAYS_SEARCH_USER_PATHS = NO; 261 | CLANG_ANALYZER_NONNULL = YES; 262 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 263 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 264 | CLANG_CXX_LIBRARY = "libc++"; 265 | CLANG_ENABLE_MODULES = YES; 266 | CLANG_ENABLE_OBJC_ARC = YES; 267 | CLANG_ENABLE_OBJC_WEAK = YES; 268 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 269 | CLANG_WARN_BOOL_CONVERSION = YES; 270 | CLANG_WARN_COMMA = YES; 271 | CLANG_WARN_CONSTANT_CONVERSION = YES; 272 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 273 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 274 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INFINITE_RECURSION = YES; 278 | CLANG_WARN_INT_CONVERSION = YES; 279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 280 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 281 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 282 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 283 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 284 | CLANG_WARN_STRICT_PROTOTYPES = YES; 285 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 286 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 287 | CLANG_WARN_UNREACHABLE_CODE = YES; 288 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 289 | COPY_PHASE_STRIP = NO; 290 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 291 | ENABLE_NS_ASSERTIONS = NO; 292 | ENABLE_STRICT_OBJC_MSGSEND = YES; 293 | GCC_C_LANGUAGE_STANDARD = gnu11; 294 | GCC_NO_COMMON_BLOCKS = YES; 295 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 296 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 297 | GCC_WARN_UNDECLARED_SELECTOR = YES; 298 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 299 | GCC_WARN_UNUSED_FUNCTION = YES; 300 | GCC_WARN_UNUSED_VARIABLE = YES; 301 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 302 | MTL_ENABLE_DEBUG_INFO = NO; 303 | MTL_FAST_MATH = YES; 304 | SDKROOT = iphoneos; 305 | SWIFT_COMPILATION_MODE = wholemodule; 306 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 307 | VALIDATE_PRODUCT = YES; 308 | }; 309 | name = Release; 310 | }; 311 | EDA5407B23E9DD82009A41C5 /* Debug */ = { 312 | isa = XCBuildConfiguration; 313 | buildSettings = { 314 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 315 | CODE_SIGN_STYLE = Automatic; 316 | INFOPLIST_FILE = UILayoutBuilderApp/Info.plist; 317 | LD_RUNPATH_SEARCH_PATHS = ( 318 | "$(inherited)", 319 | "@executable_path/Frameworks", 320 | ); 321 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.UILayoutBuilderApp"; 322 | PRODUCT_NAME = "$(TARGET_NAME)"; 323 | SWIFT_VERSION = 5.0; 324 | TARGETED_DEVICE_FAMILY = "1,2"; 325 | }; 326 | name = Debug; 327 | }; 328 | EDA5407C23E9DD82009A41C5 /* Release */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 332 | CODE_SIGN_STYLE = Automatic; 333 | INFOPLIST_FILE = UILayoutBuilderApp/Info.plist; 334 | LD_RUNPATH_SEARCH_PATHS = ( 335 | "$(inherited)", 336 | "@executable_path/Frameworks", 337 | ); 338 | PRODUCT_BUNDLE_IDENTIFIER = "jp.marty-suzuki.UILayoutBuilderApp"; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | SWIFT_VERSION = 5.0; 341 | TARGETED_DEVICE_FAMILY = "1,2"; 342 | }; 343 | name = Release; 344 | }; 345 | /* End XCBuildConfiguration section */ 346 | 347 | /* Begin XCConfigurationList section */ 348 | EDA5406123E9DD81009A41C5 /* Build configuration list for PBXProject "UILayoutBuilderApp" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | EDA5407823E9DD82009A41C5 /* Debug */, 352 | EDA5407923E9DD82009A41C5 /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | EDA5407A23E9DD82009A41C5 /* Build configuration list for PBXNativeTarget "UILayoutBuilderApp" */ = { 358 | isa = XCConfigurationList; 359 | buildConfigurations = ( 360 | EDA5407B23E9DD82009A41C5 /* Debug */, 361 | EDA5407C23E9DD82009A41C5 /* Release */, 362 | ); 363 | defaultConfigurationIsVisible = 0; 364 | defaultConfigurationName = Release; 365 | }; 366 | /* End XCConfigurationList section */ 367 | }; 368 | rootObject = EDA5405E23E9DD81009A41C5 /* Project object */; 369 | } 370 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // UILayoutBuilderApp 4 | // 5 | // Created by marty-suzuki on 2020/02/05. 6 | // Copyright © 2020 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | // MARK: UISceneSession Lifecycle 22 | 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // UILayoutBuilderApp 4 | // 5 | // Created by marty-suzuki on 2020/02/05. 6 | // Copyright © 2020 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 20 | guard let _ = (scene as? UIWindowScene) else { return } 21 | } 22 | 23 | func sceneDidDisconnect(_ scene: UIScene) { 24 | // Called as the scene is being released by the system. 25 | // This occurs shortly after the scene enters the background, or when its session is discarded. 26 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 28 | } 29 | 30 | func sceneDidBecomeActive(_ scene: UIScene) { 31 | // Called when the scene has moved from an inactive state to an active state. 32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 33 | } 34 | 35 | func sceneWillResignActive(_ scene: UIScene) { 36 | // Called when the scene will move from an active state to an inactive state. 37 | // This may occur due to temporary interruptions (ex. an incoming phone call). 38 | } 39 | 40 | func sceneWillEnterForeground(_ scene: UIScene) { 41 | // Called as the scene transitions from the background to the foreground. 42 | // Use this method to undo the changes made on entering the background. 43 | } 44 | 45 | func sceneDidEnterBackground(_ scene: UIScene) { 46 | // Called as the scene transitions from the foreground to the background. 47 | // Use this method to save data, release shared resources, and store enough scene-specific state information 48 | // to restore the scene back to its current state. 49 | } 50 | 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /Example/UILayoutBuilderApp/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // UILayoutBuilderApp 4 | // 5 | // Created by marty-suzuki on 2020/02/05. 6 | // Copyright © 2020 marty-suzuki. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import UILayoutBuilder 11 | 12 | class ViewController: UIViewController { 13 | 14 | private let greenView: UIView = { 15 | let view = UIView(frame: .zero) 16 | view.backgroundColor = .green 17 | return view 18 | }() 19 | 20 | private let whiteView: UIView = { 21 | let view = UIView(frame: .zero) 22 | view.backgroundColor = .white 23 | return view 24 | }() 25 | 26 | private let redView: UIView = { 27 | let view = UIView(frame: .zero) 28 | view.backgroundColor = .red 29 | return view 30 | }() 31 | 32 | private var greenViewBottomConstraint: NSLayoutConstraint? 33 | private var whiteViewWidthConstraint: NSLayoutConstraint? 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | 38 | let yellowView = UIView() 39 | yellowView.backgroundColor = .yellow 40 | 41 | view.ulb.add.subview(yellowView, redView) { view, yellowView, redView in 42 | 43 | redView.top.equalTo.top(view.safeAreaLayoutGuide).constant(-10) 44 | redView.leading.equalTo.leading(view.safeAreaLayoutGuide).constant(10) 45 | redView.trailing.equalTo.trailing(view.safeAreaLayoutGuide).constant(-10) 46 | redView.height.equalTo.height(view.safeAreaLayoutGuide).multiplier(0.5).constant(-15) 47 | 48 | yellowView.top.equalTo.bottom(redView).constant(10) 49 | yellowView.leading.equalTo.leading(view.safeAreaLayoutGuide).constant(10) 50 | yellowView.trailing.equalTo.trailing(view.safeAreaLayoutGuide).constant(-10) 51 | yellowView.height.equalTo.height(view.safeAreaLayoutGuide).multiplier(0.5).constant(-15) 52 | 53 | yellowView.add.subview(greenView) { greenView in 54 | greenView.top.equalTo.top(yellowView) 55 | greenView.trailing.equalTo.trailing(yellowView) 56 | greenViewBottomConstraint = greenView.bottom.equalTo.bottom(yellowView).asConstraint() 57 | greenView.width.equalTo.width(yellowView).multiplier(0.5) 58 | } 59 | 60 | redView.add.subview(whiteView) { whiteView in 61 | whiteView.bottom.equalTo.bottom(redView).constant(-10) 62 | whiteView.leading.equalTo.leading(redView).constant(10) 63 | whiteView.height.equalTo.constant(100) 64 | } 65 | } 66 | 67 | updateWhiteViewConstraint() 68 | } 69 | 70 | override func viewDidAppear(_ animated: Bool) { 71 | super.viewDidAppear(animated) 72 | reduceAnimation() 73 | } 74 | 75 | override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { 76 | super.traitCollectionDidChange(previousTraitCollection) 77 | updateWhiteViewConstraint() 78 | } 79 | 80 | private func updateWhiteViewConstraint() { 81 | self.whiteViewWidthConstraint?.isActive = false 82 | 83 | let whiteView = self.whiteView.ulb.asProxy() 84 | let redView = self.redView.ulb.asProxy() 85 | 86 | let constraint: NSLayoutConstraint 87 | if traitCollection.verticalSizeClass == .regular && traitCollection.horizontalSizeClass == .compact { 88 | constraint = whiteView.width.equalTo.width(redView).constant(-10).multiplier(0.5).asConstraint() 89 | } else { 90 | constraint = whiteView.width.equalTo.width(redView).constant(-20).asConstraint() 91 | } 92 | constraint.isActive = true 93 | self.whiteViewWidthConstraint = constraint 94 | } 95 | 96 | private func stretchAnmation() { 97 | greenViewBottomConstraint?.constant = 0 98 | UIView.animate(withDuration: 2, animations: { 99 | self.greenView.superview?.layoutIfNeeded() 100 | }) { _ in 101 | self.reduceAnimation() 102 | } 103 | } 104 | 105 | private func reduceAnimation() { 106 | let constant = self.greenView.superview?.frame.size.height ?? 0 107 | greenViewBottomConstraint?.constant = -constant / 2 108 | UIView.animate(withDuration: 2, animations: { 109 | self.greenView.superview?.layoutIfNeeded() 110 | }) { _ in 111 | self.stretchAnmation() 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Taiki Suzuki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "UILayoutBuilder", 8 | platforms: [ 9 | .iOS(.v10), .tvOS(.v10), .macOS(.v10_11) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 13 | .library( 14 | name: "UILayoutBuilder", 15 | targets: ["UILayoutBuilder"]), 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 24 | .target( 25 | name: "UILayoutBuilder", 26 | dependencies: []), 27 | .testTarget( 28 | name: "UILayoutBuilderTests", 29 | dependencies: ["UILayoutBuilder"]), 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UILayoutBuilder 📱🛠 2 | 3 |

4 | Carthage compatible 5 | LICENSE 6 |
7 | 8 | CocoaPods 9 | 10 | 11 | Carthage compatible 12 | 13 | 14 | Carthage compatible 15 | 16 |

17 | 18 | Using UILayoutBuilder, make it easy to see constraints with view hierarchy.
19 | In addition, you can find a constraint method easily by auto-completion with first one or two charactors. 20 | 21 | ![auto-completion](https://user-images.githubusercontent.com/2082134/74106399-1827b380-4baa-11ea-9e17-2c728ed7ca56.gif) 22 | 23 | You can replace: 24 | 25 | ```swift 26 | view.addSubview(subview) 27 | subview.translatesAutoresizingMaskIntoConstraints = false 28 | NSLayoutConstraint.activate([ 29 | subview.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), 30 | subview.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), 31 | subview.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10), 32 | subview.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10), 33 | ]) 34 | ``` 35 | to 36 | 37 | ```swift 38 | view.ulb.add.subview(subview) { view, subview in 39 | subview.top.equalTo.top(view.safeAreaLayoutGuide).constant(10) 40 | subview.leading.equalTo.leading(view).constant(10) 41 | subview.bottom.equalTo.bottom(view.safeAreaLayoutGuide).constant(-10) 42 | subview.trailing.equalTo.trailing(view).constant(-10) 43 | } 44 | ``` 45 | 46 | ## Installation 47 | 48 | ### Carthage 49 | 50 | If you’re using [Carthage](https://github.com/Carthage/Carthage), simply add 51 | UILayoutBuilder to your `Cartfile`: 52 | 53 | ```ruby 54 | github "marty-suzuki/UILayoutBuilder" 55 | ``` 56 | 57 | ### CocoaPods 58 | 59 | UILayoutBuilder is available through [CocoaPods](https://cocoapods.org). To install 60 | it, simply add the following line to your Podfile: 61 | 62 | ```ruby 63 | pod "UILayoutBuilder" 64 | ``` 65 | 66 | ### Swift Package Manager 67 | 68 | Simply add the following line to your `Package.swift`: 69 | 70 | ``` 71 | .package(url: "https://github.com/marty-suzuki/UILayoutBuilder.git", from: "version") 72 | ``` 73 | 74 | ## Usage 75 | 76 | Start with `ulb.add.subview`, receives proxy of superview and subview. Call `proxy.add.subview`, receives proxy of subviews only.
77 | You can constrain for AutoLayout using them. 78 | 79 | 80 | 81 | ```swift 82 | view.ulb.add.subview(grayview) { view, grayview in 83 | grayview.edges.equalTo.edges(view.safeAreaLayoutGuide).constant(10) 84 | 85 | grayview.add.subview(greenview, whiteview) { greenview, whiteview in 86 | greenview.size.equalTo.constant(width: 100, height: 100) 87 | greenview.center.equalTo.center(view).constant(x: -50, y: 0) 88 | whiteview.leading.equalTo.trailing(greenview) 89 | whiteview.top.equalTo.top(greenview) 90 | whiteview.size.equalTo.size(greenview) 91 | } 92 | } 93 | ``` 94 | 95 | For every view added by `ulb.add.subview` or `proxy.add.subview` will automatically set its `translatesAutoresizingMaskIntoConstraints` property to `false`. 96 | 97 | ### Axis 98 | 99 | ```swift 100 | subview.top.equalTo.top(view).constant(10) 101 | // subview.topAnchor.constraint(equalTo: view.topAnchor, constant: 10) 102 | 103 | subview.top.greaterThanOrEqualTo.top(view).constant(10) 104 | // subview.topAnchor.constraint(greaterThanOrEqualTo: view.topAnchor, constant: 10) 105 | 106 | subview.top.lessThanOrEqualTo.top(view).constant(10) 107 | // subview.topAnchor.constraint(lessThanOrEqualTo: view.topAnchor, constant: 10) 108 | 109 | subview.center.equalTo.center(view).constant(x: 100, y: 100) 110 | // subview.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 50) 111 | // subview.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50) 112 | 113 | subview.horizontal.equalTo.horizontal(view).constant(leading: 10, trailing: -10) 114 | // subview.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10) 115 | // subview.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10) 116 | 117 | subview.vertical.equalTo.vertical(view).constant(top: 10, bottom: -10) 118 | // subview.topAnchor.constraint(equalTo: view.topAnchor, constant: 10) 119 | // subview.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10) 120 | 121 | subview.edges.equalTo.edges(view).constant(10) 122 | // or 123 | subview.edges.equalTo.edges(view).constant(top: 10, leading: 10, bottom: -10, trailing: -10) 124 | // subview.topAnchor.constraint(equalTo: view.topAnchor, constant: 10) 125 | // subview.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10) 126 | // subview.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10) 127 | // subview.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10) 128 | ``` 129 | 130 | ### Dimension 131 | 132 | ```swift 133 | subview.height.equalTo.height(view) 134 | // subview.heightAnchor.constraint(equalTo: view.heightAnchor) 135 | 136 | subview.width.equalTo.width(view).multiplier(0.5).constant(100) 137 | // subview.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5, constant: 100) 138 | 139 | subview.height.equalTo.constant(100) 140 | // subview.heightAnchor.constraint(equalToConstant: 100) 141 | 142 | subview.size.equalTo.size(view) 143 | // subview.heightAnchor.constraint(equalTo: view.heightAnchor) 144 | // subview.widthAnchor.constraint(equalTo: view.widthAnchor) 145 | 146 | subview.size.equalTo.constant(width: 100, height: 100) 147 | // subview.heightAnchor.constraint(equalToConstant: 100) 148 | // subview.widthAnchor.constraint(equalToConstant: 100) 149 | ``` 150 | 151 | ### Priority 152 | 153 | ```swift 154 | subview.width.equalTo.width(view).priority(.required) 155 | // subview.widthAnchor.constraint(equalTo: view.widthAnchor).priority = .required 156 | ``` 157 | 158 | ### Constraints 159 | 160 | ```swift 161 | let constraint: NSLayoutConstraint = subview.width.equalTo.width(view).asConstraint() 162 | ``` 163 | 164 | ```swift 165 | let constraints = subview.edges.equalTo.edges(view).asConstraints() 166 | let top: NSLayoutConstraint = constraints.top 167 | let leading: NSLayoutConstraint = constraints.leading 168 | let bottom: NSLayoutConstraint = constraints.bottom 169 | let trailing: NSLayoutConstraint = constraints.trailing 170 | ``` 171 | 172 | ```swift 173 | let constraints = subview.size.equalTo.size(view).asConstraints() 174 | let width: NSLayoutConstraint = constraints.width 175 | let height: NSLayoutConstraint = constraints.height 176 | ``` 177 | 178 | ```swift 179 | let constraints = subview.center.equalTo.center(view).asConstraints() 180 | let x: NSLayoutConstraint = constraints.x 181 | let y: NSLayoutConstraint = constraints.y 182 | ``` 183 | 184 | ```swift 185 | let constraints = subview.horizontal.equalTo.horizontal(view).asConstraints() 186 | let leading: NSLayoutConstraint = constraints.leading 187 | let trailing: NSLayoutConstraint = constraints.trailing 188 | ``` 189 | 190 | ```swift 191 | let constraints = subview.vertical.equalTo.vertical(view).asConstraints() 192 | let top: NSLayoutConstraint = constraints.top 193 | let bottom: NSLayoutConstraint = constraints.bottom 194 | ``` 195 | 196 | ## Requirements 197 | 198 | - Xcode 11.3.1 or greater 199 | - iOS 10.0 or greater 200 | - tvOS 10.0 or greater 201 | - macOS 10.11 or greater 202 | 203 | ## Author 204 | 205 | Taiki Suzuki, s1180183@gmail.com 206 | 207 | ## LICENSE 208 | 209 | Under the MIT license. See LICENSE file for details. -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/ConstrantGroupType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConstrantGroupType.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/10. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public protocol ConstrantGroupType { 15 | func activate() 16 | func deactivate() 17 | } 18 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/Extension/UIStackViewExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIStackViewExtension.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/10. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | 11 | extension UIStackView { 12 | @objc override func _add(subview: UIView) { 13 | addArrangedSubview(subview) 14 | } 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/Extension/ULBViewExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ULBViewExtension.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/09. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | extension ULBView { 15 | @objc func _add(subview: ULBView) { 16 | addSubview(subview) 17 | } 18 | } 19 | 20 | extension ULBView: UILayoutBuilderCompatible {} 21 | 22 | extension UILayoutBuilderExtension where Base: ULBView { 23 | 24 | public var add: ULBViewAddSubview { 25 | .init(base: base) 26 | } 27 | 28 | public func asProxy() -> ViewProxy { 29 | .init(view: base, context: .init()) 30 | } 31 | } 32 | 33 | public struct ULBViewAddSubview { 34 | fileprivate let base: ULBView 35 | } 36 | 37 | extension ULBViewAddSubview { 38 | 39 | public func subview(_ subview: ULBView, handler: (ViewProxy, ViewProxy) -> Void = { _, _ in }) { 40 | subview.translatesAutoresizingMaskIntoConstraints = false 41 | base._add(subview: subview) 42 | 43 | let context = Context() 44 | handler( 45 | ViewProxy(view: base, context: context), 46 | ViewProxy(view: subview, context: context) 47 | ) 48 | NSLayoutConstraint.activate(context.buildConstraints()) 49 | } 50 | 51 | public func subview( 52 | _ subview1: ULBView, 53 | _ subview2: ULBView, 54 | handler: ( 55 | ViewProxy, 56 | ViewProxy, 57 | ViewProxy 58 | ) -> Void = { _, _, _ in } 59 | ) { 60 | [subview1, subview2].forEach { 61 | $0.translatesAutoresizingMaskIntoConstraints = false 62 | base._add(subview: $0) 63 | } 64 | 65 | let context = Context() 66 | handler( 67 | ViewProxy(view: base, context: context), 68 | ViewProxy(view: subview1, context: context), 69 | ViewProxy(view: subview2, context: context) 70 | ) 71 | NSLayoutConstraint.activate(context.buildConstraints()) 72 | } 73 | 74 | public func subview( 75 | _ subview1: ULBView, 76 | _ subview2: ULBView, 77 | _ subview3: ULBView, 78 | handler: ( 79 | ViewProxy, 80 | ViewProxy, 81 | ViewProxy, 82 | ViewProxy 83 | ) -> Void = { _, _, _, _ in } 84 | ) { 85 | [subview1, subview2, subview3].forEach { 86 | $0.translatesAutoresizingMaskIntoConstraints = false 87 | base._add(subview: $0) 88 | } 89 | 90 | let context = Context() 91 | handler( 92 | ViewProxy(view: base, context: context), 93 | ViewProxy(view: subview1, context: context), 94 | ViewProxy(view: subview2, context: context), 95 | ViewProxy(view: subview3, context: context) 96 | ) 97 | NSLayoutConstraint.activate(context.buildConstraints()) 98 | } 99 | 100 | public func subview( 101 | _ subview1: ULBView, 102 | _ subview2: ULBView, 103 | _ subview3: ULBView, 104 | _ subview4: ULBView, 105 | handler: ( 106 | ViewProxy, 107 | ViewProxy, 108 | ViewProxy, 109 | ViewProxy, 110 | ViewProxy 111 | ) -> Void = { _, _, _, _, _ in } 112 | ) { 113 | [subview1, subview2, subview3, subview4].forEach { 114 | $0.translatesAutoresizingMaskIntoConstraints = false 115 | base._add(subview: $0) 116 | } 117 | 118 | let context = Context() 119 | handler( 120 | ViewProxy(view: base, context: context), 121 | ViewProxy(view: subview1, context: context), 122 | ViewProxy(view: subview2, context: context), 123 | ViewProxy(view: subview3, context: context), 124 | ViewProxy(view: subview4, context: context) 125 | ) 126 | NSLayoutConstraint.activate(context.buildConstraints()) 127 | } 128 | 129 | public func subview( 130 | _ subview1: ULBView, 131 | _ subview2: ULBView, 132 | _ subview3: ULBView, 133 | _ subview4: ULBView, 134 | _ subview5: ULBView, 135 | handler: ( 136 | ViewProxy, 137 | ViewProxy, 138 | ViewProxy, 139 | ViewProxy, 140 | ViewProxy, 141 | ViewProxy 142 | ) -> Void = { _, _, _, _, _, _ in } 143 | ) { 144 | [subview1, subview2, subview3, subview4, subview5].forEach { 145 | $0.translatesAutoresizingMaskIntoConstraints = false 146 | base._add(subview: $0) 147 | } 148 | 149 | let context = Context() 150 | handler( 151 | ViewProxy(view: base, context: context), 152 | ViewProxy(view: subview1, context: context), 153 | ViewProxy(view: subview2, context: context), 154 | ViewProxy(view: subview3, context: context), 155 | ViewProxy(view: subview4, context: context), 156 | ViewProxy(view: subview5, context: context) 157 | ) 158 | NSLayoutConstraint.activate(context.buildConstraints()) 159 | } 160 | 161 | public func subview( 162 | _ subview1: ULBView, 163 | _ subview2: ULBView, 164 | _ subview3: ULBView, 165 | _ subview4: ULBView, 166 | _ subview5: ULBView, 167 | _ subview6: ULBView, 168 | handler: ( 169 | ViewProxy, 170 | ViewProxy, 171 | ViewProxy, 172 | ViewProxy, 173 | ViewProxy, 174 | ViewProxy, 175 | ViewProxy 176 | ) -> Void = { _, _, _, _, _, _, _ in } 177 | ) { 178 | [subview1, subview2, subview3, subview4, subview5, subview6].forEach { 179 | $0.translatesAutoresizingMaskIntoConstraints = false 180 | base._add(subview: $0) 181 | } 182 | 183 | let context = Context() 184 | handler( 185 | ViewProxy(view: base, context: context), 186 | ViewProxy(view: subview1, context: context), 187 | ViewProxy(view: subview2, context: context), 188 | ViewProxy(view: subview3, context: context), 189 | ViewProxy(view: subview4, context: context), 190 | ViewProxy(view: subview5, context: context), 191 | ViewProxy(view: subview6, context: context) 192 | ) 193 | NSLayoutConstraint.activate(context.buildConstraints()) 194 | } 195 | 196 | public func subview( 197 | _ subview1: ULBView, 198 | _ subview2: ULBView, 199 | _ subview3: ULBView, 200 | _ subview4: ULBView, 201 | _ subview5: ULBView, 202 | _ subview6: ULBView, 203 | _ subview7: ULBView, 204 | handler: ( 205 | ViewProxy, 206 | ViewProxy, 207 | ViewProxy, 208 | ViewProxy, 209 | ViewProxy, 210 | ViewProxy, 211 | ViewProxy, 212 | ViewProxy 213 | ) -> Void = { _, _, _, _, _, _, _, _ in } 214 | ) { 215 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7].forEach { 216 | $0.translatesAutoresizingMaskIntoConstraints = false 217 | base._add(subview: $0) 218 | } 219 | 220 | let context = Context() 221 | handler( 222 | ViewProxy(view: base, context: context), 223 | ViewProxy(view: subview1, context: context), 224 | ViewProxy(view: subview2, context: context), 225 | ViewProxy(view: subview3, context: context), 226 | ViewProxy(view: subview4, context: context), 227 | ViewProxy(view: subview5, context: context), 228 | ViewProxy(view: subview6, context: context), 229 | ViewProxy(view: subview7, context: context) 230 | ) 231 | NSLayoutConstraint.activate(context.buildConstraints()) 232 | } 233 | 234 | public func subview( 235 | _ subview1: ULBView, 236 | _ subview2: ULBView, 237 | _ subview3: ULBView, 238 | _ subview4: ULBView, 239 | _ subview5: ULBView, 240 | _ subview6: ULBView, 241 | _ subview7: ULBView, 242 | _ subview8: ULBView, 243 | handler: ( 244 | ViewProxy, 245 | ViewProxy, 246 | ViewProxy, 247 | ViewProxy, 248 | ViewProxy, 249 | ViewProxy, 250 | ViewProxy, 251 | ViewProxy, 252 | ViewProxy 253 | ) -> Void = { _, _, _, _, _, _, _, _, _ in } 254 | ) { 255 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7, subview8].forEach { 256 | $0.translatesAutoresizingMaskIntoConstraints = false 257 | base._add(subview: $0) 258 | } 259 | 260 | let context = Context() 261 | handler( 262 | ViewProxy(view: base, context: context), 263 | ViewProxy(view: subview1, context: context), 264 | ViewProxy(view: subview2, context: context), 265 | ViewProxy(view: subview3, context: context), 266 | ViewProxy(view: subview4, context: context), 267 | ViewProxy(view: subview5, context: context), 268 | ViewProxy(view: subview6, context: context), 269 | ViewProxy(view: subview7, context: context), 270 | ViewProxy(view: subview8, context: context) 271 | ) 272 | NSLayoutConstraint.activate(context.buildConstraints()) 273 | } 274 | 275 | public func subview( 276 | _ subview1: ULBView, 277 | _ subview2: ULBView, 278 | _ subview3: ULBView, 279 | _ subview4: ULBView, 280 | _ subview5: ULBView, 281 | _ subview6: ULBView, 282 | _ subview7: ULBView, 283 | _ subview8: ULBView, 284 | _ subview9: ULBView, 285 | handler: ( 286 | ViewProxy, 287 | ViewProxy, 288 | ViewProxy, 289 | ViewProxy, 290 | ViewProxy, 291 | ViewProxy, 292 | ViewProxy, 293 | ViewProxy, 294 | ViewProxy, 295 | ViewProxy 296 | ) -> Void = { _, _, _, _, _, _, _, _, _, _ in }) { 297 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7, subview8, subview9].forEach { 298 | $0.translatesAutoresizingMaskIntoConstraints = false 299 | base._add(subview: $0) 300 | } 301 | 302 | let context = Context() 303 | handler( 304 | ViewProxy(view: base, context: context), 305 | ViewProxy(view: subview1, context: context), 306 | ViewProxy(view: subview2, context: context), 307 | ViewProxy(view: subview3, context: context), 308 | ViewProxy(view: subview4, context: context), 309 | ViewProxy(view: subview5, context: context), 310 | ViewProxy(view: subview6, context: context), 311 | ViewProxy(view: subview7, context: context), 312 | ViewProxy(view: subview8, context: context), 313 | ViewProxy(view: subview9, context: context) 314 | ) 315 | NSLayoutConstraint.activate(context.buildConstraints()) 316 | } 317 | 318 | public func subview( 319 | _ subview1: ULBView, 320 | _ subview2: ULBView, 321 | _ subview3: ULBView, 322 | _ subview4: ULBView, 323 | _ subview5: ULBView, 324 | _ subview6: ULBView, 325 | _ subview7: ULBView, 326 | _ subview8: ULBView, 327 | _ subview9: ULBView, 328 | _ subview10: ULBView, 329 | handler: ( 330 | ViewProxy, 331 | ViewProxy, 332 | ViewProxy, 333 | ViewProxy, 334 | ViewProxy, 335 | ViewProxy, 336 | ViewProxy, 337 | ViewProxy, 338 | ViewProxy, 339 | ViewProxy, 340 | ViewProxy 341 | ) -> Void = { _, _, _, _, _, _, _, _, _, _, _ in }) { 342 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7, subview8, subview9, subview10].forEach { 343 | $0.translatesAutoresizingMaskIntoConstraints = false 344 | base._add(subview: $0) 345 | } 346 | 347 | let context = Context() 348 | handler( 349 | ViewProxy(view: base, context: context), 350 | ViewProxy(view: subview1, context: context), 351 | ViewProxy(view: subview2, context: context), 352 | ViewProxy(view: subview3, context: context), 353 | ViewProxy(view: subview4, context: context), 354 | ViewProxy(view: subview5, context: context), 355 | ViewProxy(view: subview6, context: context), 356 | ViewProxy(view: subview7, context: context), 357 | ViewProxy(view: subview8, context: context), 358 | ViewProxy(view: subview9, context: context), 359 | ViewProxy(view: subview10, context: context) 360 | ) 361 | NSLayoutConstraint.activate(context.buildConstraints()) 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/Internal/Builder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Builder.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/09. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public struct Builder { 15 | 16 | private let updater: ConstraintUpdater 17 | 18 | init(constraint: NSLayoutConstraint) { 19 | self.updater = ConstraintUpdater(constraint) 20 | } 21 | 22 | @discardableResult 23 | public func multiplier(_ multiplier: CGFloat) -> Builder { 24 | updater.update(multiplier: multiplier) 25 | return self 26 | } 27 | 28 | @discardableResult 29 | public func constant(_ constant: CGFloat) -> Builder { 30 | updater.update(constant: constant) 31 | return self 32 | } 33 | 34 | @discardableResult 35 | public func priority(_ priority: LayoutPriority) -> Builder { 36 | updater.update(priority: priority) 37 | return self 38 | } 39 | 40 | public func asConstraint() -> NSLayoutConstraint { 41 | return updater.constraint 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/Internal/ConstraintUpdater.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConstraintUpdater.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/09. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | final class ConstraintUpdater { 15 | 16 | private(set) var constraint: NSLayoutConstraint 17 | 18 | init(_ constraint: NSLayoutConstraint) { 19 | self.constraint = constraint 20 | } 21 | 22 | func update(multiplier: CGFloat? = nil, 23 | constant: CGFloat? = nil, 24 | priority: LayoutPriority? = nil) { 25 | let new = NSLayoutConstraint( 26 | item: constraint.firstItem ?? { fatalError("use \(type(of: self)) after equalTo (greaterThan, lessThan).") }(), 27 | attribute: constraint.firstAttribute, 28 | relatedBy: constraint.relation, 29 | toItem: constraint.secondItem, 30 | attribute: constraint.secondAttribute, 31 | multiplier: multiplier ?? constraint.multiplier, 32 | constant: constant ?? constraint.constant 33 | ) 34 | new.priority = priority ?? constraint.priority 35 | self.constraint = new 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/Internal/Context.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Context.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/09. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | final class Context { 15 | 16 | private var builders: [Builder] = [] 17 | 18 | func builder(constraint: NSLayoutConstraint) -> Builder { 19 | let builder = Builder(constraint: constraint) 20 | builders.append(builder) 21 | return builder 22 | } 23 | 24 | func buildConstraints() -> [NSLayoutConstraint] { 25 | builders.map { $0.asConstraint() } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutAnchorType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutAnchorType.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/07. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public protocol LayoutAnchorType { 15 | func constraint(equalTo anchor: Self) -> NSLayoutConstraint 16 | func constraint(greaterThanOrEqualTo anchor: Self) -> NSLayoutConstraint 17 | func constraint(lessThanOrEqualTo anchor: Self) -> NSLayoutConstraint 18 | } 19 | 20 | extension NSLayoutAnchor: LayoutAnchorType {} 21 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutAxes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutAxes.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/07. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public typealias LayoutCenter = LayoutAxes 15 | public typealias LayoutHorizontal = LayoutAxes 16 | public typealias LayoutVertical = LayoutAxes 17 | 18 | public protocol LayoutAxiesTrait { 19 | associatedtype Axis1: LayoutAxisTrait 20 | associatedtype Axis2: LayoutAxisTrait 21 | static func axes(from layout: LayoutRepresentable) -> LayoutAxes 22 | } 23 | 24 | public enum Axes { 25 | 26 | public enum Horizontal: LayoutAxiesTrait { 27 | public typealias Axis1 = Axis.X 28 | public typealias Axis2 = Axis.X 29 | 30 | public static func axes(from layout: LayoutRepresentable) -> LayoutAxes { 31 | layout.horizontal 32 | } 33 | } 34 | 35 | public enum Vertical: LayoutAxiesTrait { 36 | public typealias Axis1 = Axis.Y 37 | public typealias Axis2 = Axis.Y 38 | 39 | public static func axes(from layout: LayoutRepresentable) -> LayoutAxes { 40 | layout.vertical 41 | } 42 | } 43 | 44 | public enum Center: LayoutAxiesTrait { 45 | public typealias Axis1 = Axis.X 46 | public typealias Axis2 = Axis.Y 47 | 48 | public static func axes(from layout: LayoutRepresentable) -> LayoutAxes
{ 49 | layout.center 50 | } 51 | } 52 | } 53 | 54 | public struct LayoutAxes { 55 | typealias Axis1 = Trait.Axis1 56 | typealias Axis2 = Trait.Axis2 57 | 58 | private let axis1: LayoutAxis 59 | private let axis2: LayoutAxis 60 | 61 | init(axis1: LayoutAxis, axis2: LayoutAxis) { 62 | self.axis1 = axis1 63 | self.axis2 = axis2 64 | } 65 | } 66 | 67 | extension LayoutAxes { 68 | 69 | public var equalTo: Relation { 70 | .init(axis1: axis1.equalTo, axis2: axis2.equalTo) 71 | } 72 | } 73 | 74 | extension LayoutAxes { 75 | fileprivate typealias _Builder = UILayoutBuilder.Builder 76 | 77 | public struct Relation { 78 | fileprivate let axis1: LayoutAxis.Relation 79 | fileprivate let axis2: LayoutAxis.Relation 80 | } 81 | 82 | public struct Builder { 83 | private let axis1: _Builder 84 | private let axis2: _Builder 85 | 86 | fileprivate init(axis1: _Builder, axis2: _Builder) { 87 | self.axis1 = axis1 88 | self.axis2 = axis2 89 | } 90 | } 91 | 92 | public struct ConstrantGroup { 93 | fileprivate let axis1: NSLayoutConstraint 94 | fileprivate let axis2: NSLayoutConstraint 95 | } 96 | } 97 | 98 | extension LayoutAxes.ConstrantGroup: ConstrantGroupType { 99 | 100 | public func activate() { 101 | NSLayoutConstraint.activate([axis1, axis2]) 102 | } 103 | 104 | public func deactivate() { 105 | NSLayoutConstraint.deactivate([axis1, axis2]) 106 | } 107 | } 108 | 109 | extension LayoutAxes.Relation { 110 | 111 | private func axes(_ layout: LayoutRepresentable) -> LayoutAxes.Builder { 112 | let axes = Trait.axes(from: layout) 113 | return .init(axis1: axis1.anchor(axes.axis1), axis2: axis2.anchor(axes.axis2)) 114 | } 115 | } 116 | 117 | extension LayoutAxes.Builder { 118 | 119 | private func constant(axis1: CGFloat, axis2: CGFloat) -> LayoutAxes.Builder { 120 | self.axis1.constant(axis1) 121 | self.axis2.constant(axis2) 122 | return self 123 | } 124 | 125 | public func asConstraints() -> LayoutAxes.ConstrantGroup { 126 | .init(axis1: axis1.asConstraint(), axis2: axis2.asConstraint()) 127 | } 128 | } 129 | 130 | // MARK: - Axes.Center 131 | 132 | extension LayoutAxes.Relation where Trait == Axes.Center { 133 | 134 | @discardableResult 135 | public func center(_ layout: LayoutRepresentable) -> LayoutAxes.Builder { 136 | axes(layout) 137 | } 138 | } 139 | 140 | extension LayoutAxes.Builder where Trait == Axes.Center { 141 | 142 | @discardableResult 143 | public func constant(x: CGFloat, y: CGFloat) -> LayoutAxes.Builder { 144 | constant(axis1: x, axis2: y) 145 | } 146 | } 147 | 148 | extension LayoutAxes.ConstrantGroup where Trait == Axes.Center { 149 | public var x: NSLayoutConstraint { axis1 } 150 | public var y: NSLayoutConstraint { axis2 } 151 | } 152 | 153 | // MARK: - Axes.Horizontal 154 | 155 | extension LayoutAxes.Relation where Trait == Axes.Horizontal { 156 | 157 | @discardableResult 158 | public func horizontal(_ layout: LayoutRepresentable) -> LayoutAxes.Builder { 159 | axes(layout) 160 | } 161 | } 162 | 163 | extension LayoutAxes.Builder where Trait == Axes.Horizontal { 164 | 165 | @discardableResult 166 | public func constant(leading: CGFloat, trailing: CGFloat) -> LayoutAxes.Builder { 167 | constant(axis1: leading, axis2: trailing) 168 | } 169 | } 170 | 171 | extension LayoutAxes.ConstrantGroup where Trait == Axes.Horizontal { 172 | public var leading: NSLayoutConstraint { axis1 } 173 | public var trailing: NSLayoutConstraint { axis2 } 174 | } 175 | 176 | // MARK: - Axes.Vertical 177 | 178 | extension LayoutAxes.Relation where Trait == Axes.Vertical { 179 | 180 | @discardableResult 181 | public func vertical(_ layout: LayoutRepresentable) -> LayoutAxes.Builder { 182 | axes(layout) 183 | } 184 | } 185 | 186 | extension LayoutAxes.Builder where Trait == Axes.Vertical { 187 | 188 | @discardableResult 189 | public func constant(top: CGFloat, bottom: CGFloat) -> LayoutAxes.Builder { 190 | constant(axis1: top, axis2: bottom) 191 | } 192 | } 193 | 194 | extension LayoutAxes.ConstrantGroup where Trait == Axes.Vertical { 195 | public var top: NSLayoutConstraint { axis1 } 196 | public var bottom: NSLayoutConstraint { axis2 } 197 | } 198 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutAxis.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutAxis.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/05. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public protocol LayoutAxisTrait { 15 | associatedtype RawAnchor: LayoutAnchorType 16 | } 17 | 18 | public enum Axis { 19 | 20 | public enum X: LayoutAxisTrait { 21 | public typealias RawAnchor = NSLayoutXAxisAnchor 22 | } 23 | 24 | public enum Y: LayoutAxisTrait { 25 | public typealias RawAnchor = NSLayoutYAxisAnchor 26 | } 27 | } 28 | 29 | public typealias LayoutYAxis = LayoutAxis 30 | public typealias LayoutXAxis = LayoutAxis 31 | 32 | public struct LayoutAxis { 33 | typealias RawAnchor = Trait.RawAnchor 34 | 35 | private let rawAnchor: RawAnchor 36 | private let context: Context 37 | 38 | init(_ view: ULBView, for keyPath: KeyPath, context: Context) { 39 | self.rawAnchor = view[keyPath: keyPath] 40 | self.context = context 41 | } 42 | } 43 | 44 | #if os(iOS) || os(tvOS) 45 | extension LayoutAxis { 46 | 47 | init(_ layoutGuide: UILayoutGuide, for keyPath: KeyPath, context: Context) { 48 | self.rawAnchor = layoutGuide[keyPath: keyPath] 49 | self.context = context 50 | } 51 | } 52 | #endif 53 | 54 | extension LayoutAxis { 55 | 56 | public var equalTo: Relation { 57 | .init(toAnchor: { [rawAnchor] in rawAnchor.constraint(equalTo: $0) }, 58 | context: context) 59 | } 60 | 61 | public var greaterThanOrEqualTo: Relation { 62 | .init(toAnchor: { [rawAnchor] in rawAnchor.constraint(greaterThanOrEqualTo: $0) }, 63 | context: context) 64 | } 65 | 66 | public var lessThanOrEqualTo: Relation { 67 | .init(toAnchor: { [rawAnchor] in rawAnchor.constraint(lessThanOrEqualTo: $0) }, 68 | context: context) 69 | } 70 | } 71 | 72 | extension LayoutAxis { 73 | public typealias Builder = UILayoutBuilder.Builder 74 | 75 | public struct Relation { 76 | fileprivate let toAnchor: (RawAnchor) -> NSLayoutConstraint 77 | fileprivate let context: Context 78 | } 79 | } 80 | 81 | extension LayoutAxis.Relation { 82 | 83 | @discardableResult 84 | func anchor(_ anchor: LayoutAxis) -> LayoutAxis.Builder { 85 | context.builder(constraint: toAnchor(anchor.rawAnchor)) 86 | } 87 | } 88 | 89 | extension LayoutAxis.Relation where Trait == Axis.Y { 90 | 91 | @discardableResult 92 | public func top(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 93 | anchor(layout.top) 94 | } 95 | 96 | @discardableResult 97 | public func bottom(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 98 | anchor(layout.bottom) 99 | } 100 | 101 | @discardableResult 102 | public func centerY(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 103 | anchor(layout.centerY) 104 | } 105 | 106 | @discardableResult 107 | public func firstBaseline(_ view: ViewProxy) -> LayoutAxis.Builder { 108 | anchor(view.firstBaseline) 109 | } 110 | 111 | @discardableResult 112 | public func lastBaseline(_ view: ViewProxy) -> LayoutAxis.Builder { 113 | anchor(view.lastBaseline) 114 | } 115 | } 116 | 117 | extension LayoutAxis.Relation where Trait == Axis.X { 118 | 119 | @discardableResult 120 | public func leading(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 121 | anchor(layout.leading) 122 | } 123 | 124 | @discardableResult 125 | public func trailing(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 126 | anchor(layout.trailing) 127 | } 128 | 129 | @discardableResult 130 | public func left(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 131 | anchor(layout.left) 132 | } 133 | 134 | @discardableResult 135 | public func right(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 136 | anchor(layout.right) 137 | } 138 | 139 | @discardableResult 140 | public func centerX(_ layout: LayoutRepresentable) -> LayoutAxis.Builder { 141 | anchor(layout.centerX) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutDimension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutDimension.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/05. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public struct LayoutDimension { 15 | typealias RawAnchor = NSLayoutDimension 16 | 17 | private let rawAnchor: RawAnchor 18 | private let context: Context 19 | 20 | init(_ view: ULBView, for keyPath: KeyPath, context: Context) { 21 | self.rawAnchor = view[keyPath: keyPath] 22 | self.context = context 23 | } 24 | } 25 | 26 | #if os(iOS) || os(tvOS) 27 | extension LayoutDimension { 28 | 29 | init(_ layoutGuide: UILayoutGuide, for keyPath: KeyPath, context: Context) { 30 | self.rawAnchor = layoutGuide[keyPath: keyPath] 31 | self.context = context 32 | } 33 | } 34 | #endif 35 | 36 | extension LayoutDimension { 37 | 38 | public var equalTo: Relation { 39 | .init(toAnchor: { [rawAnchor] in rawAnchor.constraint(equalTo: $0) }, 40 | toConstant: { [rawAnchor] in rawAnchor.constraint(equalToConstant: $0) }, 41 | context: context) 42 | } 43 | 44 | public var greaterThanOrEqualTo: Relation { 45 | .init(toAnchor: { [rawAnchor] in rawAnchor.constraint(greaterThanOrEqualTo: $0) }, 46 | toConstant: { [rawAnchor] in rawAnchor.constraint(greaterThanOrEqualToConstant: $0) }, 47 | context: context) 48 | } 49 | 50 | public var lessThanOrEqualTo: Relation { 51 | .init(toAnchor: { [rawAnchor] in rawAnchor.constraint(lessThanOrEqualTo: $0) }, 52 | toConstant: { [rawAnchor] in rawAnchor.constraint(lessThanOrEqualToConstant: $0) }, 53 | context: context) 54 | } 55 | } 56 | 57 | extension LayoutDimension { 58 | public typealias Builder = UILayoutBuilder.Builder 59 | 60 | public struct Relation { 61 | fileprivate let toAnchor: (RawAnchor) -> NSLayoutConstraint 62 | fileprivate let toConstant: (CGFloat) -> NSLayoutConstraint 63 | fileprivate let context: Context 64 | } 65 | } 66 | 67 | extension LayoutDimension.Relation { 68 | 69 | @discardableResult 70 | private func anchor(_ anchor: LayoutDimension) -> LayoutDimension.Builder { 71 | context.builder(constraint: toAnchor(anchor.rawAnchor)) 72 | } 73 | 74 | @discardableResult 75 | public func constant(_ constant: CGFloat) -> LayoutDimension.Builder { 76 | context.builder(constraint: toConstant(constant)) 77 | } 78 | 79 | @discardableResult 80 | public func height(_ layout: LayoutRepresentable) -> LayoutDimension.Builder { 81 | anchor(layout.height) 82 | } 83 | 84 | @discardableResult 85 | public func width(_ layout: LayoutRepresentable) -> LayoutDimension.Builder { 86 | anchor(layout.width) 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutEdges.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutEdges.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/07. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public struct LayoutEdges { 15 | private let top: LayoutYAxis 16 | private let leading: LayoutXAxis 17 | private let bottom: LayoutYAxis 18 | private let trailing: LayoutXAxis 19 | 20 | init(top: LayoutYAxis, leading: LayoutXAxis, bottom: LayoutYAxis, trailing: LayoutXAxis) { 21 | self.top = top 22 | self.leading = leading 23 | self.bottom = bottom 24 | self.trailing = trailing 25 | } 26 | } 27 | 28 | extension LayoutEdges { 29 | 30 | public var equalTo: Relation { 31 | .init(top: top.equalTo, 32 | leading: leading.equalTo, 33 | bottom: bottom.equalTo, 34 | trailing: trailing.equalTo) 35 | } 36 | 37 | public var greaterThanOrEqualTo: Relation { 38 | .init(top: top.greaterThanOrEqualTo, 39 | leading: leading.greaterThanOrEqualTo, 40 | bottom: bottom.greaterThanOrEqualTo, 41 | trailing: trailing.greaterThanOrEqualTo) 42 | } 43 | 44 | public var lessThanOrEqualTo: Relation { 45 | .init(top: top.lessThanOrEqualTo, 46 | leading: leading.lessThanOrEqualTo, 47 | bottom: bottom.lessThanOrEqualTo, 48 | trailing: trailing.lessThanOrEqualTo) 49 | } 50 | } 51 | 52 | extension LayoutEdges { 53 | fileprivate typealias _Builder = UILayoutBuilder.Builder 54 | 55 | public struct Relation { 56 | fileprivate let top: LayoutYAxis.Relation 57 | fileprivate let leading: LayoutXAxis.Relation 58 | fileprivate let bottom: LayoutYAxis.Relation 59 | fileprivate let trailing: LayoutXAxis.Relation 60 | } 61 | 62 | public struct Builder { 63 | private let top: _Builder 64 | private let leading: _Builder 65 | private let bottom: _Builder 66 | private let trailing: _Builder 67 | 68 | fileprivate init(top: _Builder, 69 | leading: _Builder, 70 | bottom: _Builder, 71 | trailing: _Builder) { 72 | self.top = top 73 | self.leading = leading 74 | self.bottom = bottom 75 | self.trailing = trailing 76 | } 77 | } 78 | 79 | public struct ConstrantGroup { 80 | public let top: NSLayoutConstraint 81 | public let leading: NSLayoutConstraint 82 | public let bottom: NSLayoutConstraint 83 | public let trailing: NSLayoutConstraint 84 | } 85 | } 86 | 87 | extension LayoutEdges.ConstrantGroup: ConstrantGroupType { 88 | 89 | public func activate() { 90 | NSLayoutConstraint.activate([top, leading, bottom, trailing]) 91 | } 92 | 93 | public func deactivate() { 94 | NSLayoutConstraint.deactivate([top, leading, bottom, trailing]) 95 | } 96 | } 97 | 98 | extension LayoutEdges.Relation { 99 | 100 | @discardableResult 101 | public func edges(_ layout: LayoutRepresentable) -> LayoutEdges.Builder { 102 | .init(top: top.top(layout), 103 | leading: leading.leading(layout), 104 | bottom: bottom.bottom(layout), 105 | trailing: trailing.trailing(layout)) 106 | } 107 | } 108 | 109 | extension LayoutEdges.Builder { 110 | 111 | @discardableResult 112 | public func constant(_ constant: CGFloat) -> LayoutEdges.Builder { 113 | top.constant(constant) 114 | leading.constant(constant) 115 | bottom.constant(-constant) 116 | trailing.constant(-constant) 117 | return self 118 | } 119 | 120 | public func constant(top: CGFloat, leading: CGFloat, bottom: CGFloat, trailing: CGFloat) -> LayoutEdges.Builder { 121 | self.top.constant(top) 122 | self.leading.constant(leading) 123 | self.bottom.constant(bottom) 124 | self.trailing.constant(trailing) 125 | return self 126 | } 127 | 128 | public func asConstraints() -> LayoutEdges.ConstrantGroup { 129 | .init(top: top.asConstraint(), 130 | leading: leading.asConstraint(), 131 | bottom: bottom.asConstraint(), 132 | trailing: trailing.asConstraint()) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutGuideProxy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutGuideProxy.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/09. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | 11 | public struct LayoutGuideProxy { 12 | private let layoutGuide: UILayoutGuide 13 | private let context: Context 14 | 15 | init(layoutGuide: UILayoutGuide, context: Context) { 16 | self.layoutGuide = layoutGuide 17 | self.context = context 18 | } 19 | } 20 | 21 | extension LayoutGuideProxy: LayoutRepresentable { 22 | public var leading : LayoutXAxis { .init(layoutGuide, for: \.leadingAnchor, context: context) } 23 | public var trailing : LayoutXAxis { .init(layoutGuide, for: \.trailingAnchor, context: context) } 24 | public var left : LayoutXAxis { .init(layoutGuide, for: \.leftAnchor, context: context) } 25 | public var right : LayoutXAxis { .init(layoutGuide, for: \.rightAnchor, context: context) } 26 | public var top : LayoutYAxis { .init(layoutGuide, for: \.topAnchor, context: context) } 27 | public var bottom : LayoutYAxis { .init(layoutGuide, for: \.bottomAnchor, context: context) } 28 | public var width : LayoutDimension { .init(layoutGuide, for: \.widthAnchor, context: context) } 29 | public var height : LayoutDimension { .init(layoutGuide, for: \.heightAnchor, context: context) } 30 | public var centerX : LayoutXAxis { .init(layoutGuide, for: \.centerXAnchor, context: context) } 31 | public var centerY : LayoutYAxis { .init(layoutGuide, for: \.centerYAnchor, context: context) } 32 | 33 | public var edges : LayoutEdges { .init(top: top, leading: leading, bottom: bottom, trailing: trailing) } 34 | public var size : LayoutSize { .init(width: width, height: height) } 35 | public var center : LayoutCenter { .init(axis1: centerX, axis2: centerY) } 36 | public var horizontal : LayoutHorizontal { .init(axis1: leading, axis2: trailing) } 37 | public var vertical : LayoutVertical { .init(axis1: top, axis2: bottom) } 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutRepresentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutRepresentable.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/09. 6 | // 7 | 8 | public protocol LayoutRepresentable { 9 | var leading : LayoutXAxis { get } 10 | var trailing : LayoutXAxis { get } 11 | var left : LayoutXAxis { get } 12 | var right : LayoutXAxis { get } 13 | var top : LayoutYAxis { get } 14 | var bottom : LayoutYAxis { get } 15 | var width : LayoutDimension { get } 16 | var height : LayoutDimension { get } 17 | var centerX : LayoutXAxis { get } 18 | var centerY : LayoutYAxis { get } 19 | 20 | var edges : LayoutEdges { get } 21 | var size : LayoutSize { get } 22 | var center : LayoutCenter { get } 23 | var horizontal : LayoutHorizontal { get } 24 | var vertical : LayoutVertical { get } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/LayoutSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutSize.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/07. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | #else 11 | import AppKit 12 | #endif 13 | 14 | public struct LayoutSize { 15 | 16 | private let width: LayoutDimension 17 | private let height: LayoutDimension 18 | 19 | init(width: LayoutDimension, height: LayoutDimension) { 20 | self.width = width 21 | self.height = height 22 | } 23 | } 24 | 25 | extension LayoutSize { 26 | 27 | public var equalTo: Relation { 28 | .init(width: width.equalTo, height: height.equalTo) 29 | } 30 | } 31 | 32 | extension LayoutSize { 33 | fileprivate typealias _Builder = UILayoutBuilder.Builder 34 | 35 | public struct Relation { 36 | fileprivate let width: LayoutDimension.Relation 37 | fileprivate let height: LayoutDimension.Relation 38 | } 39 | 40 | public struct Builder { 41 | private let width: _Builder 42 | private let height: _Builder 43 | 44 | fileprivate init(width: _Builder, height: _Builder) { 45 | self.width = width 46 | self.height = height 47 | } 48 | } 49 | 50 | public struct ConstrantGroup { 51 | public let width: NSLayoutConstraint 52 | public let height: NSLayoutConstraint 53 | } 54 | } 55 | 56 | extension LayoutSize.ConstrantGroup: ConstrantGroupType { 57 | 58 | public func activate() { 59 | NSLayoutConstraint.activate([width, height]) 60 | } 61 | 62 | public func deactivate() { 63 | NSLayoutConstraint.deactivate([width, height]) 64 | } 65 | } 66 | 67 | extension LayoutSize.Relation { 68 | 69 | @discardableResult 70 | public func size(_ layout: LayoutRepresentable) -> LayoutSize.Builder { 71 | .init(width: width.width(layout), height: height.height(layout)) 72 | } 73 | 74 | @discardableResult 75 | public func constant(width: CGFloat, height: CGFloat) -> LayoutSize.Builder { 76 | .init(width: self.width.constant(width), height: self.height.constant(height)) 77 | } 78 | } 79 | 80 | extension LayoutSize.Builder { 81 | 82 | @discardableResult 83 | public func constant(width: CGFloat, height: CGFloat) -> LayoutSize.Builder { 84 | self.width.constant(width) 85 | self.height.constant(height) 86 | return self 87 | } 88 | 89 | @discardableResult 90 | public func priority(width: LayoutPriority, height: LayoutPriority) -> LayoutSize.Builder { 91 | self.width.priority(width) 92 | self.height.priority(height) 93 | return self 94 | } 95 | 96 | @discardableResult 97 | public func multiplier(width: CGFloat, height: CGFloat) -> LayoutSize.Builder { 98 | self.width.multiplier(width) 99 | self.height.multiplier(height) 100 | return self 101 | } 102 | 103 | 104 | public func asConstraints() -> LayoutSize.ConstrantGroup { 105 | .init(width: width.asConstraint(), 106 | height: height.asConstraint()) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/UILayoutBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UILayoutBuilder.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/05. 6 | // 7 | 8 | public protocol UILayoutBuilderCompatible { 9 | associatedtype UILayoutBuilderBase 10 | var ulb: UILayoutBuilderExtension { get } 11 | } 12 | 13 | extension UILayoutBuilderCompatible { 14 | public var ulb: UILayoutBuilderExtension { .init(self) } 15 | } 16 | 17 | public struct UILayoutBuilderExtension { 18 | let base: Base 19 | 20 | fileprivate init(_ base: Base) { 21 | self.base = base 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/ULBTypealias.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ULBTypealias.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/09. 6 | // 7 | 8 | #if os(iOS) || os(tvOS) 9 | import UIKit 10 | public typealias ULBView = UIView 11 | public typealias LayoutPriority = UILayoutPriority 12 | #else 13 | import AppKit 14 | public typealias ULBView = NSView 15 | public typealias LayoutPriority = NSLayoutConstraint.Priority 16 | #endif 17 | -------------------------------------------------------------------------------- /Sources/UILayoutBuilder/ViewProxy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewProxy.swift 3 | // UILayoutBuilder 4 | // 5 | // Created by marty-suzuki on 2020/02/05. 6 | // 7 | 8 | public struct ViewProxy { 9 | 10 | private let view: ULBView 11 | private let context: Context 12 | 13 | init(view: ULBView, context: Context) { 14 | self.view = view 15 | self.context = context 16 | } 17 | } 18 | 19 | extension ViewProxy: LayoutRepresentable { 20 | public var leading : LayoutXAxis { .init(view, for: \.leadingAnchor, context: context) } 21 | public var trailing : LayoutXAxis { .init(view, for: \.trailingAnchor, context: context) } 22 | public var left : LayoutXAxis { .init(view, for: \.leftAnchor, context: context) } 23 | public var right : LayoutXAxis { .init(view, for: \.rightAnchor, context: context) } 24 | public var top : LayoutYAxis { .init(view, for: \.topAnchor, context: context) } 25 | public var bottom : LayoutYAxis { .init(view, for: \.bottomAnchor, context: context) } 26 | public var width : LayoutDimension { .init(view, for: \.widthAnchor, context: context) } 27 | public var height : LayoutDimension { .init(view, for: \.heightAnchor, context: context) } 28 | public var centerX : LayoutXAxis { .init(view, for: \.centerXAnchor, context: context) } 29 | public var centerY : LayoutYAxis { .init(view, for: \.centerYAnchor, context: context) } 30 | public var firstBaseline: LayoutYAxis { .init(view, for: \.firstBaselineAnchor, context: context) } 31 | public var lastBaseline : LayoutYAxis { .init(view, for: \.lastBaselineAnchor, context: context) } 32 | 33 | public var edges : LayoutEdges { .init(top: top, leading: leading, bottom: bottom, trailing: trailing) } 34 | public var size : LayoutSize { .init(width: width, height: height) } 35 | public var center : LayoutCenter { .init(axis1: centerX, axis2: centerY) } 36 | public var horizontal : LayoutHorizontal { .init(axis1: leading, axis2: trailing) } 37 | public var vertical : LayoutVertical { .init(axis1: top, axis2: bottom) } 38 | } 39 | 40 | #if os(iOS) || os(tvOS) 41 | extension ViewProxy { 42 | 43 | @available(iOS 11, tvOS 11, macCatalyst 13, *) 44 | public var safeAreaLayoutGuide: LayoutGuideProxy { 45 | .init(layoutGuide: view.safeAreaLayoutGuide, context: context) 46 | } 47 | 48 | public var layoutMarginsGuide: LayoutGuideProxy { 49 | .init(layoutGuide: view.layoutMarginsGuide, context: context) 50 | } 51 | } 52 | #endif 53 | 54 | extension ViewProxy { 55 | 56 | public struct AddSubview { 57 | fileprivate let view: ULBView 58 | fileprivate let context: Context 59 | } 60 | 61 | public var add: AddSubview { .init(view: view, context: context) } 62 | } 63 | 64 | extension ViewProxy.AddSubview { 65 | 66 | public func subview(_ subview: ULBView, handler: (ViewProxy) -> Void = { _ in }) { 67 | subview.translatesAutoresizingMaskIntoConstraints = false 68 | view._add(subview: subview) 69 | handler(ViewProxy(view: subview, context: context)) 70 | } 71 | 72 | public func subview( 73 | _ subview1: ULBView, 74 | _ subview2: ULBView, 75 | handler: ( 76 | ViewProxy, 77 | ViewProxy 78 | ) -> Void = { _, _ in } 79 | ) { 80 | [subview1, subview2].forEach { 81 | $0.translatesAutoresizingMaskIntoConstraints = false 82 | view._add(subview: $0) 83 | } 84 | handler( 85 | ViewProxy(view: subview1, context: context), 86 | ViewProxy(view: subview2, context: context) 87 | ) 88 | } 89 | 90 | public func subview( 91 | _ subview1: ULBView, 92 | _ subview2: ULBView, 93 | _ subview3: ULBView, 94 | handler: ( 95 | ViewProxy, 96 | ViewProxy, 97 | ViewProxy 98 | ) -> Void = { _, _, _ in } 99 | ) { 100 | [subview1, subview2, subview3].forEach { 101 | $0.translatesAutoresizingMaskIntoConstraints = false 102 | view._add(subview: $0) 103 | } 104 | handler( 105 | ViewProxy(view: subview1, context: context), 106 | ViewProxy(view: subview2, context: context), 107 | ViewProxy(view: subview3, context: context) 108 | ) 109 | } 110 | 111 | public func subview( 112 | _ subview1: ULBView, 113 | _ subview2: ULBView, 114 | _ subview3: ULBView, 115 | _ subview4: ULBView, 116 | handler: ( 117 | ViewProxy, 118 | ViewProxy, 119 | ViewProxy, 120 | ViewProxy 121 | ) -> Void = { _, _, _, _ in } 122 | ) { 123 | [subview1, subview2, subview3, subview4].forEach { 124 | $0.translatesAutoresizingMaskIntoConstraints = false 125 | view._add(subview: $0) 126 | } 127 | handler( 128 | ViewProxy(view: subview1, context: context), 129 | ViewProxy(view: subview2, context: context), 130 | ViewProxy(view: subview3, context: context), 131 | ViewProxy(view: subview4, context: context) 132 | ) 133 | } 134 | 135 | public func subview( 136 | _ subview1: ULBView, 137 | _ subview2: ULBView, 138 | _ subview3: ULBView, 139 | _ subview4: ULBView, 140 | _ subview5: ULBView, 141 | handler: ( 142 | ViewProxy, 143 | ViewProxy, 144 | ViewProxy, 145 | ViewProxy, 146 | ViewProxy 147 | ) -> Void = { _, _, _, _, _ in } 148 | ) { 149 | [subview1, subview2, subview3, subview4, subview5].forEach { 150 | $0.translatesAutoresizingMaskIntoConstraints = false 151 | view._add(subview: $0) 152 | } 153 | handler( 154 | ViewProxy(view: subview1, context: context), 155 | ViewProxy(view: subview2, context: context), 156 | ViewProxy(view: subview3, context: context), 157 | ViewProxy(view: subview4, context: context), 158 | ViewProxy(view: subview5, context: context) 159 | ) 160 | } 161 | 162 | public func subview( 163 | _ subview1: ULBView, 164 | _ subview2: ULBView, 165 | _ subview3: ULBView, 166 | _ subview4: ULBView, 167 | _ subview5: ULBView, 168 | _ subview6: ULBView, 169 | handler: ( 170 | ViewProxy, 171 | ViewProxy, 172 | ViewProxy, 173 | ViewProxy, 174 | ViewProxy, 175 | ViewProxy 176 | ) -> Void = { _, _, _, _, _, _ in } 177 | ) { 178 | [subview1, subview2, subview3, subview4, subview5, subview6].forEach { 179 | $0.translatesAutoresizingMaskIntoConstraints = false 180 | view._add(subview: $0) 181 | } 182 | handler( 183 | ViewProxy(view: subview1, context: context), 184 | ViewProxy(view: subview2, context: context), 185 | ViewProxy(view: subview3, context: context), 186 | ViewProxy(view: subview4, context: context), 187 | ViewProxy(view: subview5, context: context), 188 | ViewProxy(view: subview6, context: context) 189 | ) 190 | } 191 | 192 | public func subview( 193 | _ subview1: ULBView, 194 | _ subview2: ULBView, 195 | _ subview3: ULBView, 196 | _ subview4: ULBView, 197 | _ subview5: ULBView, 198 | _ subview6: ULBView, 199 | _ subview7: ULBView, 200 | handler: ( 201 | ViewProxy, 202 | ViewProxy, 203 | ViewProxy, 204 | ViewProxy, 205 | ViewProxy, 206 | ViewProxy, 207 | ViewProxy 208 | ) -> Void = { _, _, _, _, _, _, _ in } 209 | ) { 210 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7].forEach { 211 | $0.translatesAutoresizingMaskIntoConstraints = false 212 | view._add(subview: $0) 213 | } 214 | handler( 215 | ViewProxy(view: subview1, context: context), 216 | ViewProxy(view: subview2, context: context), 217 | ViewProxy(view: subview3, context: context), 218 | ViewProxy(view: subview4, context: context), 219 | ViewProxy(view: subview5, context: context), 220 | ViewProxy(view: subview6, context: context), 221 | ViewProxy(view: subview7, context: context) 222 | ) 223 | } 224 | 225 | public func subview( 226 | _ subview1: ULBView, 227 | _ subview2: ULBView, 228 | _ subview3: ULBView, 229 | _ subview4: ULBView, 230 | _ subview5: ULBView, 231 | _ subview6: ULBView, 232 | _ subview7: ULBView, 233 | _ subview8: ULBView, 234 | handler: ( 235 | ViewProxy, 236 | ViewProxy, 237 | ViewProxy, 238 | ViewProxy, 239 | ViewProxy, 240 | ViewProxy, 241 | ViewProxy, 242 | ViewProxy 243 | ) -> Void = { _, _, _, _, _, _, _, _ in } 244 | ) { 245 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7, subview8].forEach { 246 | $0.translatesAutoresizingMaskIntoConstraints = false 247 | view._add(subview: $0) 248 | } 249 | handler( 250 | ViewProxy(view: subview1, context: context), 251 | ViewProxy(view: subview2, context: context), 252 | ViewProxy(view: subview3, context: context), 253 | ViewProxy(view: subview4, context: context), 254 | ViewProxy(view: subview5, context: context), 255 | ViewProxy(view: subview6, context: context), 256 | ViewProxy(view: subview7, context: context), 257 | ViewProxy(view: subview8, context: context) 258 | ) 259 | } 260 | 261 | public func subview( 262 | _ subview1: ULBView, 263 | _ subview2: ULBView, 264 | _ subview3: ULBView, 265 | _ subview4: ULBView, 266 | _ subview5: ULBView, 267 | _ subview6: ULBView, 268 | _ subview7: ULBView, 269 | _ subview8: ULBView, 270 | _ subview9: ULBView, 271 | handler: ( 272 | ViewProxy, 273 | ViewProxy, 274 | ViewProxy, 275 | ViewProxy, 276 | ViewProxy, 277 | ViewProxy, 278 | ViewProxy, 279 | ViewProxy, 280 | ViewProxy 281 | ) -> Void = { _, _, _, _, _, _, _, _, _ in }) { 282 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7, subview8, subview9].forEach { 283 | $0.translatesAutoresizingMaskIntoConstraints = false 284 | view._add(subview: $0) 285 | } 286 | handler( 287 | ViewProxy(view: subview1, context: context), 288 | ViewProxy(view: subview2, context: context), 289 | ViewProxy(view: subview3, context: context), 290 | ViewProxy(view: subview4, context: context), 291 | ViewProxy(view: subview5, context: context), 292 | ViewProxy(view: subview6, context: context), 293 | ViewProxy(view: subview7, context: context), 294 | ViewProxy(view: subview8, context: context), 295 | ViewProxy(view: subview9, context: context) 296 | ) 297 | } 298 | 299 | public func subview( 300 | _ subview1: ULBView, 301 | _ subview2: ULBView, 302 | _ subview3: ULBView, 303 | _ subview4: ULBView, 304 | _ subview5: ULBView, 305 | _ subview6: ULBView, 306 | _ subview7: ULBView, 307 | _ subview8: ULBView, 308 | _ subview9: ULBView, 309 | _ subview10: ULBView, 310 | handler: ( 311 | ViewProxy, 312 | ViewProxy, 313 | ViewProxy, 314 | ViewProxy, 315 | ViewProxy, 316 | ViewProxy, 317 | ViewProxy, 318 | ViewProxy, 319 | ViewProxy, 320 | ViewProxy 321 | ) -> Void = { _, _, _, _, _, _, _, _, _, _ in }) { 322 | [subview1, subview2, subview3, subview4, subview5, subview6, subview7, subview8, subview9, subview10].forEach { 323 | $0.translatesAutoresizingMaskIntoConstraints = false 324 | view._add(subview: $0) 325 | } 326 | handler( 327 | ViewProxy(view: subview1, context: context), 328 | ViewProxy(view: subview2, context: context), 329 | ViewProxy(view: subview3, context: context), 330 | ViewProxy(view: subview4, context: context), 331 | ViewProxy(view: subview5, context: context), 332 | ViewProxy(view: subview6, context: context), 333 | ViewProxy(view: subview7, context: context), 334 | ViewProxy(view: subview8, context: context), 335 | ViewProxy(view: subview9, context: context), 336 | ViewProxy(view: subview10, context: context) 337 | ) 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import UILayoutBuilderTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += UILayoutBuilderTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /Tests/UILayoutBuilderTests/UILayoutBuilderTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import UILayoutBuilder 3 | 4 | final class UILayoutBuilderTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | XCTAssertEqual(UILayoutBuilder().text, "Hello, World!") 10 | } 11 | 12 | static var allTests = [ 13 | ("testExample", testExample), 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Tests/UILayoutBuilderTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(UILayoutBuilderTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /UILayoutBuilder.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint Unio.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | last_commit = `git rev-list --tags --max-count=1`.strip 11 | last_tag = `git describe --tags #{last_commit}`.strip 12 | 13 | s.name = "UILayoutBuilder" 14 | s.version = last_tag 15 | s.summary = "An AutoLayout DSL that intuitive syntax and viewable hierarchy." 16 | s.homepage = "https://github.com/marty-suzuki/UILayoutBuilder" 17 | s.license = { :type => "MIT", :file => "LICENSE" } 18 | s.author = { "Taiki Suzuki" => "s1180183@gmail.com" } 19 | s.ios.deployment_target = "10.0" 20 | s.osx.deployment_target = '10.11' 21 | s.tvos.deployment_target = '10.0' 22 | s.source = { :git => "https://github.com/marty-suzuki/UILayoutBuilder.git", :tag => "#{s.version}" } 23 | s.source_files = "Sources/**/*.{swift}" 24 | s.swift_version = '5.0' 25 | end 26 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/UILayoutBuilderTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/UILayoutBuilder_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | FMWK 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | "UILayoutBuilder::UILayoutBuilderPackageTests::ProductTarget" /* UILayoutBuilderPackageTests */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = OBJ_66 /* Build configuration list for PBXAggregateTarget "UILayoutBuilderPackageTests" */; 13 | buildPhases = ( 14 | ); 15 | dependencies = ( 16 | OBJ_69 /* PBXTargetDependency */, 17 | ); 18 | name = UILayoutBuilderPackageTests; 19 | productName = UILayoutBuilderPackageTests; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | ED85A67123F086AA00DDD8C8 /* ConstrantGroupType.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED85A67023F086A900DDD8C8 /* ConstrantGroupType.swift */; }; 25 | OBJ_42 /* UIStackViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* UIStackViewExtension.swift */; }; 26 | OBJ_43 /* ULBViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* ULBViewExtension.swift */; }; 27 | OBJ_44 /* Builder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* Builder.swift */; }; 28 | OBJ_45 /* ConstraintUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* ConstraintUpdater.swift */; }; 29 | OBJ_46 /* Context.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* Context.swift */; }; 30 | OBJ_47 /* LayoutAnchorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* LayoutAnchorType.swift */; }; 31 | OBJ_48 /* LayoutAxes.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* LayoutAxes.swift */; }; 32 | OBJ_49 /* LayoutAxis.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* LayoutAxis.swift */; }; 33 | OBJ_50 /* LayoutDimension.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* LayoutDimension.swift */; }; 34 | OBJ_51 /* LayoutEdges.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* LayoutEdges.swift */; }; 35 | OBJ_52 /* LayoutGuideProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* LayoutGuideProxy.swift */; }; 36 | OBJ_53 /* LayoutRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* LayoutRepresentable.swift */; }; 37 | OBJ_54 /* LayoutSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* LayoutSize.swift */; }; 38 | OBJ_55 /* UILayoutBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* UILayoutBuilder.swift */; }; 39 | OBJ_56 /* ULBTypealias.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* ULBTypealias.swift */; }; 40 | OBJ_57 /* ViewProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* ViewProxy.swift */; }; 41 | OBJ_64 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; 42 | OBJ_75 /* UILayoutBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* UILayoutBuilderTests.swift */; }; 43 | OBJ_76 /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* XCTestManifests.swift */; }; 44 | OBJ_78 /* UILayoutBuilder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "UILayoutBuilder::UILayoutBuilder::Product" /* UILayoutBuilder.framework */; }; 45 | /* End PBXBuildFile section */ 46 | 47 | /* Begin PBXContainerItemProxy section */ 48 | ED85A64B23F070EC00DDD8C8 /* PBXContainerItemProxy */ = { 49 | isa = PBXContainerItemProxy; 50 | containerPortal = OBJ_1 /* Project object */; 51 | proxyType = 1; 52 | remoteGlobalIDString = "UILayoutBuilder::UILayoutBuilder"; 53 | remoteInfo = UILayoutBuilder; 54 | }; 55 | ED85A64C23F070EF00DDD8C8 /* PBXContainerItemProxy */ = { 56 | isa = PBXContainerItemProxy; 57 | containerPortal = OBJ_1 /* Project object */; 58 | proxyType = 1; 59 | remoteGlobalIDString = "UILayoutBuilder::UILayoutBuilderTests"; 60 | remoteInfo = UILayoutBuilderTests; 61 | }; 62 | /* End PBXContainerItemProxy section */ 63 | 64 | /* Begin PBXFileReference section */ 65 | ED85A67023F086A900DDD8C8 /* ConstrantGroupType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstrantGroupType.swift; sourceTree = ""; }; 66 | OBJ_10 /* UIStackViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackViewExtension.swift; sourceTree = ""; }; 67 | OBJ_11 /* ULBViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ULBViewExtension.swift; sourceTree = ""; }; 68 | OBJ_13 /* Builder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Builder.swift; sourceTree = ""; }; 69 | OBJ_14 /* ConstraintUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstraintUpdater.swift; sourceTree = ""; }; 70 | OBJ_15 /* Context.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = ""; }; 71 | OBJ_16 /* LayoutAnchorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutAnchorType.swift; sourceTree = ""; }; 72 | OBJ_17 /* LayoutAxes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutAxes.swift; sourceTree = ""; }; 73 | OBJ_18 /* LayoutAxis.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutAxis.swift; sourceTree = ""; }; 74 | OBJ_19 /* LayoutDimension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutDimension.swift; sourceTree = ""; }; 75 | OBJ_20 /* LayoutEdges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutEdges.swift; sourceTree = ""; }; 76 | OBJ_21 /* LayoutGuideProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutGuideProxy.swift; sourceTree = ""; }; 77 | OBJ_22 /* LayoutRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutRepresentable.swift; sourceTree = ""; }; 78 | OBJ_23 /* LayoutSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutSize.swift; sourceTree = ""; }; 79 | OBJ_24 /* UILayoutBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UILayoutBuilder.swift; sourceTree = ""; }; 80 | OBJ_25 /* ULBTypealias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ULBTypealias.swift; sourceTree = ""; }; 81 | OBJ_26 /* ViewProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewProxy.swift; sourceTree = ""; }; 82 | OBJ_29 /* UILayoutBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UILayoutBuilderTests.swift; sourceTree = ""; }; 83 | OBJ_30 /* XCTestManifests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestManifests.swift; sourceTree = ""; }; 84 | OBJ_34 /* Example */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Example; sourceTree = SOURCE_ROOT; }; 85 | OBJ_35 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 86 | OBJ_36 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 87 | OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 88 | "UILayoutBuilder::UILayoutBuilder::Product" /* UILayoutBuilder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = UILayoutBuilder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 89 | "UILayoutBuilder::UILayoutBuilderTests::Product" /* UILayoutBuilderTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = UILayoutBuilderTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 90 | /* End PBXFileReference section */ 91 | 92 | /* Begin PBXFrameworksBuildPhase section */ 93 | OBJ_58 /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 0; 96 | files = ( 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | OBJ_77 /* Frameworks */ = { 101 | isa = PBXFrameworksBuildPhase; 102 | buildActionMask = 0; 103 | files = ( 104 | OBJ_78 /* UILayoutBuilder.framework in Frameworks */, 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | /* End PBXFrameworksBuildPhase section */ 109 | 110 | /* Begin PBXGroup section */ 111 | OBJ_12 /* Internal */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | OBJ_13 /* Builder.swift */, 115 | OBJ_14 /* ConstraintUpdater.swift */, 116 | OBJ_15 /* Context.swift */, 117 | ); 118 | path = Internal; 119 | sourceTree = ""; 120 | }; 121 | OBJ_27 /* Tests */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | OBJ_28 /* UILayoutBuilderTests */, 125 | ); 126 | name = Tests; 127 | sourceTree = SOURCE_ROOT; 128 | }; 129 | OBJ_28 /* UILayoutBuilderTests */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | OBJ_29 /* UILayoutBuilderTests.swift */, 133 | OBJ_30 /* XCTestManifests.swift */, 134 | ); 135 | name = UILayoutBuilderTests; 136 | path = Tests/UILayoutBuilderTests; 137 | sourceTree = SOURCE_ROOT; 138 | }; 139 | OBJ_31 /* Products */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | "UILayoutBuilder::UILayoutBuilderTests::Product" /* UILayoutBuilderTests.xctest */, 143 | "UILayoutBuilder::UILayoutBuilder::Product" /* UILayoutBuilder.framework */, 144 | ); 145 | name = Products; 146 | sourceTree = BUILT_PRODUCTS_DIR; 147 | }; 148 | OBJ_5 = { 149 | isa = PBXGroup; 150 | children = ( 151 | OBJ_6 /* Package.swift */, 152 | OBJ_7 /* Sources */, 153 | OBJ_27 /* Tests */, 154 | OBJ_31 /* Products */, 155 | OBJ_34 /* Example */, 156 | OBJ_35 /* LICENSE */, 157 | OBJ_36 /* README.md */, 158 | ); 159 | sourceTree = ""; 160 | }; 161 | OBJ_7 /* Sources */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | OBJ_8 /* UILayoutBuilder */, 165 | ); 166 | name = Sources; 167 | sourceTree = SOURCE_ROOT; 168 | }; 169 | OBJ_8 /* UILayoutBuilder */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | OBJ_9 /* Extension */, 173 | OBJ_12 /* Internal */, 174 | ED85A67023F086A900DDD8C8 /* ConstrantGroupType.swift */, 175 | OBJ_16 /* LayoutAnchorType.swift */, 176 | OBJ_17 /* LayoutAxes.swift */, 177 | OBJ_18 /* LayoutAxis.swift */, 178 | OBJ_19 /* LayoutDimension.swift */, 179 | OBJ_20 /* LayoutEdges.swift */, 180 | OBJ_21 /* LayoutGuideProxy.swift */, 181 | OBJ_22 /* LayoutRepresentable.swift */, 182 | OBJ_23 /* LayoutSize.swift */, 183 | OBJ_24 /* UILayoutBuilder.swift */, 184 | OBJ_25 /* ULBTypealias.swift */, 185 | OBJ_26 /* ViewProxy.swift */, 186 | ); 187 | name = UILayoutBuilder; 188 | path = Sources/UILayoutBuilder; 189 | sourceTree = SOURCE_ROOT; 190 | }; 191 | OBJ_9 /* Extension */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | OBJ_10 /* UIStackViewExtension.swift */, 195 | OBJ_11 /* ULBViewExtension.swift */, 196 | ); 197 | path = Extension; 198 | sourceTree = ""; 199 | }; 200 | /* End PBXGroup section */ 201 | 202 | /* Begin PBXNativeTarget section */ 203 | "UILayoutBuilder::SwiftPMPackageDescription" /* UILayoutBuilderPackageDescription */ = { 204 | isa = PBXNativeTarget; 205 | buildConfigurationList = OBJ_60 /* Build configuration list for PBXNativeTarget "UILayoutBuilderPackageDescription" */; 206 | buildPhases = ( 207 | OBJ_63 /* Sources */, 208 | ); 209 | buildRules = ( 210 | ); 211 | dependencies = ( 212 | ); 213 | name = UILayoutBuilderPackageDescription; 214 | productName = UILayoutBuilderPackageDescription; 215 | productType = "com.apple.product-type.framework"; 216 | }; 217 | "UILayoutBuilder::UILayoutBuilder" /* UILayoutBuilder */ = { 218 | isa = PBXNativeTarget; 219 | buildConfigurationList = OBJ_38 /* Build configuration list for PBXNativeTarget "UILayoutBuilder" */; 220 | buildPhases = ( 221 | OBJ_41 /* Sources */, 222 | OBJ_58 /* Frameworks */, 223 | ); 224 | buildRules = ( 225 | ); 226 | dependencies = ( 227 | ); 228 | name = UILayoutBuilder; 229 | productName = UILayoutBuilder; 230 | productReference = "UILayoutBuilder::UILayoutBuilder::Product" /* UILayoutBuilder.framework */; 231 | productType = "com.apple.product-type.framework"; 232 | }; 233 | "UILayoutBuilder::UILayoutBuilderTests" /* UILayoutBuilderTests */ = { 234 | isa = PBXNativeTarget; 235 | buildConfigurationList = OBJ_71 /* Build configuration list for PBXNativeTarget "UILayoutBuilderTests" */; 236 | buildPhases = ( 237 | OBJ_74 /* Sources */, 238 | OBJ_77 /* Frameworks */, 239 | ); 240 | buildRules = ( 241 | ); 242 | dependencies = ( 243 | OBJ_79 /* PBXTargetDependency */, 244 | ); 245 | name = UILayoutBuilderTests; 246 | productName = UILayoutBuilderTests; 247 | productReference = "UILayoutBuilder::UILayoutBuilderTests::Product" /* UILayoutBuilderTests.xctest */; 248 | productType = "com.apple.product-type.bundle.unit-test"; 249 | }; 250 | /* End PBXNativeTarget section */ 251 | 252 | /* Begin PBXProject section */ 253 | OBJ_1 /* Project object */ = { 254 | isa = PBXProject; 255 | attributes = { 256 | LastSwiftMigration = 9999; 257 | LastUpgradeCheck = 9999; 258 | }; 259 | buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "UILayoutBuilder" */; 260 | compatibilityVersion = "Xcode 3.2"; 261 | developmentRegion = en; 262 | hasScannedForEncodings = 0; 263 | knownRegions = ( 264 | en, 265 | ); 266 | mainGroup = OBJ_5; 267 | productRefGroup = OBJ_31 /* Products */; 268 | projectDirPath = ""; 269 | projectRoot = ""; 270 | targets = ( 271 | "UILayoutBuilder::UILayoutBuilder" /* UILayoutBuilder */, 272 | "UILayoutBuilder::SwiftPMPackageDescription" /* UILayoutBuilderPackageDescription */, 273 | "UILayoutBuilder::UILayoutBuilderPackageTests::ProductTarget" /* UILayoutBuilderPackageTests */, 274 | "UILayoutBuilder::UILayoutBuilderTests" /* UILayoutBuilderTests */, 275 | ); 276 | }; 277 | /* End PBXProject section */ 278 | 279 | /* Begin PBXSourcesBuildPhase section */ 280 | OBJ_41 /* Sources */ = { 281 | isa = PBXSourcesBuildPhase; 282 | buildActionMask = 0; 283 | files = ( 284 | OBJ_42 /* UIStackViewExtension.swift in Sources */, 285 | OBJ_43 /* ULBViewExtension.swift in Sources */, 286 | OBJ_44 /* Builder.swift in Sources */, 287 | OBJ_45 /* ConstraintUpdater.swift in Sources */, 288 | OBJ_46 /* Context.swift in Sources */, 289 | OBJ_47 /* LayoutAnchorType.swift in Sources */, 290 | OBJ_48 /* LayoutAxes.swift in Sources */, 291 | OBJ_49 /* LayoutAxis.swift in Sources */, 292 | OBJ_50 /* LayoutDimension.swift in Sources */, 293 | OBJ_51 /* LayoutEdges.swift in Sources */, 294 | OBJ_52 /* LayoutGuideProxy.swift in Sources */, 295 | OBJ_53 /* LayoutRepresentable.swift in Sources */, 296 | OBJ_54 /* LayoutSize.swift in Sources */, 297 | ED85A67123F086AA00DDD8C8 /* ConstrantGroupType.swift in Sources */, 298 | OBJ_55 /* UILayoutBuilder.swift in Sources */, 299 | OBJ_56 /* ULBTypealias.swift in Sources */, 300 | OBJ_57 /* ViewProxy.swift in Sources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | OBJ_63 /* Sources */ = { 305 | isa = PBXSourcesBuildPhase; 306 | buildActionMask = 0; 307 | files = ( 308 | OBJ_64 /* Package.swift in Sources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | OBJ_74 /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 0; 315 | files = ( 316 | OBJ_75 /* UILayoutBuilderTests.swift in Sources */, 317 | OBJ_76 /* XCTestManifests.swift in Sources */, 318 | ); 319 | runOnlyForDeploymentPostprocessing = 0; 320 | }; 321 | /* End PBXSourcesBuildPhase section */ 322 | 323 | /* Begin PBXTargetDependency section */ 324 | OBJ_69 /* PBXTargetDependency */ = { 325 | isa = PBXTargetDependency; 326 | target = "UILayoutBuilder::UILayoutBuilderTests" /* UILayoutBuilderTests */; 327 | targetProxy = ED85A64C23F070EF00DDD8C8 /* PBXContainerItemProxy */; 328 | }; 329 | OBJ_79 /* PBXTargetDependency */ = { 330 | isa = PBXTargetDependency; 331 | target = "UILayoutBuilder::UILayoutBuilder" /* UILayoutBuilder */; 332 | targetProxy = ED85A64B23F070EC00DDD8C8 /* PBXContainerItemProxy */; 333 | }; 334 | /* End PBXTargetDependency section */ 335 | 336 | /* Begin XCBuildConfiguration section */ 337 | OBJ_3 /* Debug */ = { 338 | isa = XCBuildConfiguration; 339 | buildSettings = { 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | COMBINE_HIDPI_IMAGES = YES; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = dwarf; 344 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 345 | ENABLE_NS_ASSERTIONS = YES; 346 | GCC_OPTIMIZATION_LEVEL = 0; 347 | GCC_PREPROCESSOR_DEFINITIONS = ( 348 | "$(inherited)", 349 | "SWIFT_PACKAGE=1", 350 | "DEBUG=1", 351 | ); 352 | MACOSX_DEPLOYMENT_TARGET = 10.10; 353 | ONLY_ACTIVE_ARCH = YES; 354 | OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; 355 | PRODUCT_NAME = "$(TARGET_NAME)"; 356 | SDKROOT = macosx; 357 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; 358 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE DEBUG"; 359 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 360 | USE_HEADERMAP = NO; 361 | }; 362 | name = Debug; 363 | }; 364 | OBJ_39 /* Debug */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | ENABLE_TESTABILITY = YES; 368 | FRAMEWORK_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 371 | ); 372 | HEADER_SEARCH_PATHS = "$(inherited)"; 373 | INFOPLIST_FILE = UILayoutBuilder.xcodeproj/UILayoutBuilder_Info.plist; 374 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 375 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; 376 | MACOSX_DEPLOYMENT_TARGET = 10.11; 377 | OTHER_CFLAGS = "$(inherited)"; 378 | OTHER_LDFLAGS = "$(inherited)"; 379 | OTHER_SWIFT_FLAGS = "$(inherited)"; 380 | PRODUCT_BUNDLE_IDENTIFIER = UILayoutBuilder; 381 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 382 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 383 | SKIP_INSTALL = YES; 384 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; 385 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; 386 | SWIFT_VERSION = 5.0; 387 | TARGET_NAME = UILayoutBuilder; 388 | TVOS_DEPLOYMENT_TARGET = 10.0; 389 | WATCHOS_DEPLOYMENT_TARGET = ""; 390 | }; 391 | name = Debug; 392 | }; 393 | OBJ_4 /* Release */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | CLANG_ENABLE_OBJC_ARC = YES; 397 | COMBINE_HIDPI_IMAGES = YES; 398 | COPY_PHASE_STRIP = YES; 399 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 400 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 401 | GCC_OPTIMIZATION_LEVEL = s; 402 | GCC_PREPROCESSOR_DEFINITIONS = ( 403 | "$(inherited)", 404 | "SWIFT_PACKAGE=1", 405 | ); 406 | MACOSX_DEPLOYMENT_TARGET = 10.10; 407 | OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | SDKROOT = macosx; 410 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; 411 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE"; 412 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 413 | USE_HEADERMAP = NO; 414 | }; 415 | name = Release; 416 | }; 417 | OBJ_40 /* Release */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ENABLE_TESTABILITY = YES; 421 | FRAMEWORK_SEARCH_PATHS = ( 422 | "$(inherited)", 423 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 424 | ); 425 | HEADER_SEARCH_PATHS = "$(inherited)"; 426 | INFOPLIST_FILE = UILayoutBuilder.xcodeproj/UILayoutBuilder_Info.plist; 427 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 428 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; 429 | MACOSX_DEPLOYMENT_TARGET = 10.11; 430 | OTHER_CFLAGS = "$(inherited)"; 431 | OTHER_LDFLAGS = "$(inherited)"; 432 | OTHER_SWIFT_FLAGS = "$(inherited)"; 433 | PRODUCT_BUNDLE_IDENTIFIER = UILayoutBuilder; 434 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 435 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 436 | SKIP_INSTALL = YES; 437 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; 438 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; 439 | SWIFT_VERSION = 5.0; 440 | TARGET_NAME = UILayoutBuilder; 441 | TVOS_DEPLOYMENT_TARGET = 10.0; 442 | WATCHOS_DEPLOYMENT_TARGET = ""; 443 | }; 444 | name = Release; 445 | }; 446 | OBJ_61 /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | LD = /usr/bin/true; 450 | OTHER_SWIFT_FLAGS = "-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode_11.3.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -package-description-version 5.1"; 451 | SWIFT_VERSION = 5.0; 452 | }; 453 | name = Debug; 454 | }; 455 | OBJ_62 /* Release */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | LD = /usr/bin/true; 459 | OTHER_SWIFT_FLAGS = "-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode_11.3.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -package-description-version 5.1"; 460 | SWIFT_VERSION = 5.0; 461 | }; 462 | name = Release; 463 | }; 464 | OBJ_67 /* Debug */ = { 465 | isa = XCBuildConfiguration; 466 | buildSettings = { 467 | }; 468 | name = Debug; 469 | }; 470 | OBJ_68 /* Release */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | }; 474 | name = Release; 475 | }; 476 | OBJ_72 /* Debug */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | CLANG_ENABLE_MODULES = YES; 480 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 481 | FRAMEWORK_SEARCH_PATHS = ( 482 | "$(inherited)", 483 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 484 | ); 485 | HEADER_SEARCH_PATHS = "$(inherited)"; 486 | INFOPLIST_FILE = UILayoutBuilder.xcodeproj/UILayoutBuilderTests_Info.plist; 487 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 488 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks"; 489 | MACOSX_DEPLOYMENT_TARGET = 10.11; 490 | OTHER_CFLAGS = "$(inherited)"; 491 | OTHER_LDFLAGS = "$(inherited)"; 492 | OTHER_SWIFT_FLAGS = "$(inherited)"; 493 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; 494 | SWIFT_VERSION = 5.0; 495 | TARGET_NAME = UILayoutBuilderTests; 496 | TVOS_DEPLOYMENT_TARGET = 10.0; 497 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 498 | }; 499 | name = Debug; 500 | }; 501 | OBJ_73 /* Release */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | CLANG_ENABLE_MODULES = YES; 505 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 506 | FRAMEWORK_SEARCH_PATHS = ( 507 | "$(inherited)", 508 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 509 | ); 510 | HEADER_SEARCH_PATHS = "$(inherited)"; 511 | INFOPLIST_FILE = UILayoutBuilder.xcodeproj/UILayoutBuilderTests_Info.plist; 512 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 513 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks"; 514 | MACOSX_DEPLOYMENT_TARGET = 10.11; 515 | OTHER_CFLAGS = "$(inherited)"; 516 | OTHER_LDFLAGS = "$(inherited)"; 517 | OTHER_SWIFT_FLAGS = "$(inherited)"; 518 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; 519 | SWIFT_VERSION = 5.0; 520 | TARGET_NAME = UILayoutBuilderTests; 521 | TVOS_DEPLOYMENT_TARGET = 10.0; 522 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 523 | }; 524 | name = Release; 525 | }; 526 | /* End XCBuildConfiguration section */ 527 | 528 | /* Begin XCConfigurationList section */ 529 | OBJ_2 /* Build configuration list for PBXProject "UILayoutBuilder" */ = { 530 | isa = XCConfigurationList; 531 | buildConfigurations = ( 532 | OBJ_3 /* Debug */, 533 | OBJ_4 /* Release */, 534 | ); 535 | defaultConfigurationIsVisible = 0; 536 | defaultConfigurationName = Release; 537 | }; 538 | OBJ_38 /* Build configuration list for PBXNativeTarget "UILayoutBuilder" */ = { 539 | isa = XCConfigurationList; 540 | buildConfigurations = ( 541 | OBJ_39 /* Debug */, 542 | OBJ_40 /* Release */, 543 | ); 544 | defaultConfigurationIsVisible = 0; 545 | defaultConfigurationName = Release; 546 | }; 547 | OBJ_60 /* Build configuration list for PBXNativeTarget "UILayoutBuilderPackageDescription" */ = { 548 | isa = XCConfigurationList; 549 | buildConfigurations = ( 550 | OBJ_61 /* Debug */, 551 | OBJ_62 /* Release */, 552 | ); 553 | defaultConfigurationIsVisible = 0; 554 | defaultConfigurationName = Release; 555 | }; 556 | OBJ_66 /* Build configuration list for PBXAggregateTarget "UILayoutBuilderPackageTests" */ = { 557 | isa = XCConfigurationList; 558 | buildConfigurations = ( 559 | OBJ_67 /* Debug */, 560 | OBJ_68 /* Release */, 561 | ); 562 | defaultConfigurationIsVisible = 0; 563 | defaultConfigurationName = Release; 564 | }; 565 | OBJ_71 /* Build configuration list for PBXNativeTarget "UILayoutBuilderTests" */ = { 566 | isa = XCConfigurationList; 567 | buildConfigurations = ( 568 | OBJ_72 /* Debug */, 569 | OBJ_73 /* Release */, 570 | ); 571 | defaultConfigurationIsVisible = 0; 572 | defaultConfigurationName = Release; 573 | }; 574 | /* End XCConfigurationList section */ 575 | }; 576 | rootObject = OBJ_1 /* Project object */; 577 | } 578 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/xcshareddata/xcschemes/UILayoutBuilder-Package.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 63 | 64 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /UILayoutBuilder.xcodeproj/xcshareddata/xcschemes/UILayoutBuilder.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | --------------------------------------------------------------------------------