├── .gitattributes ├── FlexboxKit.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ └── FlexboxKit.xccheckout │ └── xcuserdata │ └── alexusbergo.xcuserdatad │ ├── UserInterfaceState.xcuserstate │ └── WorkspaceSettings.xcsettings ├── FlexboxKit ├── FLEXBOXContainerView.h ├── FLEXBOXContainerView.m ├── FLEXBOXNode.h ├── FLEXBOXNode.m ├── FlexboxKit.h ├── Info.plist ├── Layout.c ├── Layout.h ├── UIView+FLEXBOX.h └── UIView+FLEXBOX.m ├── FlexboxKitDemo ├── FlexboxKitDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ └── FlexboxKitDemo.xccheckout │ │ └── xcuserdata │ │ └── alexusbergo.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings ├── FlexboxKitDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── ButtonDemoViewController.h │ ├── ButtonDemoViewController.m │ ├── CellDemoTableViewController.h │ ├── CellDemoTableViewController.m │ ├── GridDemoViewController.h │ ├── GridDemoViewController.m │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── UIColor+Demo.h │ ├── UIColor+Demo.m │ └── main.m └── FlexboxKitDemoTests │ ├── FlexboxKitDemoTests.m │ └── Info.plist ├── FlexboxKitTests ├── FlexboxKitTests.m └── Info.plist ├── LICENSE ├── README.md ├── cell-example.png └── demo.gif /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c linguist-language=Objective-c 2 | -------------------------------------------------------------------------------- /FlexboxKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1603018D1AFF551600D249F2 /* FLEXBOXContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1603018B1AFF551600D249F2 /* FLEXBOXContainerView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 1603018E1AFF551600D249F2 /* FLEXBOXContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1603018C1AFF551600D249F2 /* FLEXBOXContainerView.m */; }; 12 | 16AD78A01AFE7C50003C2D01 /* FlexboxKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 16AD789F1AFE7C50003C2D01 /* FlexboxKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | 16AD78A61AFE7C50003C2D01 /* FlexboxKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16AD789A1AFE7C50003C2D01 /* FlexboxKit.framework */; }; 14 | 16AD78AD1AFE7C50003C2D01 /* FlexboxKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78AC1AFE7C50003C2D01 /* FlexboxKitTests.m */; }; 15 | 16AD78B81AFE7C69003C2D01 /* Layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78B61AFE7C69003C2D01 /* Layout.c */; }; 16 | 16AD78B91AFE7C69003C2D01 /* Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 16AD78B71AFE7C69003C2D01 /* Layout.h */; settings = {ATTRIBUTES = (Public, ); }; }; 17 | 16AD78BC1AFE7C92003C2D01 /* FLEXBOXNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 16AD78BA1AFE7C92003C2D01 /* FLEXBOXNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | 16AD78BD1AFE7C92003C2D01 /* FLEXBOXNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78BB1AFE7C92003C2D01 /* FLEXBOXNode.m */; }; 19 | 16AD78C01AFE8FB2003C2D01 /* UIView+FLEXBOX.h in Headers */ = {isa = PBXBuildFile; fileRef = 16AD78BE1AFE8FB2003C2D01 /* UIView+FLEXBOX.h */; settings = {ATTRIBUTES = (Public, ); }; }; 20 | 16AD78C11AFE8FB2003C2D01 /* UIView+FLEXBOX.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78BF1AFE8FB2003C2D01 /* UIView+FLEXBOX.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 16AD78A71AFE7C50003C2D01 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 16AD78911AFE7C50003C2D01 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 16AD78991AFE7C50003C2D01; 29 | remoteInfo = FlexboxKit; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 1603018B1AFF551600D249F2 /* FLEXBOXContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXBOXContainerView.h; sourceTree = ""; }; 35 | 1603018C1AFF551600D249F2 /* FLEXBOXContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXBOXContainerView.m; sourceTree = ""; }; 36 | 16AD789A1AFE7C50003C2D01 /* FlexboxKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FlexboxKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 16AD789E1AFE7C50003C2D01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 16AD789F1AFE7C50003C2D01 /* FlexboxKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FlexboxKit.h; sourceTree = ""; }; 39 | 16AD78A51AFE7C50003C2D01 /* FlexboxKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FlexboxKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 16AD78AB1AFE7C50003C2D01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 16AD78AC1AFE7C50003C2D01 /* FlexboxKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlexboxKitTests.m; sourceTree = ""; }; 42 | 16AD78B61AFE7C69003C2D01 /* Layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Layout.c; sourceTree = ""; }; 43 | 16AD78B71AFE7C69003C2D01 /* Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Layout.h; sourceTree = ""; }; 44 | 16AD78BA1AFE7C92003C2D01 /* FLEXBOXNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXBOXNode.h; sourceTree = ""; }; 45 | 16AD78BB1AFE7C92003C2D01 /* FLEXBOXNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXBOXNode.m; sourceTree = ""; }; 46 | 16AD78BE1AFE8FB2003C2D01 /* UIView+FLEXBOX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+FLEXBOX.h"; sourceTree = ""; }; 47 | 16AD78BF1AFE8FB2003C2D01 /* UIView+FLEXBOX.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+FLEXBOX.m"; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 16AD78961AFE7C50003C2D01 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | 16AD78A21AFE7C50003C2D01 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | 16AD78A61AFE7C50003C2D01 /* FlexboxKit.framework in Frameworks */, 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | 16AD78901AFE7C50003C2D01 = { 70 | isa = PBXGroup; 71 | children = ( 72 | 16AD789C1AFE7C50003C2D01 /* FlexboxKit */, 73 | 16AD78A91AFE7C50003C2D01 /* FlexboxKitTests */, 74 | 16AD789B1AFE7C50003C2D01 /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 16AD789B1AFE7C50003C2D01 /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 16AD789A1AFE7C50003C2D01 /* FlexboxKit.framework */, 82 | 16AD78A51AFE7C50003C2D01 /* FlexboxKitTests.xctest */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | 16AD789C1AFE7C50003C2D01 /* FlexboxKit */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 16AD78B71AFE7C69003C2D01 /* Layout.h */, 91 | 16AD78B61AFE7C69003C2D01 /* Layout.c */, 92 | 16AD78BA1AFE7C92003C2D01 /* FLEXBOXNode.h */, 93 | 16AD78BB1AFE7C92003C2D01 /* FLEXBOXNode.m */, 94 | 16AD78BE1AFE8FB2003C2D01 /* UIView+FLEXBOX.h */, 95 | 16AD78BF1AFE8FB2003C2D01 /* UIView+FLEXBOX.m */, 96 | 1603018B1AFF551600D249F2 /* FLEXBOXContainerView.h */, 97 | 1603018C1AFF551600D249F2 /* FLEXBOXContainerView.m */, 98 | 16AD789F1AFE7C50003C2D01 /* FlexboxKit.h */, 99 | 16AD789D1AFE7C50003C2D01 /* Supporting Files */, 100 | ); 101 | path = FlexboxKit; 102 | sourceTree = ""; 103 | }; 104 | 16AD789D1AFE7C50003C2D01 /* Supporting Files */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 16AD789E1AFE7C50003C2D01 /* Info.plist */, 108 | ); 109 | name = "Supporting Files"; 110 | sourceTree = ""; 111 | }; 112 | 16AD78A91AFE7C50003C2D01 /* FlexboxKitTests */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 16AD78AC1AFE7C50003C2D01 /* FlexboxKitTests.m */, 116 | 16AD78AA1AFE7C50003C2D01 /* Supporting Files */, 117 | ); 118 | path = FlexboxKitTests; 119 | sourceTree = ""; 120 | }; 121 | 16AD78AA1AFE7C50003C2D01 /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 16AD78AB1AFE7C50003C2D01 /* Info.plist */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXHeadersBuildPhase section */ 132 | 16AD78971AFE7C50003C2D01 /* Headers */ = { 133 | isa = PBXHeadersBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | 1603018D1AFF551600D249F2 /* FLEXBOXContainerView.h in Headers */, 137 | 16AD78B91AFE7C69003C2D01 /* Layout.h in Headers */, 138 | 16AD78BC1AFE7C92003C2D01 /* FLEXBOXNode.h in Headers */, 139 | 16AD78C01AFE8FB2003C2D01 /* UIView+FLEXBOX.h in Headers */, 140 | 16AD78A01AFE7C50003C2D01 /* FlexboxKit.h in Headers */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXHeadersBuildPhase section */ 145 | 146 | /* Begin PBXNativeTarget section */ 147 | 16AD78991AFE7C50003C2D01 /* FlexboxKit */ = { 148 | isa = PBXNativeTarget; 149 | buildConfigurationList = 16AD78B01AFE7C50003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKit" */; 150 | buildPhases = ( 151 | 16AD78951AFE7C50003C2D01 /* Sources */, 152 | 16AD78961AFE7C50003C2D01 /* Frameworks */, 153 | 16AD78971AFE7C50003C2D01 /* Headers */, 154 | 16AD78981AFE7C50003C2D01 /* Resources */, 155 | ); 156 | buildRules = ( 157 | ); 158 | dependencies = ( 159 | ); 160 | name = FlexboxKit; 161 | productName = FlexboxKit; 162 | productReference = 16AD789A1AFE7C50003C2D01 /* FlexboxKit.framework */; 163 | productType = "com.apple.product-type.framework"; 164 | }; 165 | 16AD78A41AFE7C50003C2D01 /* FlexboxKitTests */ = { 166 | isa = PBXNativeTarget; 167 | buildConfigurationList = 16AD78B31AFE7C50003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKitTests" */; 168 | buildPhases = ( 169 | 16AD78A11AFE7C50003C2D01 /* Sources */, 170 | 16AD78A21AFE7C50003C2D01 /* Frameworks */, 171 | 16AD78A31AFE7C50003C2D01 /* Resources */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | 16AD78A81AFE7C50003C2D01 /* PBXTargetDependency */, 177 | ); 178 | name = FlexboxKitTests; 179 | productName = FlexboxKitTests; 180 | productReference = 16AD78A51AFE7C50003C2D01 /* FlexboxKitTests.xctest */; 181 | productType = "com.apple.product-type.bundle.unit-test"; 182 | }; 183 | /* End PBXNativeTarget section */ 184 | 185 | /* Begin PBXProject section */ 186 | 16AD78911AFE7C50003C2D01 /* Project object */ = { 187 | isa = PBXProject; 188 | attributes = { 189 | LastUpgradeCheck = 0640; 190 | ORGANIZATIONNAME = "Alex Usbergo"; 191 | TargetAttributes = { 192 | 16AD78991AFE7C50003C2D01 = { 193 | CreatedOnToolsVersion = 6.4; 194 | }; 195 | 16AD78A41AFE7C50003C2D01 = { 196 | CreatedOnToolsVersion = 6.4; 197 | }; 198 | }; 199 | }; 200 | buildConfigurationList = 16AD78941AFE7C50003C2D01 /* Build configuration list for PBXProject "FlexboxKit" */; 201 | compatibilityVersion = "Xcode 3.2"; 202 | developmentRegion = English; 203 | hasScannedForEncodings = 0; 204 | knownRegions = ( 205 | en, 206 | ); 207 | mainGroup = 16AD78901AFE7C50003C2D01; 208 | productRefGroup = 16AD789B1AFE7C50003C2D01 /* Products */; 209 | projectDirPath = ""; 210 | projectRoot = ""; 211 | targets = ( 212 | 16AD78991AFE7C50003C2D01 /* FlexboxKit */, 213 | 16AD78A41AFE7C50003C2D01 /* FlexboxKitTests */, 214 | ); 215 | }; 216 | /* End PBXProject section */ 217 | 218 | /* Begin PBXResourcesBuildPhase section */ 219 | 16AD78981AFE7C50003C2D01 /* Resources */ = { 220 | isa = PBXResourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | 16AD78A31AFE7C50003C2D01 /* Resources */ = { 227 | isa = PBXResourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXResourcesBuildPhase section */ 234 | 235 | /* Begin PBXSourcesBuildPhase section */ 236 | 16AD78951AFE7C50003C2D01 /* Sources */ = { 237 | isa = PBXSourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 16AD78BD1AFE7C92003C2D01 /* FLEXBOXNode.m in Sources */, 241 | 16AD78C11AFE8FB2003C2D01 /* UIView+FLEXBOX.m in Sources */, 242 | 16AD78B81AFE7C69003C2D01 /* Layout.c in Sources */, 243 | 1603018E1AFF551600D249F2 /* FLEXBOXContainerView.m in Sources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | 16AD78A11AFE7C50003C2D01 /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | 16AD78AD1AFE7C50003C2D01 /* FlexboxKitTests.m in Sources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | /* End PBXSourcesBuildPhase section */ 256 | 257 | /* Begin PBXTargetDependency section */ 258 | 16AD78A81AFE7C50003C2D01 /* PBXTargetDependency */ = { 259 | isa = PBXTargetDependency; 260 | target = 16AD78991AFE7C50003C2D01 /* FlexboxKit */; 261 | targetProxy = 16AD78A71AFE7C50003C2D01 /* PBXContainerItemProxy */; 262 | }; 263 | /* End PBXTargetDependency section */ 264 | 265 | /* Begin XCBuildConfiguration section */ 266 | 16AD78AE1AFE7C50003C2D01 /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_SEARCH_USER_PATHS = NO; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BOOL_CONVERSION = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_INT_CONVERSION = YES; 280 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 284 | COPY_PHASE_STRIP = NO; 285 | CURRENT_PROJECT_VERSION = 1; 286 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 287 | ENABLE_STRICT_OBJC_MSGSEND = YES; 288 | GCC_C_LANGUAGE_STANDARD = gnu99; 289 | GCC_DYNAMIC_NO_PIC = NO; 290 | GCC_NO_COMMON_BLOCKS = YES; 291 | GCC_OPTIMIZATION_LEVEL = 0; 292 | GCC_PREPROCESSOR_DEFINITIONS = ( 293 | "DEBUG=1", 294 | "$(inherited)", 295 | ); 296 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 304 | MTL_ENABLE_DEBUG_INFO = YES; 305 | ONLY_ACTIVE_ARCH = YES; 306 | SDKROOT = iphoneos; 307 | TARGETED_DEVICE_FAMILY = "1,2"; 308 | VERSIONING_SYSTEM = "apple-generic"; 309 | VERSION_INFO_PREFIX = ""; 310 | }; 311 | name = Debug; 312 | }; 313 | 16AD78AF1AFE7C50003C2D01 /* Release */ = { 314 | isa = XCBuildConfiguration; 315 | buildSettings = { 316 | ALWAYS_SEARCH_USER_PATHS = NO; 317 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 318 | CLANG_CXX_LIBRARY = "libc++"; 319 | CLANG_ENABLE_MODULES = YES; 320 | CLANG_ENABLE_OBJC_ARC = YES; 321 | CLANG_WARN_BOOL_CONVERSION = YES; 322 | CLANG_WARN_CONSTANT_CONVERSION = YES; 323 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 324 | CLANG_WARN_EMPTY_BODY = YES; 325 | CLANG_WARN_ENUM_CONVERSION = YES; 326 | CLANG_WARN_INT_CONVERSION = YES; 327 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | CURRENT_PROJECT_VERSION = 1; 333 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 334 | ENABLE_NS_ASSERTIONS = NO; 335 | ENABLE_STRICT_OBJC_MSGSEND = YES; 336 | GCC_C_LANGUAGE_STANDARD = gnu99; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 339 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 340 | GCC_WARN_UNDECLARED_SELECTOR = YES; 341 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 342 | GCC_WARN_UNUSED_FUNCTION = YES; 343 | GCC_WARN_UNUSED_VARIABLE = YES; 344 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 345 | MTL_ENABLE_DEBUG_INFO = NO; 346 | SDKROOT = iphoneos; 347 | TARGETED_DEVICE_FAMILY = "1,2"; 348 | VALIDATE_PRODUCT = YES; 349 | VERSIONING_SYSTEM = "apple-generic"; 350 | VERSION_INFO_PREFIX = ""; 351 | }; 352 | name = Release; 353 | }; 354 | 16AD78B11AFE7C50003C2D01 /* Debug */ = { 355 | isa = XCBuildConfiguration; 356 | buildSettings = { 357 | DEFINES_MODULE = YES; 358 | DYLIB_COMPATIBILITY_VERSION = 1; 359 | DYLIB_CURRENT_VERSION = 1; 360 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 361 | INFOPLIST_FILE = FlexboxKit/Info.plist; 362 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 363 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | SKIP_INSTALL = YES; 366 | }; 367 | name = Debug; 368 | }; 369 | 16AD78B21AFE7C50003C2D01 /* Release */ = { 370 | isa = XCBuildConfiguration; 371 | buildSettings = { 372 | DEFINES_MODULE = YES; 373 | DYLIB_COMPATIBILITY_VERSION = 1; 374 | DYLIB_CURRENT_VERSION = 1; 375 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 376 | INFOPLIST_FILE = FlexboxKit/Info.plist; 377 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 378 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 379 | PRODUCT_NAME = "$(TARGET_NAME)"; 380 | SKIP_INSTALL = YES; 381 | }; 382 | name = Release; 383 | }; 384 | 16AD78B41AFE7C50003C2D01 /* Debug */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | FRAMEWORK_SEARCH_PATHS = ( 388 | "$(SDKROOT)/Developer/Library/Frameworks", 389 | "$(inherited)", 390 | ); 391 | GCC_PREPROCESSOR_DEFINITIONS = ( 392 | "DEBUG=1", 393 | "$(inherited)", 394 | ); 395 | INFOPLIST_FILE = FlexboxKitTests/Info.plist; 396 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 397 | PRODUCT_NAME = "$(TARGET_NAME)"; 398 | }; 399 | name = Debug; 400 | }; 401 | 16AD78B51AFE7C50003C2D01 /* Release */ = { 402 | isa = XCBuildConfiguration; 403 | buildSettings = { 404 | FRAMEWORK_SEARCH_PATHS = ( 405 | "$(SDKROOT)/Developer/Library/Frameworks", 406 | "$(inherited)", 407 | ); 408 | INFOPLIST_FILE = FlexboxKitTests/Info.plist; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | }; 412 | name = Release; 413 | }; 414 | /* End XCBuildConfiguration section */ 415 | 416 | /* Begin XCConfigurationList section */ 417 | 16AD78941AFE7C50003C2D01 /* Build configuration list for PBXProject "FlexboxKit" */ = { 418 | isa = XCConfigurationList; 419 | buildConfigurations = ( 420 | 16AD78AE1AFE7C50003C2D01 /* Debug */, 421 | 16AD78AF1AFE7C50003C2D01 /* Release */, 422 | ); 423 | defaultConfigurationIsVisible = 0; 424 | defaultConfigurationName = Release; 425 | }; 426 | 16AD78B01AFE7C50003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKit" */ = { 427 | isa = XCConfigurationList; 428 | buildConfigurations = ( 429 | 16AD78B11AFE7C50003C2D01 /* Debug */, 430 | 16AD78B21AFE7C50003C2D01 /* Release */, 431 | ); 432 | defaultConfigurationIsVisible = 0; 433 | defaultConfigurationName = Release; 434 | }; 435 | 16AD78B31AFE7C50003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKitTests" */ = { 436 | isa = XCConfigurationList; 437 | buildConfigurations = ( 438 | 16AD78B41AFE7C50003C2D01 /* Debug */, 439 | 16AD78B51AFE7C50003C2D01 /* Release */, 440 | ); 441 | defaultConfigurationIsVisible = 0; 442 | defaultConfigurationName = Release; 443 | }; 444 | /* End XCConfigurationList section */ 445 | }; 446 | rootObject = 16AD78911AFE7C50003C2D01 /* Project object */; 447 | } 448 | -------------------------------------------------------------------------------- /FlexboxKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FlexboxKit.xcodeproj/project.xcworkspace/xcshareddata/FlexboxKit.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 8BA3A973-546B-4352-B825-4C72534C56FF 9 | IDESourceControlProjectName 10 | FlexboxKit 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 14 | github.com:alexdrone/ios-flexboxkit.git 15 | 16 | IDESourceControlProjectPath 17 | FlexboxKit.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:alexdrone/ios-flexboxkit.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 36 | IDESourceControlWCCName 37 | ios-flexboxkit 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /FlexboxKit.xcodeproj/project.xcworkspace/xcuserdata/alexusbergo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexdrone/flexboxobjc_deprecated/db7e0dd588ad664d9d239a564219279fe6f05b35/FlexboxKit.xcodeproj/project.xcworkspace/xcuserdata/alexusbergo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FlexboxKit.xcodeproj/project.xcworkspace/xcuserdata/alexusbergo.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FlexboxKit/FLEXBOXContainerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLEXBOXContainerView.h 3 | // FlexboxKit 4 | // 5 | // Created by Alex Usbergo on 10/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FLEXBOXContainerView : UIView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FlexboxKit/FLEXBOXContainerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLEXBOXContainerView.m 3 | // FlexboxKit 4 | // 5 | // Created by Alex Usbergo on 10/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import "FLEXBOXContainerView.h" 10 | #import "UIView+FLEXBOX.h" 11 | 12 | @implementation FLEXBOXContainerView 13 | 14 | - (void)layoutSubviews 15 | { 16 | //default flexbox container attributes 17 | self.flex = self.flex < FLT_EPSILON ? 1 : self.flex; 18 | self.flexContainer = YES; 19 | 20 | [super layoutSubviews]; 21 | [self flexLayoutSubviews]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /FlexboxKit/FLEXBOXNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLEXBOXNode.h 3 | // FlexboxKit 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import "Layout.h" 10 | @import UIKit; 11 | 12 | typedef NS_ENUM(NSInteger, FLEXBOXFlexDirection) { 13 | FLEXBOXFlexDirectionColumn = CSS_FLEX_DIRECTION_COLUMN, 14 | FLEXBOXFlexDirectionRow = CSS_FLEX_DIRECTION_ROW, 15 | FLEXBOXFlexDirectionRowReverse = CSS_FLEX_DIRECTION_ROW_REVERSE, 16 | FLEXBOXFlexDirectionColumnReverse = CSS_FLEX_DIRECTION_COLUMN_REVERSE 17 | }; 18 | 19 | typedef NS_ENUM(NSInteger, FLEXBOXContentDirection) { 20 | FLEXBOXContentDirectionInherit = CSS_DIRECTION_INHERIT, 21 | FLEXBOXContentDirectionLeftToRight = CSS_DIRECTION_LTR, 22 | FLEXBOXContentDirectionRightToLeft = CSS_DIRECTION_RTL 23 | }; 24 | 25 | typedef NS_ENUM(NSInteger, FLEXBOXJustification) { 26 | FLEXBOXJustificationFlexStart = CSS_JUSTIFY_FLEX_START, 27 | FLEXBOXJustificationCenter = CSS_JUSTIFY_CENTER, 28 | FLEXBOXJustificationFlexEnd = CSS_JUSTIFY_FLEX_END, 29 | FLEXBOXJustificationSpaceBetween = CSS_JUSTIFY_SPACE_BETWEEN, 30 | FLEXBOXJustificationSpaceAround = CSS_JUSTIFY_SPACE_AROUND 31 | }; 32 | 33 | typedef NS_ENUM(NSInteger, FLEXBOXAlignment) { 34 | FLEXBOXAlignmentAuto = CSS_ALIGN_AUTO, 35 | FLEXBOXAlignmentFlexStart = CSS_ALIGN_FLEX_START, 36 | FLEXBOXAlignmentCenter = CSS_ALIGN_CENTER, 37 | FLEXBOXAlignmentFlexEnd = CSS_ALIGN_FLEX_END, 38 | FLEXBOXAlignmentStretch = CSS_ALIGN_STRETCH 39 | }; 40 | 41 | extern const CGFloat FLEXBOXUndefinedDimension; 42 | 43 | @interface FLEXBOXNode : NSObject 44 | 45 | @property (nonatomic, readonly, assign) css_node_t *node; 46 | @property (nonatomic, readonly, assign) CGRect frame; 47 | 48 | @property (nonatomic, copy) CGSize (^measureBlock)(CGFloat width); 49 | @property (nonatomic, copy) FLEXBOXNode *(^childrenAtIndexBlock)(NSUInteger i); 50 | @property (nonatomic, copy) NSUInteger (^childrenCountBlock)(void); 51 | 52 | 53 | /// Compute the layout for the node constrained to the width passed as argument 54 | /// @param maximumWidth The maximum width or FLEXBOXUndefinedDimension 55 | - (void)layoutConstrainedToMaximumWidth:(CGFloat)maximumWidth; 56 | 57 | // Style 58 | 59 | @property (nonatomic, assign) CGSize dimensions; 60 | @property (nonatomic, assign) CGSize minDimensions; 61 | @property (nonatomic, assign) CGSize maxDimensions; 62 | @property (nonatomic, assign) FLEXBOXFlexDirection flexDirection; 63 | @property (nonatomic, assign) UIEdgeInsets margin; 64 | @property (nonatomic, assign) UIEdgeInsets padding; 65 | @property (nonatomic, assign) BOOL flexWrap; 66 | @property (nonatomic, assign) FLEXBOXJustification justifyContent; 67 | @property (nonatomic, assign) FLEXBOXAlignment alignSelf; 68 | @property (nonatomic, assign) FLEXBOXAlignment alignItems; 69 | @property (nonatomic, assign) CGFloat flex; 70 | @property (nonatomic, assign) FLEXBOXContentDirection contentDirection; 71 | 72 | @end 73 | 74 | -------------------------------------------------------------------------------- /FlexboxKit/FLEXBOXNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLEXBOXNode.m 3 | // FlexboxKit 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import "FLEXBOXNode.h" 10 | 11 | const CGFloat FLEXBOXUndefinedDimension = CSS_UNDEFINED; 12 | 13 | static bool FLEXBOX_alwaysDirty(void *context) 14 | { 15 | return YES; 16 | } 17 | 18 | static css_node_t *FLEXBOX_getChild(void *context, int i) 19 | { 20 | FLEXBOXNode *_self = (__bridge FLEXBOXNode*)context; 21 | FLEXBOXNode *child = _self.childrenAtIndexBlock(i); 22 | return child.node; 23 | } 24 | 25 | static css_dim_t FLEXBOX_measureNode(void *context, float width) 26 | { 27 | FLEXBOXNode *_self = (__bridge FLEXBOXNode*)context; 28 | CGSize size = _self.measureBlock(width); 29 | return (css_dim_t){ size.width, size.height }; 30 | } 31 | 32 | @implementation FLEXBOXNode 33 | 34 | #pragma mark - Lifecycle 35 | 36 | - (instancetype)init 37 | { 38 | if (self = [super init]) { 39 | 40 | //initialise the css_node_t 41 | _node = new_css_node(); 42 | _node->context = (__bridge void *)self; 43 | _node->is_dirty = FLEXBOX_alwaysDirty; 44 | _node->measure = FLEXBOX_measureNode; 45 | _node->get_child = FLEXBOX_getChild; 46 | 47 | _maxDimensions = CGSizeZero; 48 | _minDimensions = CGSizeZero; 49 | 50 | //defaults 51 | self.flexDirection = FLEXBOXFlexDirectionColumn; 52 | self.flexWrap = NO; 53 | self.alignItems = FLEXBOXAlignmentStretch; 54 | self.alignSelf = FLEXBOXAlignmentAuto; 55 | self.margin = UIEdgeInsetsZero; 56 | self.padding = UIEdgeInsetsZero; 57 | self.justifyContent = FLEXBOXJustificationFlexStart; 58 | self.flex = 0; 59 | self.contentDirection = FLEXBOXContentDirectionInherit; 60 | } 61 | 62 | return self; 63 | } 64 | 65 | - (void)dealloc 66 | { 67 | free_css_node(_node); 68 | } 69 | 70 | #pragma mark - Layout and Internals 71 | 72 | - (void)prepareForLayout 73 | { 74 | if (self.childrenAtIndexBlock == nil) 75 | return; 76 | 77 | NSAssert(self.childrenCountBlock, nil); 78 | NSUInteger count = self.childrenCountBlock(); 79 | 80 | // prepares the nodes for the layout recursively 81 | for (NSInteger i = 0; i < count; i++) { 82 | FLEXBOXNode *node = self.childrenAtIndexBlock(i); 83 | [node prepareForLayout]; 84 | } 85 | 86 | // Apparently we need to reset these before laying out, otherwise the layout 87 | // has some weird additive effect. 88 | self.node->layout.position[CSS_LEFT] = 0; 89 | self.node->layout.position[CSS_TOP] = 0; 90 | self.node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; 91 | self.node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; 92 | } 93 | 94 | - (void)layoutConstrainedToMaximumWidth:(CGFloat)maximumWidth 95 | { 96 | _node->children_count = (int)self.childrenCountBlock(); 97 | 98 | maximumWidth = fabs(maximumWidth - FLT_MAX) < FLT_EPSILON ? FLEXBOXUndefinedDimension : maximumWidth; 99 | [self prepareForLayout]; 100 | layoutNode(_node, maximumWidth, _node->style.direction); 101 | } 102 | 103 | - (CGRect)frame 104 | { 105 | return (CGRect) { 106 | .origin.x = self.node->layout.position[CSS_LEFT], 107 | .origin.y = self.node->layout.position[CSS_TOP], 108 | .size.width = self.node->layout.dimensions[CSS_WIDTH], 109 | .size.height = self.node->layout.dimensions[CSS_HEIGHT] 110 | }; 111 | } 112 | 113 | #pragma mark - Style 114 | 115 | - (void)setDimensions:(CGSize)size 116 | { 117 | _dimensions = size; 118 | _node->style.dimensions[CSS_WIDTH] = size.width; 119 | _node->style.dimensions[CSS_HEIGHT] = size.height; 120 | } 121 | 122 | - (void)setMinDimensions:(CGSize)size 123 | { 124 | _minDimensions = size; 125 | // _node->style.minDimensions[CSS_WIDTH] = size.width; 126 | // _node->style.minDimensions[CSS_HEIGHT] = size.height; 127 | } 128 | 129 | - (void)setMaxDimensions:(CGSize)size 130 | { 131 | _maxDimensions = size; 132 | // _node->style.maxDimensions[CSS_WIDTH] = size.width; 133 | // _node->style.maxDimensions[CSS_HEIGHT] = size.height; 134 | } 135 | 136 | - (void)setFlexDirection:(FLEXBOXFlexDirection)flexDirection 137 | { 138 | _flexDirection = flexDirection; 139 | _node->style.flex_direction = (int)flexDirection; 140 | } 141 | 142 | - (void)setMargin:(UIEdgeInsets)margin 143 | { 144 | _margin = margin; 145 | _node->style.margin[CSS_LEFT] = margin.left; 146 | _node->style.margin[CSS_TOP] = margin.top; 147 | _node->style.margin[CSS_RIGHT] = margin.right; 148 | _node->style.margin[CSS_BOTTOM] = margin.bottom; 149 | } 150 | 151 | - (void)setPadding:(UIEdgeInsets)padding 152 | { 153 | _padding = padding; 154 | _node->style.padding[CSS_LEFT] = padding.left; 155 | _node->style.padding[CSS_TOP] = padding.top; 156 | _node->style.padding[CSS_RIGHT] = padding.right; 157 | _node->style.padding[CSS_BOTTOM] = padding.bottom; 158 | } 159 | 160 | - (void)setFlex:(CGFloat)flex 161 | { 162 | _flex = flex; 163 | _node->style.flex = flex; 164 | } 165 | 166 | - (void)setFlexWrap:(BOOL)flexWrap 167 | { 168 | _flexWrap = flexWrap; 169 | _node->style.flex_wrap = flexWrap; 170 | } 171 | 172 | - (void)setJustifyContent:(FLEXBOXJustification)justifyContent 173 | { 174 | _justifyContent = justifyContent; 175 | _node->style.justify_content = (int)justifyContent; 176 | } 177 | 178 | - (void)setAlignItems:(FLEXBOXAlignment)alignItems 179 | { 180 | _alignItems = alignItems; 181 | _node->style.align_items = (int)alignItems; 182 | } 183 | 184 | - (void)setAlignSelf:(FLEXBOXAlignment)alignSelf 185 | { 186 | _alignSelf = alignSelf; 187 | _node->style.align_self = (int)alignSelf; 188 | } 189 | 190 | - (void)setContentDirection:(FLEXBOXContentDirection)contentDirection 191 | { 192 | _contentDirection = contentDirection; 193 | _node->style.direction = (int)contentDirection; 194 | } 195 | 196 | @end 197 | 198 | -------------------------------------------------------------------------------- /FlexboxKit/FlexboxKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // FlexboxKit.h 3 | // FlexboxKit 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | #import 13 | #import 14 | 15 | //! Project version number for FlexboxKit. 16 | FOUNDATION_EXPORT double FlexboxKitVersionNumber; 17 | 18 | //! Project version string for FlexboxKit. 19 | FOUNDATION_EXPORT const unsigned char FlexboxKitVersionString[]; 20 | 21 | // In this header, you should import all the public headers of your framework using statements like #import 22 | 23 | 24 | -------------------------------------------------------------------------------- /FlexboxKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.flexbox.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /FlexboxKit/Layout.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "Layout.h" 16 | 17 | #ifdef _MSC_VER 18 | #include 19 | #define isnan _isnan 20 | 21 | /* define fmaxf if < VC12 */ 22 | #if _MSC_VER < 1800 23 | __forceinline const float fmaxf(const float a, const float b) { 24 | return (a > b) ? a : b; 25 | } 26 | #endif 27 | #endif 28 | 29 | bool isUndefined(float value) { 30 | return isnan(value); 31 | } 32 | 33 | static bool eq(float a, float b) { 34 | if (isUndefined(a)) { 35 | return isUndefined(b); 36 | } 37 | return fabs(a - b) < 0.0001; 38 | } 39 | 40 | void init_css_node(css_node_t *node) { 41 | node->style.align_items = CSS_ALIGN_STRETCH; 42 | node->style.align_content = CSS_ALIGN_FLEX_START; 43 | 44 | node->style.direction = CSS_DIRECTION_INHERIT; 45 | node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN; 46 | 47 | // Some of the fields default to undefined and not 0 48 | node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED; 49 | node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; 50 | 51 | node->style.minDimensions[CSS_WIDTH] = CSS_UNDEFINED; 52 | node->style.minDimensions[CSS_HEIGHT] = CSS_UNDEFINED; 53 | 54 | node->style.maxDimensions[CSS_WIDTH] = CSS_UNDEFINED; 55 | node->style.maxDimensions[CSS_HEIGHT] = CSS_UNDEFINED; 56 | 57 | node->style.position[CSS_LEFT] = CSS_UNDEFINED; 58 | node->style.position[CSS_TOP] = CSS_UNDEFINED; 59 | node->style.position[CSS_RIGHT] = CSS_UNDEFINED; 60 | node->style.position[CSS_BOTTOM] = CSS_UNDEFINED; 61 | 62 | node->style.margin[CSS_START] = CSS_UNDEFINED; 63 | node->style.margin[CSS_END] = CSS_UNDEFINED; 64 | node->style.padding[CSS_START] = CSS_UNDEFINED; 65 | node->style.padding[CSS_END] = CSS_UNDEFINED; 66 | node->style.border[CSS_START] = CSS_UNDEFINED; 67 | node->style.border[CSS_END] = CSS_UNDEFINED; 68 | 69 | node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; 70 | node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; 71 | 72 | // Such that the comparison is always going to be false 73 | node->layout.last_requested_dimensions[CSS_WIDTH] = -1; 74 | node->layout.last_requested_dimensions[CSS_HEIGHT] = -1; 75 | node->layout.last_parent_max_width = -1; 76 | node->layout.last_direction = (css_direction_t)-1; 77 | node->layout.should_update = true; 78 | } 79 | 80 | css_node_t *new_css_node() { 81 | css_node_t *node = (css_node_t *)calloc(1, sizeof(*node)); 82 | init_css_node(node); 83 | return node; 84 | } 85 | 86 | void free_css_node(css_node_t *node) { 87 | free(node); 88 | } 89 | 90 | static void indent(int n) { 91 | for (int i = 0; i < n; ++i) { 92 | printf(" "); 93 | } 94 | } 95 | 96 | static void print_number_0(const char *str, float number) { 97 | if (!eq(number, 0)) { 98 | printf("%s: %g, ", str, number); 99 | } 100 | } 101 | 102 | static void print_number_nan(const char *str, float number) { 103 | if (!isnan(number)) { 104 | printf("%s: %g, ", str, number); 105 | } 106 | } 107 | 108 | static bool four_equal(float four[4]) { 109 | return 110 | eq(four[0], four[1]) && 111 | eq(four[0], four[2]) && 112 | eq(four[0], four[3]); 113 | } 114 | 115 | 116 | static void print_css_node_rec( 117 | css_node_t *node, 118 | css_print_options_t options, 119 | int level 120 | ) { 121 | indent(level); 122 | printf("{"); 123 | 124 | if (node->print) { 125 | node->print(node->context); 126 | } 127 | 128 | if (options & CSS_PRINT_LAYOUT) { 129 | printf("layout: {"); 130 | printf("width: %g, ", node->layout.dimensions[CSS_WIDTH]); 131 | printf("height: %g, ", node->layout.dimensions[CSS_HEIGHT]); 132 | printf("top: %g, ", node->layout.position[CSS_TOP]); 133 | printf("left: %g", node->layout.position[CSS_LEFT]); 134 | printf("}, "); 135 | } 136 | 137 | if (options & CSS_PRINT_STYLE) { 138 | if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN) { 139 | printf("flexDirection: 'column', "); 140 | } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { 141 | printf("flexDirection: 'columnReverse', "); 142 | } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW) { 143 | printf("flexDirection: 'row', "); 144 | } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) { 145 | printf("flexDirection: 'rowReverse', "); 146 | } 147 | 148 | if (node->style.justify_content == CSS_JUSTIFY_CENTER) { 149 | printf("justifyContent: 'center', "); 150 | } else if (node->style.justify_content == CSS_JUSTIFY_FLEX_END) { 151 | printf("justifyContent: 'flex-end', "); 152 | } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_AROUND) { 153 | printf("justifyContent: 'space-around', "); 154 | } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_BETWEEN) { 155 | printf("justifyContent: 'space-between', "); 156 | } 157 | 158 | if (node->style.align_items == CSS_ALIGN_CENTER) { 159 | printf("alignItems: 'center', "); 160 | } else if (node->style.align_items == CSS_ALIGN_FLEX_END) { 161 | printf("alignItems: 'flex-end', "); 162 | } else if (node->style.align_items == CSS_ALIGN_STRETCH) { 163 | printf("alignItems: 'stretch', "); 164 | } 165 | 166 | if (node->style.align_content == CSS_ALIGN_CENTER) { 167 | printf("alignContent: 'center', "); 168 | } else if (node->style.align_content == CSS_ALIGN_FLEX_END) { 169 | printf("alignContent: 'flex-end', "); 170 | } else if (node->style.align_content == CSS_ALIGN_STRETCH) { 171 | printf("alignContent: 'stretch', "); 172 | } 173 | 174 | if (node->style.align_self == CSS_ALIGN_FLEX_START) { 175 | printf("alignSelf: 'flex-start', "); 176 | } else if (node->style.align_self == CSS_ALIGN_CENTER) { 177 | printf("alignSelf: 'center', "); 178 | } else if (node->style.align_self == CSS_ALIGN_FLEX_END) { 179 | printf("alignSelf: 'flex-end', "); 180 | } else if (node->style.align_self == CSS_ALIGN_STRETCH) { 181 | printf("alignSelf: 'stretch', "); 182 | } 183 | 184 | print_number_nan("flex", node->style.flex); 185 | 186 | if (four_equal(node->style.margin)) { 187 | print_number_0("margin", node->style.margin[CSS_LEFT]); 188 | } else { 189 | print_number_0("marginLeft", node->style.margin[CSS_LEFT]); 190 | print_number_0("marginRight", node->style.margin[CSS_RIGHT]); 191 | print_number_0("marginTop", node->style.margin[CSS_TOP]); 192 | print_number_0("marginBottom", node->style.margin[CSS_BOTTOM]); 193 | print_number_0("marginStart", node->style.margin[CSS_START]); 194 | print_number_0("marginEnd", node->style.margin[CSS_END]); 195 | } 196 | 197 | if (four_equal(node->style.padding)) { 198 | print_number_0("padding", node->style.margin[CSS_LEFT]); 199 | } else { 200 | print_number_0("paddingLeft", node->style.padding[CSS_LEFT]); 201 | print_number_0("paddingRight", node->style.padding[CSS_RIGHT]); 202 | print_number_0("paddingTop", node->style.padding[CSS_TOP]); 203 | print_number_0("paddingBottom", node->style.padding[CSS_BOTTOM]); 204 | print_number_0("paddingStart", node->style.padding[CSS_START]); 205 | print_number_0("paddingEnd", node->style.padding[CSS_END]); 206 | } 207 | 208 | if (four_equal(node->style.border)) { 209 | print_number_0("borderWidth", node->style.border[CSS_LEFT]); 210 | } else { 211 | print_number_0("borderLeftWidth", node->style.border[CSS_LEFT]); 212 | print_number_0("borderRightWidth", node->style.border[CSS_RIGHT]); 213 | print_number_0("borderTopWidth", node->style.border[CSS_TOP]); 214 | print_number_0("borderBottomWidth", node->style.border[CSS_BOTTOM]); 215 | print_number_0("borderStartWidth", node->style.border[CSS_START]); 216 | print_number_0("borderEndWidth", node->style.border[CSS_END]); 217 | } 218 | 219 | print_number_nan("width", node->style.dimensions[CSS_WIDTH]); 220 | print_number_nan("height", node->style.dimensions[CSS_HEIGHT]); 221 | 222 | if (node->style.position_type == CSS_POSITION_ABSOLUTE) { 223 | printf("position: 'absolute', "); 224 | } 225 | 226 | print_number_nan("left", node->style.position[CSS_LEFT]); 227 | print_number_nan("right", node->style.position[CSS_RIGHT]); 228 | print_number_nan("top", node->style.position[CSS_TOP]); 229 | print_number_nan("bottom", node->style.position[CSS_BOTTOM]); 230 | } 231 | 232 | if (options & CSS_PRINT_CHILDREN && node->children_count > 0) { 233 | printf("children: [\n"); 234 | for (int i = 0; i < node->children_count; ++i) { 235 | print_css_node_rec(node->get_child(node->context, i), options, level + 1); 236 | } 237 | indent(level); 238 | printf("]},\n"); 239 | } else { 240 | printf("},\n"); 241 | } 242 | } 243 | 244 | void print_css_node(css_node_t *node, css_print_options_t options) { 245 | print_css_node_rec(node, options, 0); 246 | } 247 | 248 | 249 | static css_position_t leading[4] = { 250 | /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP, 251 | /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM, 252 | /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT, 253 | /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT 254 | }; 255 | static css_position_t trailing[4] = { 256 | /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_BOTTOM, 257 | /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_TOP, 258 | /* CSS_FLEX_DIRECTION_ROW = */ CSS_RIGHT, 259 | /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_LEFT 260 | }; 261 | static css_position_t pos[4] = { 262 | /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP, 263 | /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM, 264 | /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT, 265 | /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT 266 | }; 267 | static css_dimension_t dim[4] = { 268 | /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_HEIGHT, 269 | /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_HEIGHT, 270 | /* CSS_FLEX_DIRECTION_ROW = */ CSS_WIDTH, 271 | /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH 272 | }; 273 | 274 | static bool isRowDirection(css_flex_direction_t flex_direction) { 275 | return flex_direction == CSS_FLEX_DIRECTION_ROW || 276 | flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE; 277 | } 278 | 279 | static bool isColumnDirection(css_flex_direction_t flex_direction) { 280 | return flex_direction == CSS_FLEX_DIRECTION_COLUMN || 281 | flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE; 282 | } 283 | 284 | static float getLeadingMargin(css_node_t *node, css_flex_direction_t axis) { 285 | if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_START])) { 286 | return node->style.margin[CSS_START]; 287 | } 288 | 289 | return node->style.margin[leading[axis]]; 290 | } 291 | 292 | static float getTrailingMargin(css_node_t *node, css_flex_direction_t axis) { 293 | if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_END])) { 294 | return node->style.margin[CSS_END]; 295 | } 296 | 297 | return node->style.margin[trailing[axis]]; 298 | } 299 | 300 | static float getLeadingPadding(css_node_t *node, css_flex_direction_t axis) { 301 | if (isRowDirection(axis) && 302 | !isUndefined(node->style.padding[CSS_START]) && 303 | node->style.padding[CSS_START] >= 0) { 304 | return node->style.padding[CSS_START]; 305 | } 306 | 307 | if (node->style.padding[leading[axis]] >= 0) { 308 | return node->style.padding[leading[axis]]; 309 | } 310 | 311 | return 0; 312 | } 313 | 314 | static float getTrailingPadding(css_node_t *node, css_flex_direction_t axis) { 315 | if (isRowDirection(axis) && 316 | !isUndefined(node->style.padding[CSS_END]) && 317 | node->style.padding[CSS_END] >= 0) { 318 | return node->style.padding[CSS_END]; 319 | } 320 | 321 | if (node->style.padding[trailing[axis]] >= 0) { 322 | return node->style.padding[trailing[axis]]; 323 | } 324 | 325 | return 0; 326 | } 327 | 328 | static float getLeadingBorder(css_node_t *node, css_flex_direction_t axis) { 329 | if (isRowDirection(axis) && 330 | !isUndefined(node->style.border[CSS_START]) && 331 | node->style.border[CSS_START] >= 0) { 332 | return node->style.border[CSS_START]; 333 | } 334 | 335 | if (node->style.border[leading[axis]] >= 0) { 336 | return node->style.border[leading[axis]]; 337 | } 338 | 339 | return 0; 340 | } 341 | 342 | static float getTrailingBorder(css_node_t *node, css_flex_direction_t axis) { 343 | if (isRowDirection(axis) && 344 | !isUndefined(node->style.border[CSS_END]) && 345 | node->style.border[CSS_END] >= 0) { 346 | return node->style.border[CSS_END]; 347 | } 348 | 349 | if (node->style.border[trailing[axis]] >= 0) { 350 | return node->style.border[trailing[axis]]; 351 | } 352 | 353 | return 0; 354 | } 355 | 356 | static float getLeadingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { 357 | return getLeadingPadding(node, axis) + getLeadingBorder(node, axis); 358 | } 359 | 360 | static float getTrailingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { 361 | return getTrailingPadding(node, axis) + getTrailingBorder(node, axis); 362 | } 363 | 364 | static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) { 365 | return getLeadingBorder(node, axis) + getTrailingBorder(node, axis); 366 | } 367 | 368 | static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) { 369 | return getLeadingMargin(node, axis) + getTrailingMargin(node, axis); 370 | } 371 | 372 | static float getPaddingAndBorderAxis(css_node_t *node, css_flex_direction_t axis) { 373 | return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis); 374 | } 375 | 376 | static css_position_type_t getPositionType(css_node_t *node) { 377 | return node->style.position_type; 378 | } 379 | 380 | static css_justify_t getJustifyContent(css_node_t *node) { 381 | return node->style.justify_content; 382 | } 383 | 384 | static css_align_t getAlignContent(css_node_t *node) { 385 | return node->style.align_content; 386 | } 387 | 388 | static css_align_t getAlignItem(css_node_t *node, css_node_t *child) { 389 | if (child->style.align_self != CSS_ALIGN_AUTO) { 390 | return child->style.align_self; 391 | } 392 | return node->style.align_items; 393 | } 394 | 395 | static css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) { 396 | css_direction_t direction = node->style.direction; 397 | 398 | if (direction == CSS_DIRECTION_INHERIT) { 399 | direction = parentDirection > CSS_DIRECTION_INHERIT ? parentDirection : CSS_DIRECTION_LTR; 400 | } 401 | 402 | return direction; 403 | } 404 | 405 | static css_flex_direction_t getFlexDirection(css_node_t *node) { 406 | return node->style.flex_direction; 407 | } 408 | 409 | static css_flex_direction_t resolveAxis(css_flex_direction_t flex_direction, css_direction_t direction) { 410 | if (direction == CSS_DIRECTION_RTL) { 411 | if (flex_direction == CSS_FLEX_DIRECTION_ROW) { 412 | return CSS_FLEX_DIRECTION_ROW_REVERSE; 413 | } else if (flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) { 414 | return CSS_FLEX_DIRECTION_ROW; 415 | } 416 | } 417 | 418 | return flex_direction; 419 | } 420 | 421 | static css_flex_direction_t getCrossFlexDirection(css_flex_direction_t flex_direction, css_direction_t direction) { 422 | if (isColumnDirection(flex_direction)) { 423 | return resolveAxis(CSS_FLEX_DIRECTION_ROW, direction); 424 | } else { 425 | return CSS_FLEX_DIRECTION_COLUMN; 426 | } 427 | } 428 | 429 | static float getFlex(css_node_t *node) { 430 | return node->style.flex; 431 | } 432 | 433 | static bool isFlex(css_node_t *node) { 434 | return ( 435 | getPositionType(node) == CSS_POSITION_RELATIVE && 436 | getFlex(node) > 0 437 | ); 438 | } 439 | 440 | static bool isFlexWrap(css_node_t *node) { 441 | return node->style.flex_wrap == CSS_WRAP; 442 | } 443 | 444 | static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) { 445 | return node->layout.dimensions[dim[axis]] + 446 | getLeadingMargin(node, axis) + 447 | getTrailingMargin(node, axis); 448 | } 449 | 450 | static bool isDimDefined(css_node_t *node, css_flex_direction_t axis) { 451 | float value = node->style.dimensions[dim[axis]]; 452 | return !isUndefined(value) && value > 0.0; 453 | } 454 | 455 | static bool isPosDefined(css_node_t *node, css_position_t position) { 456 | return !isUndefined(node->style.position[position]); 457 | } 458 | 459 | static bool isMeasureDefined(css_node_t *node) { 460 | return node->measure; 461 | } 462 | 463 | static float getPosition(css_node_t *node, css_position_t position) { 464 | float result = node->style.position[position]; 465 | if (!isUndefined(result)) { 466 | return result; 467 | } 468 | return 0; 469 | } 470 | 471 | static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) { 472 | float min = CSS_UNDEFINED; 473 | float max = CSS_UNDEFINED; 474 | 475 | if (isColumnDirection(axis)) { 476 | min = node->style.minDimensions[CSS_HEIGHT]; 477 | max = node->style.maxDimensions[CSS_HEIGHT]; 478 | } else if (isRowDirection(axis)) { 479 | min = node->style.minDimensions[CSS_WIDTH]; 480 | max = node->style.maxDimensions[CSS_WIDTH]; 481 | } 482 | 483 | float boundValue = value; 484 | 485 | if (!isUndefined(max) && max >= 0.0 && boundValue > max) { 486 | boundValue = max; 487 | } 488 | if (!isUndefined(min) && min >= 0.0 && boundValue < min) { 489 | boundValue = min; 490 | } 491 | 492 | return boundValue; 493 | } 494 | 495 | // When the user specifically sets a value for width or height 496 | static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) { 497 | // The parent already computed us a width or height. We just skip it 498 | if (!isUndefined(node->layout.dimensions[dim[axis]])) { 499 | return; 500 | } 501 | // We only run if there's a width or height defined 502 | if (!isDimDefined(node, axis)) { 503 | return; 504 | } 505 | 506 | // The dimensions can never be smaller than the padding and border 507 | node->layout.dimensions[dim[axis]] = fmaxf( 508 | boundAxis(node, axis, node->style.dimensions[dim[axis]]), 509 | getPaddingAndBorderAxis(node, axis) 510 | ); 511 | } 512 | 513 | static void setTrailingPosition(css_node_t *node, css_node_t *child, css_flex_direction_t axis) { 514 | child->layout.position[trailing[axis]] = node->layout.dimensions[dim[axis]] - 515 | child->layout.dimensions[dim[axis]] - child->layout.position[pos[axis]]; 516 | } 517 | 518 | // If both left and right are defined, then use left. Otherwise return 519 | // +left or -right depending on which is defined. 520 | static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) { 521 | float lead = node->style.position[leading[axis]]; 522 | if (!isUndefined(lead)) { 523 | return lead; 524 | } 525 | return -getPosition(node, trailing[axis]); 526 | } 527 | 528 | static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) { 529 | /** START_GENERATED **/ 530 | css_direction_t direction = resolveDirection(node, parentDirection); 531 | css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction); 532 | css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction); 533 | css_flex_direction_t resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction); 534 | 535 | // Handle width and height style attributes 536 | setDimensionFromStyle(node, mainAxis); 537 | setDimensionFromStyle(node, crossAxis); 538 | 539 | // Set the resolved resolution in the node's layout 540 | node->layout.direction = direction; 541 | 542 | // The position is set by the parent, but we need to complete it with a 543 | // delta composed of the margin and left/top/right/bottom 544 | node->layout.position[leading[mainAxis]] += getLeadingMargin(node, mainAxis) + 545 | getRelativePosition(node, mainAxis); 546 | node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) + 547 | getRelativePosition(node, mainAxis); 548 | node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) + 549 | getRelativePosition(node, crossAxis); 550 | node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) + 551 | getRelativePosition(node, crossAxis); 552 | 553 | if (isMeasureDefined(node)) { 554 | float width = CSS_UNDEFINED; 555 | if (isDimDefined(node, resolvedRowAxis)) { 556 | width = node->style.dimensions[CSS_WIDTH]; 557 | } else if (!isUndefined(node->layout.dimensions[dim[resolvedRowAxis]])) { 558 | width = node->layout.dimensions[dim[resolvedRowAxis]]; 559 | } else { 560 | width = parentMaxWidth - 561 | getMarginAxis(node, resolvedRowAxis); 562 | } 563 | width -= getPaddingAndBorderAxis(node, resolvedRowAxis); 564 | 565 | // We only need to give a dimension for the text if we haven't got any 566 | // for it computed yet. It can either be from the style attribute or because 567 | // the element is flexible. 568 | bool isRowUndefined = !isDimDefined(node, resolvedRowAxis) && 569 | isUndefined(node->layout.dimensions[dim[resolvedRowAxis]]); 570 | bool isColumnUndefined = !isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) && 571 | isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]); 572 | 573 | // Let's not measure the text if we already know both dimensions 574 | if (isRowUndefined || isColumnUndefined) { 575 | css_dim_t measureDim = node->measure( 576 | node->context, 577 | 578 | width 579 | ); 580 | if (isRowUndefined) { 581 | node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] + 582 | getPaddingAndBorderAxis(node, resolvedRowAxis); 583 | } 584 | if (isColumnUndefined) { 585 | node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] + 586 | getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN); 587 | } 588 | } 589 | if (node->children_count == 0) { 590 | return; 591 | } 592 | } 593 | 594 | int i; 595 | int ii; 596 | css_node_t* child; 597 | css_flex_direction_t axis; 598 | 599 | // Pre-fill some dimensions straight from the parent 600 | for (i = 0; i < node->children_count; ++i) { 601 | child = node->get_child(node->context, i); 602 | // Pre-fill cross axis dimensions when the child is using stretch before 603 | // we call the recursive layout pass 604 | if (getAlignItem(node, child) == CSS_ALIGN_STRETCH && 605 | getPositionType(child) == CSS_POSITION_RELATIVE && 606 | !isUndefined(node->layout.dimensions[dim[crossAxis]]) && 607 | !isDimDefined(child, crossAxis)) { 608 | child->layout.dimensions[dim[crossAxis]] = fmaxf( 609 | boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] - 610 | getPaddingAndBorderAxis(node, crossAxis) - 611 | getMarginAxis(child, crossAxis)), 612 | // You never want to go smaller than padding 613 | getPaddingAndBorderAxis(child, crossAxis) 614 | ); 615 | } else if (getPositionType(child) == CSS_POSITION_ABSOLUTE) { 616 | // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both 617 | // left and right or top and bottom). 618 | for (ii = 0; ii < 2; ii++) { 619 | axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; 620 | if (!isUndefined(node->layout.dimensions[dim[axis]]) && 621 | !isDimDefined(child, axis) && 622 | isPosDefined(child, leading[axis]) && 623 | isPosDefined(child, trailing[axis])) { 624 | child->layout.dimensions[dim[axis]] = fmaxf( 625 | boundAxis(child, axis, node->layout.dimensions[dim[axis]] - 626 | getPaddingAndBorderAxis(node, axis) - 627 | getMarginAxis(child, axis) - 628 | getPosition(child, leading[axis]) - 629 | getPosition(child, trailing[axis])), 630 | // You never want to go smaller than padding 631 | getPaddingAndBorderAxis(child, axis) 632 | ); 633 | } 634 | } 635 | } 636 | } 637 | 638 | float definedMainDim = CSS_UNDEFINED; 639 | if (!isUndefined(node->layout.dimensions[dim[mainAxis]])) { 640 | definedMainDim = node->layout.dimensions[dim[mainAxis]] - 641 | getPaddingAndBorderAxis(node, mainAxis); 642 | } 643 | 644 | // We want to execute the next two loops one per line with flex-wrap 645 | int startLine = 0; 646 | int endLine = 0; 647 | // int nextOffset = 0; 648 | int alreadyComputedNextLayout = 0; 649 | // We aggregate the total dimensions of the container in those two variables 650 | float linesCrossDim = 0; 651 | float linesMainDim = 0; 652 | int linesCount = 0; 653 | while (endLine < node->children_count) { 654 | // Layout non flexible children and count children by type 655 | 656 | // mainContentDim is accumulation of the dimensions and margin of all the 657 | // non flexible children. This will be used in order to either set the 658 | // dimensions of the node if none already exist, or to compute the 659 | // remaining space left for the flexible children. 660 | float mainContentDim = 0; 661 | 662 | // There are three kind of children, non flexible, flexible and absolute. 663 | // We need to know how many there are in order to distribute the space. 664 | int flexibleChildrenCount = 0; 665 | float totalFlexible = 0; 666 | int nonFlexibleChildrenCount = 0; 667 | 668 | float maxWidth; 669 | for (i = startLine; i < node->children_count; ++i) { 670 | child = node->get_child(node->context, i); 671 | float nextContentDim = 0; 672 | 673 | // It only makes sense to consider a child flexible if we have a computed 674 | // dimension for the node-> 675 | if (!isUndefined(node->layout.dimensions[dim[mainAxis]]) && isFlex(child)) { 676 | flexibleChildrenCount++; 677 | totalFlexible += getFlex(child); 678 | 679 | // Even if we don't know its exact size yet, we already know the padding, 680 | // border and margin. We'll use this partial information, which represents 681 | // the smallest possible size for the child, to compute the remaining 682 | // available space. 683 | nextContentDim = getPaddingAndBorderAxis(child, mainAxis) + 684 | getMarginAxis(child, mainAxis); 685 | 686 | } else { 687 | maxWidth = CSS_UNDEFINED; 688 | if (!isRowDirection(mainAxis)) { 689 | maxWidth = parentMaxWidth - 690 | getMarginAxis(node, resolvedRowAxis) - 691 | getPaddingAndBorderAxis(node, resolvedRowAxis); 692 | 693 | if (isDimDefined(node, resolvedRowAxis)) { 694 | maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - 695 | getPaddingAndBorderAxis(node, resolvedRowAxis); 696 | } 697 | } 698 | 699 | // This is the main recursive call. We layout non flexible children. 700 | if (alreadyComputedNextLayout == 0) { 701 | layoutNode(child, maxWidth, direction); 702 | } 703 | 704 | // Absolute positioned elements do not take part of the layout, so we 705 | // don't use them to compute mainContentDim 706 | if (getPositionType(child) == CSS_POSITION_RELATIVE) { 707 | nonFlexibleChildrenCount++; 708 | // At this point we know the final size and margin of the element. 709 | nextContentDim = getDimWithMargin(child, mainAxis); 710 | } 711 | } 712 | 713 | // The element we are about to add would make us go to the next line 714 | if (isFlexWrap(node) && 715 | !isUndefined(node->layout.dimensions[dim[mainAxis]]) && 716 | mainContentDim + nextContentDim > definedMainDim && 717 | // If there's only one element, then it's bigger than the content 718 | // and needs its own line 719 | i != startLine) { 720 | nonFlexibleChildrenCount--; 721 | alreadyComputedNextLayout = 1; 722 | break; 723 | } 724 | alreadyComputedNextLayout = 0; 725 | mainContentDim += nextContentDim; 726 | endLine = i + 1; 727 | } 728 | 729 | // Layout flexible children and allocate empty space 730 | 731 | // In order to position the elements in the main axis, we have two 732 | // controls. The space between the beginning and the first element 733 | // and the space between each two elements. 734 | float leadingMainDim = 0; 735 | float betweenMainDim = 0; 736 | 737 | // The remaining available space that needs to be allocated 738 | float remainingMainDim = 0; 739 | if (!isUndefined(node->layout.dimensions[dim[mainAxis]])) { 740 | remainingMainDim = definedMainDim - mainContentDim; 741 | } else { 742 | remainingMainDim = fmaxf(mainContentDim, 0) - mainContentDim; 743 | } 744 | 745 | // If there are flexible children in the mix, they are going to fill the 746 | // remaining space 747 | if (flexibleChildrenCount != 0) { 748 | float flexibleMainDim = remainingMainDim / totalFlexible; 749 | float baseMainDim; 750 | float boundMainDim; 751 | 752 | // Iterate over every child in the axis. If the flex share of remaining 753 | // space doesn't meet min/max bounds, remove this child from flex 754 | // calculations. 755 | for (i = startLine; i < endLine; ++i) { 756 | child = node->get_child(node->context, i); 757 | if (isFlex(child)) { 758 | baseMainDim = flexibleMainDim * getFlex(child) + 759 | getPaddingAndBorderAxis(child, mainAxis); 760 | boundMainDim = boundAxis(child, mainAxis, baseMainDim); 761 | 762 | if (baseMainDim != boundMainDim) { 763 | remainingMainDim -= boundMainDim; 764 | totalFlexible -= getFlex(child); 765 | } 766 | } 767 | } 768 | flexibleMainDim = remainingMainDim / totalFlexible; 769 | 770 | // The non flexible children can overflow the container, in this case 771 | // we should just assume that there is no space available. 772 | if (flexibleMainDim < 0) { 773 | flexibleMainDim = 0; 774 | } 775 | // We iterate over the full array and only apply the action on flexible 776 | // children. This is faster than actually allocating a new array that 777 | // contains only flexible children. 778 | for (i = startLine; i < endLine; ++i) { 779 | child = node->get_child(node->context, i); 780 | if (isFlex(child)) { 781 | // At this point we know the final size of the element in the main 782 | // dimension 783 | child->layout.dimensions[dim[mainAxis]] = boundAxis(child, mainAxis, 784 | flexibleMainDim * getFlex(child) + getPaddingAndBorderAxis(child, mainAxis) 785 | ); 786 | 787 | maxWidth = CSS_UNDEFINED; 788 | if (isDimDefined(node, resolvedRowAxis)) { 789 | maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - 790 | getPaddingAndBorderAxis(node, resolvedRowAxis); 791 | } else if (!isRowDirection(mainAxis)) { 792 | maxWidth = parentMaxWidth - 793 | getMarginAxis(node, resolvedRowAxis) - 794 | getPaddingAndBorderAxis(node, resolvedRowAxis); 795 | } 796 | 797 | // And we recursively call the layout algorithm for this child 798 | layoutNode(child, maxWidth, direction); 799 | } 800 | } 801 | 802 | // We use justifyContent to figure out how to allocate the remaining 803 | // space available 804 | } else { 805 | css_justify_t justifyContent = getJustifyContent(node); 806 | if (justifyContent == CSS_JUSTIFY_CENTER) { 807 | leadingMainDim = remainingMainDim / 2; 808 | } else if (justifyContent == CSS_JUSTIFY_FLEX_END) { 809 | leadingMainDim = remainingMainDim; 810 | } else if (justifyContent == CSS_JUSTIFY_SPACE_BETWEEN) { 811 | remainingMainDim = fmaxf(remainingMainDim, 0); 812 | if (flexibleChildrenCount + nonFlexibleChildrenCount - 1 != 0) { 813 | betweenMainDim = remainingMainDim / 814 | (flexibleChildrenCount + nonFlexibleChildrenCount - 1); 815 | } else { 816 | betweenMainDim = 0; 817 | } 818 | } else if (justifyContent == CSS_JUSTIFY_SPACE_AROUND) { 819 | // Space on the edges is half of the space between elements 820 | betweenMainDim = remainingMainDim / 821 | (flexibleChildrenCount + nonFlexibleChildrenCount); 822 | leadingMainDim = betweenMainDim / 2; 823 | } 824 | } 825 | 826 | // Position elements in the main axis and compute dimensions 827 | 828 | // At this point, all the children have their dimensions set. We need to 829 | // find their position. In order to do that, we accumulate data in 830 | // variables that are also useful to compute the total dimensions of the 831 | // container! 832 | float crossDim = 0; 833 | float mainDim = leadingMainDim + 834 | getLeadingPaddingAndBorder(node, mainAxis); 835 | 836 | for (i = startLine; i < endLine; ++i) { 837 | child = node->get_child(node->context, i); 838 | child->line_index = linesCount; 839 | 840 | if (getPositionType(child) == CSS_POSITION_ABSOLUTE && 841 | isPosDefined(child, leading[mainAxis])) { 842 | // In case the child is position absolute and has left/top being 843 | // defined, we override the position to whatever the user said 844 | // (and margin/border). 845 | child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) + 846 | getLeadingBorder(node, mainAxis) + 847 | getLeadingMargin(child, mainAxis); 848 | } else { 849 | // If the child is position absolute (without top/left) or relative, 850 | // we put it at the current accumulated offset. 851 | child->layout.position[pos[mainAxis]] += mainDim; 852 | 853 | // Define the trailing position accordingly. 854 | if (!isUndefined(node->layout.dimensions[dim[mainAxis]])) { 855 | setTrailingPosition(node, child, mainAxis); 856 | } 857 | } 858 | 859 | // Now that we placed the element, we need to update the variables 860 | // We only need to do that for relative elements. Absolute elements 861 | // do not take part in that phase. 862 | if (getPositionType(child) == CSS_POSITION_RELATIVE) { 863 | // The main dimension is the sum of all the elements dimension plus 864 | // the spacing. 865 | mainDim += betweenMainDim + getDimWithMargin(child, mainAxis); 866 | // The cross dimension is the max of the elements dimension since there 867 | // can only be one element in that cross dimension. 868 | crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis))); 869 | } 870 | } 871 | 872 | float containerCrossAxis = node->layout.dimensions[dim[crossAxis]]; 873 | if (isUndefined(node->layout.dimensions[dim[crossAxis]])) { 874 | containerCrossAxis = fmaxf( 875 | // For the cross dim, we add both sides at the end because the value 876 | // is aggregate via a max function. Intermediate negative values 877 | // can mess this computation otherwise 878 | boundAxis(node, crossAxis, crossDim + getPaddingAndBorderAxis(node, crossAxis)), 879 | getPaddingAndBorderAxis(node, crossAxis) 880 | ); 881 | } 882 | 883 | // Position elements in the cross axis 884 | for (i = startLine; i < endLine; ++i) { 885 | child = node->get_child(node->context, i); 886 | 887 | if (getPositionType(child) == CSS_POSITION_ABSOLUTE && 888 | isPosDefined(child, leading[crossAxis])) { 889 | // In case the child is absolutely positionned and has a 890 | // top/left/bottom/right being set, we override all the previously 891 | // computed positions to set it correctly. 892 | child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) + 893 | getLeadingBorder(node, crossAxis) + 894 | getLeadingMargin(child, crossAxis); 895 | 896 | } else { 897 | float leadingCrossDim = getLeadingPaddingAndBorder(node, crossAxis); 898 | 899 | // For a relative children, we're either using alignItems (parent) or 900 | // alignSelf (child) in order to determine the position in the cross axis 901 | if (getPositionType(child) == CSS_POSITION_RELATIVE) { 902 | css_align_t alignItem = getAlignItem(node, child); 903 | if (alignItem == CSS_ALIGN_STRETCH) { 904 | // You can only stretch if the dimension has not already been set 905 | // previously. 906 | if (!isDimDefined(child, crossAxis)) { 907 | child->layout.dimensions[dim[crossAxis]] = fmaxf( 908 | boundAxis(child, crossAxis, containerCrossAxis - 909 | getPaddingAndBorderAxis(node, crossAxis) - 910 | getMarginAxis(child, crossAxis)), 911 | // You never want to go smaller than padding 912 | getPaddingAndBorderAxis(child, crossAxis) 913 | ); 914 | } 915 | } else if (alignItem != CSS_ALIGN_FLEX_START) { 916 | // The remaining space between the parent dimensions+padding and child 917 | // dimensions+margin. 918 | float remainingCrossDim = containerCrossAxis - 919 | getPaddingAndBorderAxis(node, crossAxis) - 920 | getDimWithMargin(child, crossAxis); 921 | 922 | if (alignItem == CSS_ALIGN_CENTER) { 923 | leadingCrossDim += remainingCrossDim / 2; 924 | } else { // CSS_ALIGN_FLEX_END 925 | leadingCrossDim += remainingCrossDim; 926 | } 927 | } 928 | } 929 | 930 | // And we apply the position 931 | child->layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim; 932 | 933 | // Define the trailing position accordingly. 934 | if (!isUndefined(node->layout.dimensions[dim[crossAxis]])) { 935 | setTrailingPosition(node, child, crossAxis); 936 | } 937 | } 938 | } 939 | 940 | linesCrossDim += crossDim; 941 | linesMainDim = fmaxf(linesMainDim, mainDim); 942 | linesCount += 1; 943 | startLine = endLine; 944 | } 945 | 946 | // 947 | // 948 | // Note(prenaux): More than one line, we need to layout the crossAxis 949 | // according to alignContent. 950 | // 951 | // Note that we could probably remove and handle the one line case 952 | // here too, but for the moment this is safer since it won't interfere with 953 | // previously working code. 954 | // 955 | // See specs: 956 | // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm 957 | // section 9.4 958 | // 959 | if (linesCount > 1 && 960 | !isUndefined(node->layout.dimensions[dim[crossAxis]])) { 961 | float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] - 962 | getPaddingAndBorderAxis(node, crossAxis); 963 | float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim; 964 | 965 | float crossDimLead = 0; 966 | float currentLead = getLeadingPaddingAndBorder(node, crossAxis); 967 | 968 | css_align_t alignContent = getAlignContent(node); 969 | if (alignContent == CSS_ALIGN_FLEX_END) { 970 | currentLead += remainingAlignContentDim; 971 | } else if (alignContent == CSS_ALIGN_CENTER) { 972 | currentLead += remainingAlignContentDim / 2; 973 | } else if (alignContent == CSS_ALIGN_STRETCH) { 974 | if (nodeCrossAxisInnerSize > linesCrossDim) { 975 | crossDimLead = (remainingAlignContentDim / linesCount); 976 | } 977 | } 978 | 979 | int endIndex = 0; 980 | for (i = 0; i < linesCount; ++i) { 981 | int startIndex = endIndex; 982 | 983 | // compute the line's height and find the endIndex 984 | float lineHeight = 0; 985 | for (ii = startIndex; ii < node->children_count; ++ii) { 986 | child = node->get_child(node->context, ii); 987 | if (getPositionType(child) != CSS_POSITION_RELATIVE) { 988 | continue; 989 | } 990 | if (child->line_index != i) { 991 | break; 992 | } 993 | if (!isUndefined(child->layout.dimensions[dim[crossAxis]])) { 994 | lineHeight = fmaxf( 995 | lineHeight, 996 | child->layout.dimensions[dim[crossAxis]] + getMarginAxis(child, crossAxis) 997 | ); 998 | } 999 | } 1000 | endIndex = ii; 1001 | lineHeight += crossDimLead; 1002 | 1003 | for (ii = startIndex; ii < endIndex; ++ii) { 1004 | child = node->get_child(node->context, ii); 1005 | if (getPositionType(child) != CSS_POSITION_RELATIVE) { 1006 | continue; 1007 | } 1008 | 1009 | css_align_t alignContentAlignItem = getAlignItem(node, child); 1010 | if (alignContentAlignItem == CSS_ALIGN_FLEX_START) { 1011 | child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis); 1012 | } else if (alignContentAlignItem == CSS_ALIGN_FLEX_END) { 1013 | child->layout.position[pos[crossAxis]] = currentLead + lineHeight - getTrailingMargin(child, crossAxis) - child->layout.dimensions[dim[crossAxis]]; 1014 | } else if (alignContentAlignItem == CSS_ALIGN_CENTER) { 1015 | float childHeight = child->layout.dimensions[dim[crossAxis]]; 1016 | child->layout.position[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2; 1017 | } else if (alignContentAlignItem == CSS_ALIGN_STRETCH) { 1018 | child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis); 1019 | // TODO(prenaux): Correctly set the height of items with undefined 1020 | // (auto) crossAxis dimension. 1021 | } 1022 | } 1023 | 1024 | currentLead += lineHeight; 1025 | } 1026 | } 1027 | 1028 | bool needsMainTrailingPos = false; 1029 | bool needsCrossTrailingPos = false; 1030 | 1031 | // If the user didn't specify a width or height, and it has not been set 1032 | // by the container, then we set it via the children. 1033 | if (isUndefined(node->layout.dimensions[dim[mainAxis]])) { 1034 | node->layout.dimensions[dim[mainAxis]] = fmaxf( 1035 | // We're missing the last padding at this point to get the final 1036 | // dimension 1037 | boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)), 1038 | // We can never assign a width smaller than the padding and borders 1039 | getPaddingAndBorderAxis(node, mainAxis) 1040 | ); 1041 | 1042 | needsMainTrailingPos = true; 1043 | } 1044 | 1045 | if (isUndefined(node->layout.dimensions[dim[crossAxis]])) { 1046 | node->layout.dimensions[dim[crossAxis]] = fmaxf( 1047 | // For the cross dim, we add both sides at the end because the value 1048 | // is aggregate via a max function. Intermediate negative values 1049 | // can mess this computation otherwise 1050 | boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)), 1051 | getPaddingAndBorderAxis(node, crossAxis) 1052 | ); 1053 | 1054 | needsCrossTrailingPos = true; 1055 | } 1056 | 1057 | // Set trailing position if necessary 1058 | if (needsMainTrailingPos || needsCrossTrailingPos) { 1059 | for (i = 0; i < node->children_count; ++i) { 1060 | child = node->get_child(node->context, i); 1061 | 1062 | if (needsMainTrailingPos) { 1063 | setTrailingPosition(node, child, mainAxis); 1064 | } 1065 | 1066 | if (needsCrossTrailingPos) { 1067 | setTrailingPosition(node, child, crossAxis); 1068 | } 1069 | } 1070 | } 1071 | 1072 | // Calculate dimensions for absolutely positioned elements 1073 | for (i = 0; i < node->children_count; ++i) { 1074 | child = node->get_child(node->context, i); 1075 | if (getPositionType(child) == CSS_POSITION_ABSOLUTE) { 1076 | // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both 1077 | // left and right or top and bottom). 1078 | for (ii = 0; ii < 2; ii++) { 1079 | axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; 1080 | if (!isUndefined(node->layout.dimensions[dim[axis]]) && 1081 | !isDimDefined(child, axis) && 1082 | isPosDefined(child, leading[axis]) && 1083 | isPosDefined(child, trailing[axis])) { 1084 | child->layout.dimensions[dim[axis]] = fmaxf( 1085 | boundAxis(child, axis, node->layout.dimensions[dim[axis]] - 1086 | getBorderAxis(node, axis) - 1087 | getMarginAxis(child, axis) - 1088 | getPosition(child, leading[axis]) - 1089 | getPosition(child, trailing[axis]) 1090 | ), 1091 | // You never want to go smaller than padding 1092 | getPaddingAndBorderAxis(child, axis) 1093 | ); 1094 | } 1095 | } 1096 | for (ii = 0; ii < 2; ii++) { 1097 | axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; 1098 | if (isPosDefined(child, trailing[axis]) && 1099 | !isPosDefined(child, leading[axis])) { 1100 | child->layout.position[leading[axis]] = 1101 | node->layout.dimensions[dim[axis]] - 1102 | child->layout.dimensions[dim[axis]] - 1103 | getPosition(child, trailing[axis]); 1104 | } 1105 | } 1106 | } 1107 | } 1108 | /** END_GENERATED **/ 1109 | } 1110 | 1111 | void layoutNode(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) { 1112 | css_layout_t *layout = &node->layout; 1113 | css_direction_t direction = node->style.direction; 1114 | layout->should_update = true; 1115 | 1116 | bool skipLayout = 1117 | !node->is_dirty(node->context) && 1118 | eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) && 1119 | eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) && 1120 | eq(layout->last_parent_max_width, parentMaxWidth); 1121 | eq(layout->last_direction, direction); 1122 | 1123 | if (skipLayout) { 1124 | layout->dimensions[CSS_WIDTH] = layout->last_dimensions[CSS_WIDTH]; 1125 | layout->dimensions[CSS_HEIGHT] = layout->last_dimensions[CSS_HEIGHT]; 1126 | layout->position[CSS_TOP] = layout->last_position[CSS_TOP]; 1127 | layout->position[CSS_LEFT] = layout->last_position[CSS_LEFT]; 1128 | } else { 1129 | layout->last_requested_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; 1130 | layout->last_requested_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT]; 1131 | layout->last_parent_max_width = parentMaxWidth; 1132 | layout->last_direction = direction; 1133 | 1134 | layoutNodeImpl(node, parentMaxWidth, parentDirection); 1135 | 1136 | layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; 1137 | layout->last_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT]; 1138 | layout->last_position[CSS_TOP] = layout->position[CSS_TOP]; 1139 | layout->last_position[CSS_LEFT] = layout->position[CSS_LEFT]; 1140 | } 1141 | } 1142 | -------------------------------------------------------------------------------- /FlexboxKit/Layout.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #ifndef __LAYOUT_H 11 | #define __LAYOUT_H 12 | 13 | #include 14 | #ifndef __cplusplus 15 | #include 16 | #endif 17 | 18 | // Not defined in MSVC++ 19 | #ifndef NAN 20 | static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff}; 21 | #define NAN (*(const float *)__nan) 22 | #endif 23 | 24 | #define CSS_UNDEFINED NAN 25 | 26 | typedef enum { 27 | CSS_DIRECTION_INHERIT = 0, 28 | CSS_DIRECTION_LTR, 29 | CSS_DIRECTION_RTL 30 | } css_direction_t; 31 | 32 | typedef enum { 33 | CSS_FLEX_DIRECTION_COLUMN = 0, 34 | CSS_FLEX_DIRECTION_COLUMN_REVERSE, 35 | CSS_FLEX_DIRECTION_ROW, 36 | CSS_FLEX_DIRECTION_ROW_REVERSE 37 | } css_flex_direction_t; 38 | 39 | typedef enum { 40 | CSS_JUSTIFY_FLEX_START = 0, 41 | CSS_JUSTIFY_CENTER, 42 | CSS_JUSTIFY_FLEX_END, 43 | CSS_JUSTIFY_SPACE_BETWEEN, 44 | CSS_JUSTIFY_SPACE_AROUND 45 | } css_justify_t; 46 | 47 | // Note: auto is only a valid value for alignSelf. It is NOT a valid value for 48 | // alignItems. 49 | typedef enum { 50 | CSS_ALIGN_AUTO = 0, 51 | CSS_ALIGN_FLEX_START, 52 | CSS_ALIGN_CENTER, 53 | CSS_ALIGN_FLEX_END, 54 | CSS_ALIGN_STRETCH 55 | } css_align_t; 56 | 57 | typedef enum { 58 | CSS_POSITION_RELATIVE = 0, 59 | CSS_POSITION_ABSOLUTE 60 | } css_position_type_t; 61 | 62 | typedef enum { 63 | CSS_NOWRAP = 0, 64 | CSS_WRAP 65 | } css_wrap_type_t; 66 | 67 | // Note: left and top are shared between position[2] and position[4], so 68 | // they have to be before right and bottom. 69 | typedef enum { 70 | CSS_LEFT = 0, 71 | CSS_TOP, 72 | CSS_RIGHT, 73 | CSS_BOTTOM, 74 | CSS_START, 75 | CSS_END, 76 | CSS_POSITION_COUNT 77 | } css_position_t; 78 | 79 | typedef enum { 80 | CSS_WIDTH = 0, 81 | CSS_HEIGHT 82 | } css_dimension_t; 83 | 84 | typedef struct { 85 | float position[4]; 86 | float dimensions[2]; 87 | css_direction_t direction; 88 | 89 | // Instead of recomputing the entire layout every single time, we 90 | // cache some information to break early when nothing changed 91 | bool should_update; 92 | float last_requested_dimensions[2]; 93 | float last_parent_max_width; 94 | float last_dimensions[2]; 95 | float last_position[2]; 96 | css_direction_t last_direction; 97 | } css_layout_t; 98 | 99 | typedef struct { 100 | float dimensions[2]; 101 | } css_dim_t; 102 | 103 | typedef struct { 104 | css_direction_t direction; 105 | css_flex_direction_t flex_direction; 106 | css_justify_t justify_content; 107 | css_align_t align_content; 108 | css_align_t align_items; 109 | css_align_t align_self; 110 | css_position_type_t position_type; 111 | css_wrap_type_t flex_wrap; 112 | float flex; 113 | float margin[6]; 114 | float position[4]; 115 | /** 116 | * You should skip all the rules that contain negative values for the 117 | * following attributes. For example: 118 | * {padding: 10, paddingLeft: -5} 119 | * should output: 120 | * {left: 10 ...} 121 | * the following two are incorrect: 122 | * {left: -5 ...} 123 | * {left: 0 ...} 124 | */ 125 | float padding[6]; 126 | float border[6]; 127 | float dimensions[2]; 128 | float minDimensions[2]; 129 | float maxDimensions[2]; 130 | } css_style_t; 131 | 132 | typedef struct css_node { 133 | css_style_t style; 134 | css_layout_t layout; 135 | int children_count; 136 | int line_index; 137 | 138 | css_dim_t (*measure)(void *context, float width); 139 | void (*print)(void *context); 140 | struct css_node* (*get_child)(void *context, int i); 141 | bool (*is_dirty)(void *context); 142 | void *context; 143 | } css_node_t; 144 | 145 | 146 | // Lifecycle of nodes and children 147 | css_node_t *new_css_node(void); 148 | void init_css_node(css_node_t *node); 149 | void free_css_node(css_node_t *node); 150 | 151 | // Print utilities 152 | typedef enum { 153 | CSS_PRINT_LAYOUT = 1, 154 | CSS_PRINT_STYLE = 2, 155 | CSS_PRINT_CHILDREN = 4, 156 | } css_print_options_t; 157 | void print_css_node(css_node_t *node, css_print_options_t options); 158 | 159 | // Function that computes the layout! 160 | void layoutNode(css_node_t *node, float maxWidth, css_direction_t parentDirection); 161 | bool isUndefined(float value); 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /FlexboxKit/UIView+FLEXBOX.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+FLEXBOX.h 3 | // FlexboxKit 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "FLEXBOXNode.h" 11 | 12 | @interface UIView (FLEXBOX) 13 | 14 | // Properties 15 | 16 | /// YES if this view contains subviews that you wish to layout using the flexbox engine 17 | /// @note You don't need to set this if your view is a FLEXBOXContainerView 18 | @property (nonatomic, assign) BOOL flexContainer; 19 | 20 | /// Set this if you wish to have a fixed size for this element 21 | @property (nonatomic, assign) CGSize flexFixedSize; 22 | 23 | /// The minumum size for this element 24 | @property (nonatomic, assign) CGSize flexMinimumSize; 25 | 26 | /// The maximum size for this element 27 | @property (nonatomic, assign) CGSize flexMaximumSize; 28 | 29 | /// It establishes the main-axis, thus defining the direction flex items are placed in the flex container. 30 | /// - row: same as text direction (@see FLEXBOXFlexDirectionColumn) 31 | /// - column (default): same as row but top to bottom (@see FLEXBOXFlexDirectionRow) 32 | /// - row-reverse: (@see FLEXBOXFlexDirectionRowReverse) 33 | /// - column-reverse: (@see FLEXBOXFlexDirectionColumnReverse) 34 | @property (nonatomic, assign) FLEXBOXFlexDirection flexDirection; 35 | 36 | /// The margins for this flex item (default is 0) 37 | @property (nonatomic, assign) UIEdgeInsets flexMargin; 38 | 39 | /// The padding for this flex item (default is 0) 40 | @property (nonatomic, assign) UIEdgeInsets flexPadding; 41 | 42 | /// Make the flexible items wrap if necesarry: 43 | /// - wrap YES 44 | /// - nowrap (default) NO 45 | @property (nonatomic, assign) BOOL flexWrap; 46 | 47 | /// It defines the alignment along the main axis. It helps distribute extra free 48 | /// space leftover when either all the flex items on a line are inflexible, or are 49 | /// flexible but have reached their maximum size. It also exerts some control over 50 | /// the alignment of items when they overflow the line. 51 | /// - flex-start (default): items are packed toward the start line (@see FLEXBOXJustificationFlexStart) 52 | /// - flex-end: items are packed toward to end line (@see FLEXBOXJustificationFlexEnd) 53 | /// - center: items are centered along the line (@see FLEXBOXJustificationCenter) 54 | /// - space-between: items are evenly distributed in the line; first item is on the start line, last item on the end line (@see FLEXBOXJustificationSpaceBetween) 55 | /// - space-around: items are evenly distributed in the line with equal space around them (@see FLEXBOXJustificationSpaceAround) 56 | @property (nonatomic, assign) FLEXBOXJustification flexJustifyContent; 57 | 58 | /// Center the alignments for one of the items inside a flexible element 59 | /// - auto (default): The element inherits its parent container's align-items property, or "stretch" if it has no parent container (@see FLEXBOXAlignmentAuto) 60 | /// - stretch: The element is positioned to fit the conatiner (@see FLEXBOXAlignmentStretch) 61 | /// - center: The element is positioned at the center of the container (@see FLEXBOXAlignmentCenter) 62 | /// - flex-start: The element is are positioned at the beginning of the container (@see FLEXBOXAlignmentFlexStart) 63 | /// - flex-end: The element is positioned at the end of the container (@see FLEXBOXAlignmentFlexEnd) 64 | @property (nonatomic, assign) FLEXBOXAlignment flexAlignSelf; 65 | 66 | /// Center the alignments for all the items of the flexible element: 67 | /// - stretch (default): The element is positioned to fit the conatiner (@see FLEXBOXAlignmentStretch) 68 | /// - center: The element is positioned at the center of the container (@see FLEXBOXAlignmentCenter) 69 | /// - flex-start: The element is are positioned at the beginning of the container (@see FLEXBOXAlignmentFlexStart) 70 | /// - flex-end: The element is positioned at the end of the container (@see FLEXBOXAlignmentFlexEnd) 71 | @property (nonatomic, assign) FLEXBOXAlignment flexAlignItems; 72 | 73 | /// The flex property specifies the initial length of a flexible item. 74 | /// A value between 0 and 1 (a ratio e.g. 1/2, 2/3) 75 | @property (nonatomic, assign) CGFloat flex; 76 | 77 | 78 | /// The node content directon (default is inherit) 79 | @property (nonatomic, assign) FLEXBOXContentDirection flexContentDirection; 80 | 81 | // Methods 82 | 83 | /// Entry point for defining the size for this flex item 84 | /// @note By default it calls -[UIView sizeThatFits:] 85 | - (CGSize)flexComputeSize:(CGSize)bounds; 86 | 87 | /// Call this method in -[UIView layoutSubviews] if you want the flexbox 88 | /// engine to compute the layout 89 | - (void)flexLayoutSubviews; 90 | 91 | /// Define this block if you want to specify some custom logic instead of 92 | /// calling -[UIView sizeThatFits:] in -[UIView flexComputeSize:] 93 | @property (nonatomic, copy) CGSize (^flexSizeThatFitsBlock)(CGSize size); 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /FlexboxKit/UIView+FLEXBOX.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+FLEXBOX.m 3 | // FlexboxKit 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import "UIView+FLEXBOX.h" 10 | #import "FLEXBOXContainerView.h" 11 | #import 12 | 13 | const void *FLEXBOXContainerKey; 14 | const void *FLEXBOXNodeKey; 15 | const void *FLEXBOXOffsetNodeKey; 16 | const void *FLEXBOXOffsetKey; 17 | const void *FLEXBOXSizeKey; 18 | const void *FLEXBOXSizeThatFitsBlock; 19 | 20 | @interface UIView (_FLEXBOX) 21 | 22 | /// The associated flexbox node 23 | @property (nonatomic, strong) FLEXBOXNode *flexNode; 24 | @property (nonatomic, readonly, getter=isFlexOffsetNodeDefined) BOOL flexNodeDefined; 25 | 26 | @end 27 | 28 | 29 | @implementation UIView (FLEXBOX) 30 | 31 | - (FLEXBOXNode*)flexNode 32 | { 33 | FLEXBOXNode *node = objc_getAssociatedObject(self, &FLEXBOXNodeKey); 34 | 35 | if (node == nil) { 36 | node = [[FLEXBOXNode alloc] init]; 37 | self.flexNode = node; 38 | 39 | __weak __typeof(self) weakSelf = self; 40 | 41 | self.flexNode.childrenAtIndexBlock = ^FLEXBOXNode*(NSUInteger i) { 42 | return [weakSelf.subviews[i] flexNode]; 43 | }; 44 | 45 | self.flexNode.childrenCountBlock = ^NSUInteger(void) { 46 | return weakSelf.subviews.count; 47 | }; 48 | 49 | self.flexNode.measureBlock = ^CGSize(CGFloat width) { 50 | return [weakSelf flexComputeSize:(CGSize){width, NAN}]; 51 | }; 52 | } 53 | 54 | return node; 55 | } 56 | 57 | - (void)setFlexNode:(FLEXBOXNode*)flexNode 58 | { 59 | objc_setAssociatedObject(self, &FLEXBOXNodeKey, flexNode, OBJC_ASSOCIATION_RETAIN); 60 | } 61 | 62 | 63 | - (BOOL)flexContainer 64 | { 65 | return [objc_getAssociatedObject(self, &FLEXBOXContainerKey) boolValue]; 66 | } 67 | 68 | - (void)setFlexContainer:(BOOL)flexContainer 69 | { 70 | objc_setAssociatedObject(self, &FLEXBOXContainerKey, @(flexContainer), OBJC_ASSOCIATION_RETAIN); 71 | self.flex = flexContainer ? 1 : 0; 72 | } 73 | 74 | - (CGSize)flexFixedSize 75 | { 76 | NSValue *value = objc_getAssociatedObject(self, &FLEXBOXSizeKey); 77 | if (value != nil) { 78 | return [value CGSizeValue]; 79 | } else { 80 | return CGSizeZero; 81 | } 82 | } 83 | 84 | - (void)setFlexFixedSize:(CGSize)flexFixedSize 85 | { 86 | return objc_setAssociatedObject(self, &FLEXBOXSizeKey, [NSValue valueWithCGSize:flexFixedSize], OBJC_ASSOCIATION_RETAIN); 87 | } 88 | 89 | - (void)setFlexSizeThatFitsBlock:(CGSize (^)(CGSize))sizeThatFitsBlock 90 | { 91 | objc_setAssociatedObject(self, &FLEXBOXSizeThatFitsBlock, [sizeThatFitsBlock copy], OBJC_ASSOCIATION_COPY); 92 | } 93 | 94 | - (CGSize (^)(CGSize))flexSizeThatFitsBlock 95 | { 96 | return objc_getAssociatedObject(self, &FLEXBOXSizeThatFitsBlock); 97 | } 98 | 99 | - (CGSize)flexComputeSize:(CGSize)bounds 100 | { 101 | if (!CGSizeEqualToSize(self.flexFixedSize, CGSizeZero)) 102 | return self.flexFixedSize; 103 | 104 | bounds.height = isnan(bounds.height) ? FLT_MAX : bounds.height; 105 | bounds.width = isnan(bounds.width) ? FLT_MAX : bounds.width; 106 | 107 | CGSize size = CGSizeZero; 108 | 109 | if (self.flexSizeThatFitsBlock != nil) { 110 | size = self.flexSizeThatFitsBlock(bounds); 111 | } else { 112 | size = [self sizeThatFits:bounds]; 113 | } 114 | 115 | CGSize max = self.flexMaximumSize; 116 | if (!CGSizeEqualToSize(max, CGSizeZero) || !CGSizeEqualToSize(max, (CGSize){FLT_MAX, FLT_MAX})) { 117 | size.height = !isnan(max.height) && fabs(max.height) > FLT_EPSILON && size.height > max.height ? max.height : size.height; 118 | size.width = !isnan(max.width) && fabs(max.width) > FLT_EPSILON && size.width > max.width ? max.width : size.width; 119 | } 120 | 121 | CGSize min = self.flexMinimumSize; 122 | if (!CGSizeEqualToSize(min, CGSizeZero) || !CGSizeEqualToSize(max, (CGSize){FLT_MIN, FLT_MIN})) { 123 | size.height = !isnan(min.height) && fabs(min.height) > FLT_EPSILON && size.height < min.height ? min.height : size.height; 124 | size.width = !isnan(min.width) && fabs(min.width) > FLT_EPSILON && size.width < min.width ? min.width : size.width; 125 | } 126 | 127 | return size; 128 | } 129 | 130 | - (void)flexLayoutSubviews 131 | { 132 | self.flexNode.dimensions = self.bounds.size; 133 | [self _flexLayoutSubviewsFromView:self]; 134 | self.frame = (CGRect){self.frame.origin, self.flexNode.frame.size}; 135 | } 136 | 137 | - (void)_flexLayoutSubviewsFromView:(UIView*)view 138 | { 139 | [view.flexNode layoutConstrainedToMaximumWidth:CGRectGetWidth(view.bounds)]; 140 | 141 | for (NSUInteger i = 0; i < view.subviews.count; i++) { 142 | 143 | UIView *subview = view.subviews[i]; 144 | FLEXBOXNode *subnode = subview.flexNode; 145 | subview.frame = CGRectIntegral(subnode.frame); 146 | } 147 | 148 | for (NSUInteger i = 0; i < view.subviews.count; i++) { 149 | UIView *subview = view.subviews[i]; 150 | 151 | if (subview.flexContainer) 152 | [self _flexLayoutSubviewsFromView:subview]; 153 | } 154 | } 155 | 156 | #pragma mark - Properties 157 | 158 | - (FLEXBOXFlexDirection)flexDirection 159 | { 160 | return self.flexNode.flexDirection; 161 | } 162 | 163 | - (void)setFlexDirection:(FLEXBOXFlexDirection)flexDirection 164 | { 165 | self.flexNode.flexDirection = flexDirection; 166 | } 167 | 168 | - (UIEdgeInsets)flexMargin 169 | { 170 | return self.flexNode.margin; 171 | } 172 | 173 | - (void)setFlexMargin:(UIEdgeInsets)flexMargin 174 | { 175 | self.flexNode.margin = flexMargin; 176 | } 177 | 178 | - (UIEdgeInsets)flexPadding 179 | { 180 | return self.flexNode.padding; 181 | } 182 | 183 | - (void)setFlexPadding:(UIEdgeInsets)flexPadding 184 | { 185 | self.flexNode.padding = flexPadding; 186 | } 187 | 188 | - (BOOL)flexWrap 189 | { 190 | return self.flexNode.flexWrap; 191 | } 192 | 193 | - (void)setFlexWrap:(BOOL)flexWrap 194 | { 195 | self.flexNode.flexWrap = flexWrap; 196 | } 197 | 198 | - (FLEXBOXJustification)flexJustifyContent 199 | { 200 | return self.flexNode.justifyContent; 201 | } 202 | 203 | - (void)setFlexJustifyContent:(FLEXBOXJustification)flexJustifyContent 204 | { 205 | self.flexNode.justifyContent = flexJustifyContent; 206 | } 207 | 208 | - (FLEXBOXAlignment)flexAlignSelf 209 | { 210 | return self.flexNode.alignSelf; 211 | } 212 | 213 | - (void)setFlexAlignSelf:(FLEXBOXAlignment)flexAlignSelf 214 | { 215 | self.flexNode.alignSelf = flexAlignSelf; 216 | } 217 | 218 | - (FLEXBOXAlignment)flexAlignItems 219 | { 220 | return self.flexNode.alignItems; 221 | } 222 | 223 | - (void)setFlexAlignItems:(FLEXBOXAlignment)flexAlignItems 224 | { 225 | self.flexNode.alignItems = flexAlignItems; 226 | } 227 | 228 | - (CGFloat)flex 229 | { 230 | return self.flexNode.flex; 231 | } 232 | 233 | - (void)setFlex:(CGFloat)flex 234 | { 235 | self.flexNode.flex = flex; 236 | } 237 | 238 | - (CGSize)flexMinimumSize 239 | { 240 | return self.flexNode.minDimensions; 241 | } 242 | 243 | - (void)setFlexMinimumSize:(CGSize)flexMinimumSize 244 | { 245 | self.flexNode.minDimensions = flexMinimumSize; 246 | } 247 | 248 | - (CGSize)flexMaximumSize 249 | { 250 | return self.flexNode.maxDimensions; 251 | } 252 | 253 | - (void)setFlexMaximumSize:(CGSize)flexMaximumSize 254 | { 255 | self.flexNode.maxDimensions = flexMaximumSize; 256 | } 257 | 258 | - (FLEXBOXContentDirection)flexContentDirection 259 | { 260 | return self.flexNode.contentDirection; 261 | } 262 | 263 | - (void)setFlexContentDirection:(FLEXBOXContentDirection)flexContentDirection 264 | { 265 | self.flexNode.contentDirection = flexContentDirection; 266 | } 267 | 268 | @end 269 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 16184A341AFE984200D9BC28 /* FlexboxKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16AD78FB1AFE9768003C2D01 /* FlexboxKit.framework */; }; 11 | 16184A351AFE984200D9BC28 /* FlexboxKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 16AD78FB1AFE9768003C2D01 /* FlexboxKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 12 | 162265831AFFB1D40039345E /* CellDemoTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 162265821AFFB1D40039345E /* CellDemoTableViewController.m */; }; 13 | 16AD78D21AFE9762003C2D01 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78D11AFE9762003C2D01 /* main.m */; }; 14 | 16AD78D51AFE9762003C2D01 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78D41AFE9762003C2D01 /* AppDelegate.m */; }; 15 | 16AD78D81AFE9762003C2D01 /* ButtonDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78D71AFE9762003C2D01 /* ButtonDemoViewController.m */; }; 16 | 16AD78DD1AFE9762003C2D01 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 16AD78DC1AFE9762003C2D01 /* Images.xcassets */; }; 17 | 16AD78E01AFE9762003C2D01 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 16AD78DE1AFE9762003C2D01 /* LaunchScreen.xib */; }; 18 | 16AD78EC1AFE9762003C2D01 /* FlexboxKitDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AD78EB1AFE9762003C2D01 /* FlexboxKitDemoTests.m */; }; 19 | 16BA5F771B0A8ACF00BBEE70 /* GridDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 16BA5F761B0A8ACF00BBEE70 /* GridDemoViewController.m */; }; 20 | 16DE54E91B171D36005775A0 /* UIColor+Demo.m in Sources */ = {isa = PBXBuildFile; fileRef = 16DE54E81B171D36005775A0 /* UIColor+Demo.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 16184A361AFE984200D9BC28 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 16AD78F51AFE9767003C2D01 /* FlexboxKit.xcodeproj */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 16AD78991AFE7C50003C2D01; 29 | remoteInfo = FlexboxKit; 30 | }; 31 | 16AD78E61AFE9762003C2D01 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 16AD78C41AFE9762003C2D01 /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 16AD78CB1AFE9762003C2D01; 36 | remoteInfo = FlexboxKitDemo; 37 | }; 38 | 16AD78FA1AFE9768003C2D01 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = 16AD78F51AFE9767003C2D01 /* FlexboxKit.xcodeproj */; 41 | proxyType = 2; 42 | remoteGlobalIDString = 16AD789A1AFE7C50003C2D01; 43 | remoteInfo = FlexboxKit; 44 | }; 45 | 16AD78FC1AFE9768003C2D01 /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = 16AD78F51AFE9767003C2D01 /* FlexboxKit.xcodeproj */; 48 | proxyType = 2; 49 | remoteGlobalIDString = 16AD78A51AFE7C50003C2D01; 50 | remoteInfo = FlexboxKitTests; 51 | }; 52 | /* End PBXContainerItemProxy section */ 53 | 54 | /* Begin PBXCopyFilesBuildPhase section */ 55 | 16184A381AFE984200D9BC28 /* Embed Frameworks */ = { 56 | isa = PBXCopyFilesBuildPhase; 57 | buildActionMask = 2147483647; 58 | dstPath = ""; 59 | dstSubfolderSpec = 10; 60 | files = ( 61 | 16184A351AFE984200D9BC28 /* FlexboxKit.framework in Embed Frameworks */, 62 | ); 63 | name = "Embed Frameworks"; 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXCopyFilesBuildPhase section */ 67 | 68 | /* Begin PBXFileReference section */ 69 | 162265811AFFB1D40039345E /* CellDemoTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CellDemoTableViewController.h; sourceTree = ""; }; 70 | 162265821AFFB1D40039345E /* CellDemoTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CellDemoTableViewController.m; sourceTree = ""; }; 71 | 16AD78CC1AFE9762003C2D01 /* FlexboxKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FlexboxKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | 16AD78D01AFE9762003C2D01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | 16AD78D11AFE9762003C2D01 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 74 | 16AD78D31AFE9762003C2D01 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 75 | 16AD78D41AFE9762003C2D01 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 76 | 16AD78D61AFE9762003C2D01 /* ButtonDemoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ButtonDemoViewController.h; sourceTree = ""; }; 77 | 16AD78D71AFE9762003C2D01 /* ButtonDemoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ButtonDemoViewController.m; sourceTree = ""; }; 78 | 16AD78DC1AFE9762003C2D01 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 79 | 16AD78DF1AFE9762003C2D01 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 80 | 16AD78E51AFE9762003C2D01 /* FlexboxKitDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FlexboxKitDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | 16AD78EA1AFE9762003C2D01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | 16AD78EB1AFE9762003C2D01 /* FlexboxKitDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlexboxKitDemoTests.m; sourceTree = ""; }; 83 | 16AD78F51AFE9767003C2D01 /* FlexboxKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = FlexboxKit.xcodeproj; path = ../FlexboxKit.xcodeproj; sourceTree = ""; }; 84 | 16BA5F751B0A8ACF00BBEE70 /* GridDemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GridDemoViewController.h; sourceTree = ""; }; 85 | 16BA5F761B0A8ACF00BBEE70 /* GridDemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GridDemoViewController.m; sourceTree = ""; }; 86 | 16DE54E71B171D36005775A0 /* UIColor+Demo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+Demo.h"; sourceTree = ""; }; 87 | 16DE54E81B171D36005775A0 /* UIColor+Demo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+Demo.m"; sourceTree = ""; }; 88 | /* End PBXFileReference section */ 89 | 90 | /* Begin PBXFrameworksBuildPhase section */ 91 | 16AD78C91AFE9762003C2D01 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | 16184A341AFE984200D9BC28 /* FlexboxKit.framework in Frameworks */, 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | 16AD78E21AFE9762003C2D01 /* Frameworks */ = { 100 | isa = PBXFrameworksBuildPhase; 101 | buildActionMask = 2147483647; 102 | files = ( 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXFrameworksBuildPhase section */ 107 | 108 | /* Begin PBXGroup section */ 109 | 16AD78C31AFE9762003C2D01 = { 110 | isa = PBXGroup; 111 | children = ( 112 | 16AD78F51AFE9767003C2D01 /* FlexboxKit.xcodeproj */, 113 | 16AD78CE1AFE9762003C2D01 /* FlexboxKitDemo */, 114 | 16AD78E81AFE9762003C2D01 /* FlexboxKitDemoTests */, 115 | 16AD78CD1AFE9762003C2D01 /* Products */, 116 | ); 117 | sourceTree = ""; 118 | }; 119 | 16AD78CD1AFE9762003C2D01 /* Products */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 16AD78CC1AFE9762003C2D01 /* FlexboxKitDemo.app */, 123 | 16AD78E51AFE9762003C2D01 /* FlexboxKitDemoTests.xctest */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | 16AD78CE1AFE9762003C2D01 /* FlexboxKitDemo */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 16DE54E51B171D01005775A0 /* Demos */, 132 | 16AD78D31AFE9762003C2D01 /* AppDelegate.h */, 133 | 16AD78D41AFE9762003C2D01 /* AppDelegate.m */, 134 | 16AD78DC1AFE9762003C2D01 /* Images.xcassets */, 135 | 16AD78DE1AFE9762003C2D01 /* LaunchScreen.xib */, 136 | 16AD78CF1AFE9762003C2D01 /* Supporting Files */, 137 | ); 138 | path = FlexboxKitDemo; 139 | sourceTree = ""; 140 | }; 141 | 16AD78CF1AFE9762003C2D01 /* Supporting Files */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 16AD78D01AFE9762003C2D01 /* Info.plist */, 145 | 16AD78D11AFE9762003C2D01 /* main.m */, 146 | ); 147 | name = "Supporting Files"; 148 | sourceTree = ""; 149 | }; 150 | 16AD78E81AFE9762003C2D01 /* FlexboxKitDemoTests */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 16AD78EB1AFE9762003C2D01 /* FlexboxKitDemoTests.m */, 154 | 16AD78E91AFE9762003C2D01 /* Supporting Files */, 155 | ); 156 | path = FlexboxKitDemoTests; 157 | sourceTree = ""; 158 | }; 159 | 16AD78E91AFE9762003C2D01 /* Supporting Files */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 16AD78EA1AFE9762003C2D01 /* Info.plist */, 163 | ); 164 | name = "Supporting Files"; 165 | sourceTree = ""; 166 | }; 167 | 16AD78F61AFE9767003C2D01 /* Products */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 16AD78FB1AFE9768003C2D01 /* FlexboxKit.framework */, 171 | 16AD78FD1AFE9768003C2D01 /* FlexboxKitTests.xctest */, 172 | ); 173 | name = Products; 174 | sourceTree = ""; 175 | }; 176 | 16DE54E51B171D01005775A0 /* Demos */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 16AD78D61AFE9762003C2D01 /* ButtonDemoViewController.h */, 180 | 16AD78D71AFE9762003C2D01 /* ButtonDemoViewController.m */, 181 | 162265811AFFB1D40039345E /* CellDemoTableViewController.h */, 182 | 162265821AFFB1D40039345E /* CellDemoTableViewController.m */, 183 | 16BA5F751B0A8ACF00BBEE70 /* GridDemoViewController.h */, 184 | 16BA5F761B0A8ACF00BBEE70 /* GridDemoViewController.m */, 185 | 16DE54E71B171D36005775A0 /* UIColor+Demo.h */, 186 | 16DE54E81B171D36005775A0 /* UIColor+Demo.m */, 187 | ); 188 | name = Demos; 189 | sourceTree = ""; 190 | }; 191 | /* End PBXGroup section */ 192 | 193 | /* Begin PBXNativeTarget section */ 194 | 16AD78CB1AFE9762003C2D01 /* FlexboxKitDemo */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = 16AD78EF1AFE9762003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKitDemo" */; 197 | buildPhases = ( 198 | 16AD78C81AFE9762003C2D01 /* Sources */, 199 | 16AD78C91AFE9762003C2D01 /* Frameworks */, 200 | 16AD78CA1AFE9762003C2D01 /* Resources */, 201 | 16184A381AFE984200D9BC28 /* Embed Frameworks */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | 16184A371AFE984200D9BC28 /* PBXTargetDependency */, 207 | ); 208 | name = FlexboxKitDemo; 209 | productName = FlexboxKitDemo; 210 | productReference = 16AD78CC1AFE9762003C2D01 /* FlexboxKitDemo.app */; 211 | productType = "com.apple.product-type.application"; 212 | }; 213 | 16AD78E41AFE9762003C2D01 /* FlexboxKitDemoTests */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = 16AD78F21AFE9762003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKitDemoTests" */; 216 | buildPhases = ( 217 | 16AD78E11AFE9762003C2D01 /* Sources */, 218 | 16AD78E21AFE9762003C2D01 /* Frameworks */, 219 | 16AD78E31AFE9762003C2D01 /* Resources */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | 16AD78E71AFE9762003C2D01 /* PBXTargetDependency */, 225 | ); 226 | name = FlexboxKitDemoTests; 227 | productName = FlexboxKitDemoTests; 228 | productReference = 16AD78E51AFE9762003C2D01 /* FlexboxKitDemoTests.xctest */; 229 | productType = "com.apple.product-type.bundle.unit-test"; 230 | }; 231 | /* End PBXNativeTarget section */ 232 | 233 | /* Begin PBXProject section */ 234 | 16AD78C41AFE9762003C2D01 /* Project object */ = { 235 | isa = PBXProject; 236 | attributes = { 237 | LastUpgradeCheck = 0640; 238 | ORGANIZATIONNAME = "Alex Usbergo"; 239 | TargetAttributes = { 240 | 16AD78CB1AFE9762003C2D01 = { 241 | CreatedOnToolsVersion = 6.4; 242 | }; 243 | 16AD78E41AFE9762003C2D01 = { 244 | CreatedOnToolsVersion = 6.4; 245 | TestTargetID = 16AD78CB1AFE9762003C2D01; 246 | }; 247 | }; 248 | }; 249 | buildConfigurationList = 16AD78C71AFE9762003C2D01 /* Build configuration list for PBXProject "FlexboxKitDemo" */; 250 | compatibilityVersion = "Xcode 3.2"; 251 | developmentRegion = English; 252 | hasScannedForEncodings = 0; 253 | knownRegions = ( 254 | en, 255 | Base, 256 | ); 257 | mainGroup = 16AD78C31AFE9762003C2D01; 258 | productRefGroup = 16AD78CD1AFE9762003C2D01 /* Products */; 259 | projectDirPath = ""; 260 | projectReferences = ( 261 | { 262 | ProductGroup = 16AD78F61AFE9767003C2D01 /* Products */; 263 | ProjectRef = 16AD78F51AFE9767003C2D01 /* FlexboxKit.xcodeproj */; 264 | }, 265 | ); 266 | projectRoot = ""; 267 | targets = ( 268 | 16AD78CB1AFE9762003C2D01 /* FlexboxKitDemo */, 269 | 16AD78E41AFE9762003C2D01 /* FlexboxKitDemoTests */, 270 | ); 271 | }; 272 | /* End PBXProject section */ 273 | 274 | /* Begin PBXReferenceProxy section */ 275 | 16AD78FB1AFE9768003C2D01 /* FlexboxKit.framework */ = { 276 | isa = PBXReferenceProxy; 277 | fileType = wrapper.framework; 278 | path = FlexboxKit.framework; 279 | remoteRef = 16AD78FA1AFE9768003C2D01 /* PBXContainerItemProxy */; 280 | sourceTree = BUILT_PRODUCTS_DIR; 281 | }; 282 | 16AD78FD1AFE9768003C2D01 /* FlexboxKitTests.xctest */ = { 283 | isa = PBXReferenceProxy; 284 | fileType = wrapper.cfbundle; 285 | path = FlexboxKitTests.xctest; 286 | remoteRef = 16AD78FC1AFE9768003C2D01 /* PBXContainerItemProxy */; 287 | sourceTree = BUILT_PRODUCTS_DIR; 288 | }; 289 | /* End PBXReferenceProxy section */ 290 | 291 | /* Begin PBXResourcesBuildPhase section */ 292 | 16AD78CA1AFE9762003C2D01 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 16AD78E01AFE9762003C2D01 /* LaunchScreen.xib in Resources */, 297 | 16AD78DD1AFE9762003C2D01 /* Images.xcassets in Resources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | 16AD78E31AFE9762003C2D01 /* Resources */ = { 302 | isa = PBXResourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | /* End PBXResourcesBuildPhase section */ 309 | 310 | /* Begin PBXSourcesBuildPhase section */ 311 | 16AD78C81AFE9762003C2D01 /* Sources */ = { 312 | isa = PBXSourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | 16DE54E91B171D36005775A0 /* UIColor+Demo.m in Sources */, 316 | 162265831AFFB1D40039345E /* CellDemoTableViewController.m in Sources */, 317 | 16AD78D81AFE9762003C2D01 /* ButtonDemoViewController.m in Sources */, 318 | 16AD78D51AFE9762003C2D01 /* AppDelegate.m in Sources */, 319 | 16AD78D21AFE9762003C2D01 /* main.m in Sources */, 320 | 16BA5F771B0A8ACF00BBEE70 /* GridDemoViewController.m in Sources */, 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | 16AD78E11AFE9762003C2D01 /* Sources */ = { 325 | isa = PBXSourcesBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | 16AD78EC1AFE9762003C2D01 /* FlexboxKitDemoTests.m in Sources */, 329 | ); 330 | runOnlyForDeploymentPostprocessing = 0; 331 | }; 332 | /* End PBXSourcesBuildPhase section */ 333 | 334 | /* Begin PBXTargetDependency section */ 335 | 16184A371AFE984200D9BC28 /* PBXTargetDependency */ = { 336 | isa = PBXTargetDependency; 337 | name = FlexboxKit; 338 | targetProxy = 16184A361AFE984200D9BC28 /* PBXContainerItemProxy */; 339 | }; 340 | 16AD78E71AFE9762003C2D01 /* PBXTargetDependency */ = { 341 | isa = PBXTargetDependency; 342 | target = 16AD78CB1AFE9762003C2D01 /* FlexboxKitDemo */; 343 | targetProxy = 16AD78E61AFE9762003C2D01 /* PBXContainerItemProxy */; 344 | }; 345 | /* End PBXTargetDependency section */ 346 | 347 | /* Begin PBXVariantGroup section */ 348 | 16AD78DE1AFE9762003C2D01 /* LaunchScreen.xib */ = { 349 | isa = PBXVariantGroup; 350 | children = ( 351 | 16AD78DF1AFE9762003C2D01 /* Base */, 352 | ); 353 | name = LaunchScreen.xib; 354 | sourceTree = ""; 355 | }; 356 | /* End PBXVariantGroup section */ 357 | 358 | /* Begin XCBuildConfiguration section */ 359 | 16AD78ED1AFE9762003C2D01 /* Debug */ = { 360 | isa = XCBuildConfiguration; 361 | buildSettings = { 362 | ALWAYS_SEARCH_USER_PATHS = NO; 363 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 364 | CLANG_CXX_LIBRARY = "libc++"; 365 | CLANG_ENABLE_MODULES = YES; 366 | CLANG_ENABLE_OBJC_ARC = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_CONSTANT_CONVERSION = YES; 369 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 370 | CLANG_WARN_EMPTY_BODY = YES; 371 | CLANG_WARN_ENUM_CONVERSION = YES; 372 | CLANG_WARN_INT_CONVERSION = YES; 373 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 374 | CLANG_WARN_UNREACHABLE_CODE = YES; 375 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 376 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 377 | COPY_PHASE_STRIP = NO; 378 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 379 | ENABLE_STRICT_OBJC_MSGSEND = YES; 380 | GCC_C_LANGUAGE_STANDARD = gnu99; 381 | GCC_DYNAMIC_NO_PIC = NO; 382 | GCC_NO_COMMON_BLOCKS = YES; 383 | GCC_OPTIMIZATION_LEVEL = 0; 384 | GCC_PREPROCESSOR_DEFINITIONS = ( 385 | "DEBUG=1", 386 | "$(inherited)", 387 | ); 388 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 389 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 390 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 391 | GCC_WARN_UNDECLARED_SELECTOR = YES; 392 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 393 | GCC_WARN_UNUSED_FUNCTION = YES; 394 | GCC_WARN_UNUSED_VARIABLE = YES; 395 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 396 | MTL_ENABLE_DEBUG_INFO = YES; 397 | ONLY_ACTIVE_ARCH = YES; 398 | SDKROOT = iphoneos; 399 | TARGETED_DEVICE_FAMILY = "1,2"; 400 | }; 401 | name = Debug; 402 | }; 403 | 16AD78EE1AFE9762003C2D01 /* Release */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ALWAYS_SEARCH_USER_PATHS = NO; 407 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 408 | CLANG_CXX_LIBRARY = "libc++"; 409 | CLANG_ENABLE_MODULES = YES; 410 | CLANG_ENABLE_OBJC_ARC = YES; 411 | CLANG_WARN_BOOL_CONVERSION = YES; 412 | CLANG_WARN_CONSTANT_CONVERSION = YES; 413 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 414 | CLANG_WARN_EMPTY_BODY = YES; 415 | CLANG_WARN_ENUM_CONVERSION = YES; 416 | CLANG_WARN_INT_CONVERSION = YES; 417 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 418 | CLANG_WARN_UNREACHABLE_CODE = YES; 419 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 420 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 421 | COPY_PHASE_STRIP = NO; 422 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 423 | ENABLE_NS_ASSERTIONS = NO; 424 | ENABLE_STRICT_OBJC_MSGSEND = YES; 425 | GCC_C_LANGUAGE_STANDARD = gnu99; 426 | GCC_NO_COMMON_BLOCKS = YES; 427 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 428 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 429 | GCC_WARN_UNDECLARED_SELECTOR = YES; 430 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 431 | GCC_WARN_UNUSED_FUNCTION = YES; 432 | GCC_WARN_UNUSED_VARIABLE = YES; 433 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 434 | MTL_ENABLE_DEBUG_INFO = NO; 435 | SDKROOT = iphoneos; 436 | TARGETED_DEVICE_FAMILY = "1,2"; 437 | VALIDATE_PRODUCT = YES; 438 | }; 439 | name = Release; 440 | }; 441 | 16AD78F01AFE9762003C2D01 /* Debug */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 445 | INFOPLIST_FILE = FlexboxKitDemo/Info.plist; 446 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 447 | PRODUCT_NAME = "$(TARGET_NAME)"; 448 | }; 449 | name = Debug; 450 | }; 451 | 16AD78F11AFE9762003C2D01 /* Release */ = { 452 | isa = XCBuildConfiguration; 453 | buildSettings = { 454 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 455 | INFOPLIST_FILE = FlexboxKitDemo/Info.plist; 456 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 457 | PRODUCT_NAME = "$(TARGET_NAME)"; 458 | }; 459 | name = Release; 460 | }; 461 | 16AD78F31AFE9762003C2D01 /* Debug */ = { 462 | isa = XCBuildConfiguration; 463 | buildSettings = { 464 | BUNDLE_LOADER = "$(TEST_HOST)"; 465 | FRAMEWORK_SEARCH_PATHS = ( 466 | "$(SDKROOT)/Developer/Library/Frameworks", 467 | "$(inherited)", 468 | ); 469 | GCC_PREPROCESSOR_DEFINITIONS = ( 470 | "DEBUG=1", 471 | "$(inherited)", 472 | ); 473 | INFOPLIST_FILE = FlexboxKitDemoTests/Info.plist; 474 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 475 | PRODUCT_NAME = "$(TARGET_NAME)"; 476 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FlexboxKitDemo.app/FlexboxKitDemo"; 477 | }; 478 | name = Debug; 479 | }; 480 | 16AD78F41AFE9762003C2D01 /* Release */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | BUNDLE_LOADER = "$(TEST_HOST)"; 484 | FRAMEWORK_SEARCH_PATHS = ( 485 | "$(SDKROOT)/Developer/Library/Frameworks", 486 | "$(inherited)", 487 | ); 488 | INFOPLIST_FILE = FlexboxKitDemoTests/Info.plist; 489 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FlexboxKitDemo.app/FlexboxKitDemo"; 492 | }; 493 | name = Release; 494 | }; 495 | /* End XCBuildConfiguration section */ 496 | 497 | /* Begin XCConfigurationList section */ 498 | 16AD78C71AFE9762003C2D01 /* Build configuration list for PBXProject "FlexboxKitDemo" */ = { 499 | isa = XCConfigurationList; 500 | buildConfigurations = ( 501 | 16AD78ED1AFE9762003C2D01 /* Debug */, 502 | 16AD78EE1AFE9762003C2D01 /* Release */, 503 | ); 504 | defaultConfigurationIsVisible = 0; 505 | defaultConfigurationName = Release; 506 | }; 507 | 16AD78EF1AFE9762003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKitDemo" */ = { 508 | isa = XCConfigurationList; 509 | buildConfigurations = ( 510 | 16AD78F01AFE9762003C2D01 /* Debug */, 511 | 16AD78F11AFE9762003C2D01 /* Release */, 512 | ); 513 | defaultConfigurationIsVisible = 0; 514 | defaultConfigurationName = Release; 515 | }; 516 | 16AD78F21AFE9762003C2D01 /* Build configuration list for PBXNativeTarget "FlexboxKitDemoTests" */ = { 517 | isa = XCConfigurationList; 518 | buildConfigurations = ( 519 | 16AD78F31AFE9762003C2D01 /* Debug */, 520 | 16AD78F41AFE9762003C2D01 /* Release */, 521 | ); 522 | defaultConfigurationIsVisible = 0; 523 | defaultConfigurationName = Release; 524 | }; 525 | /* End XCConfigurationList section */ 526 | }; 527 | rootObject = 16AD78C41AFE9762003C2D01 /* Project object */; 528 | } 529 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo.xcodeproj/project.xcworkspace/xcshareddata/FlexboxKitDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | FB7C21E2-4DA4-4168-B04C-4F04EE163516 9 | IDESourceControlProjectName 10 | FlexboxKitDemo 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 14 | github.com:alexdrone/ios-flexboxkit.git 15 | 16 | IDESourceControlProjectPath 17 | FlexboxKitDemo/FlexboxKitDemo.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:alexdrone/ios-flexboxkit.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 7F64158A23285CFBA7007C5FB79921ADE9424B4A 36 | IDESourceControlWCCName 37 | ios-flexboxkit 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo.xcodeproj/project.xcworkspace/xcuserdata/alexusbergo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexdrone/flexboxobjc_deprecated/db7e0dd588ad664d9d239a564219279fe6f05b35/FlexboxKitDemo/FlexboxKitDemo.xcodeproj/project.xcworkspace/xcuserdata/alexusbergo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo.xcodeproj/project.xcworkspace/xcuserdata/alexusbergo.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ButtonDemoViewController.h" 11 | #import "CellDemoTableViewController.h" 12 | #import "GridDemoViewController.h" 13 | 14 | @interface AppDelegate () 15 | 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | 21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 22 | { 23 | 24 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 25 | 26 | //Comment/uncomment these lines to try the different demos 27 | self.window.rootViewController = [[GridDemoViewController alloc] init]; 28 | // self.window.rootViewController = [[CellDemoTableViewController alloc] init]; 29 | // self.window.rootViewController = [[ButtonDemoViewController alloc] init]; 30 | 31 | [self.window makeKeyAndVisible]; 32 | 33 | // Override point for customization after application launch. 34 | return YES; 35 | } 36 | 37 | - (void)applicationWillResignActive:(UIApplication *)application 38 | { 39 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 40 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 41 | } 42 | 43 | - (void)applicationDidEnterBackground:(UIApplication *)application 44 | { 45 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 46 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 47 | } 48 | 49 | - (void)applicationWillEnterForeground:(UIApplication *)application 50 | { 51 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 52 | } 53 | 54 | - (void)applicationDidBecomeActive:(UIApplication *)application 55 | { 56 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 57 | } 58 | 59 | - (void)applicationWillTerminate:(UIApplication *)application 60 | { 61 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/ButtonDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ButtonDemoViewController : UIViewController 12 | @end 13 | 14 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/ButtonDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import "UIColor+Demo.h" 10 | #import "ButtonDemoViewController.h" 11 | @import FlexboxKit; 12 | 13 | @interface ButtonDemoViewController () 14 | 15 | @property (nonatomic, strong) FLEXBOXContainerView *container; 16 | @property (nonatomic, strong) NSArray *views; 17 | 18 | @end 19 | 20 | @implementation ButtonDemoViewController 21 | 22 | - (void)viewDidLoad 23 | { 24 | [super viewDidLoad]; 25 | 26 | //the flexbox container 27 | self.container = [[FLEXBOXContainerView alloc] initWithFrame:self.view.bounds]; 28 | self.container.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth; 29 | self.container.backgroundColor = UIColor.darkGrayColor; 30 | 31 | self.views = [self createDummyViews]; 32 | 33 | //view hierarchy 34 | [self.view addSubview:self.container]; 35 | for (UIView *v in self.views) 36 | [self.container addSubview:v]; 37 | 38 | //Flexbox 39 | [self layout:0]; 40 | } 41 | 42 | - (void)didPressButton:(UIButton*)sender 43 | { 44 | [self layout:sender.tag]; 45 | } 46 | 47 | #pragma mark - Different layouts 48 | 49 | - (void)layout:(NSInteger)index 50 | { 51 | self.container.flexJustifyContent = FLEXBOXJustificationCenter; 52 | self.container.flexAlignItems = FLEXBOXAlignmentCenter; 53 | self.container.flexPadding = (UIEdgeInsets){32,16,32,16};; 54 | 55 | for (UIView *v in self.views) { 56 | v.flexMargin = (UIEdgeInsets){8,8,8,8}; 57 | v.flexPadding = (UIEdgeInsets){4,4,4,4}; 58 | v.flex = 0; 59 | v.flexFixedSize = CGSizeZero; 60 | v.flexMaximumSize = (CGSize){FLT_MAX, FLT_MAX}; 61 | } 62 | 63 | switch (index) { 64 | 65 | // all items in in a column 66 | case 0: { 67 | self.container.flexJustifyContent = FLEXBOXJustificationCenter; 68 | self.container.flexAlignItems = FLEXBOXAlignmentCenter; 69 | self.container.flexDirection = FLEXBOXFlexDirectionColumn; 70 | 71 | break; 72 | } 73 | 74 | // all items in a row, 75 | case 1: { 76 | self.container.flexJustifyContent = FLEXBOXJustificationCenter; 77 | self.container.flexAlignItems = FLEXBOXAlignmentCenter; 78 | self.container.flexDirection = FLEXBOXFlexDirectionRow; 79 | 80 | for (UIView *v in self.views) { 81 | v.flex = 1; 82 | } 83 | break; 84 | } 85 | 86 | // wraps to the next line 87 | case 2: { 88 | 89 | for (UIView *v in self.views) { 90 | v.flexPadding = (UIEdgeInsets){12,12,12,12}; 91 | } 92 | self.container.flexWrap = YES; 93 | break; 94 | } 95 | 96 | // start 97 | case 3: { 98 | self.container.flexAlignItems = FLEXBOXAlignmentFlexStart; 99 | self.container.flexJustifyContent = FLEXBOXJustificationFlexStart; 100 | break; 101 | 102 | } 103 | 104 | // end 105 | case 4: { 106 | self.container.flexAlignItems = FLEXBOXAlignmentFlexEnd; 107 | self.container.flexJustifyContent = FLEXBOXJustificationFlexEnd; 108 | for (UIView *v in self.views) { 109 | v.flex = 1; 110 | } 111 | 112 | break; 113 | } 114 | 115 | // stretch 116 | case 5: { 117 | self.container.flexAlignItems = FLEXBOXAlignmentStretch; 118 | self.container.flexJustifyContent = FLEXBOXJustificationCenter; 119 | 120 | for (UIView *v in self.views) { 121 | v.flex = 1; 122 | } 123 | break; 124 | } 125 | 126 | // stretch (with max width) 127 | case 6: { 128 | self.container.flexJustifyContent = FLEXBOXJustificationCenter; 129 | self.container.flexAlignItems = FLEXBOXAlignmentCenter; 130 | 131 | for (UIView *v in self.views) { 132 | 133 | v.flexMinimumSize = (CGSize){100, 32}; 134 | v.flexMaximumSize = (CGSize){150, 32}; 135 | } 136 | break; 137 | } 138 | 139 | // fixed size 140 | case 7: { 141 | 142 | for (UIView *v in self.views) { 143 | v.flexFixedSize = CGSizeMake(64, 32); 144 | } 145 | 146 | break; 147 | } 148 | 149 | default: 150 | break; 151 | } 152 | 153 | [UIView animateWithDuration:0.66 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:0 options:0 animations:^{ 154 | 155 | [self.container flexLayoutSubviews]; 156 | //...or just [self.view setNeedsLayout] 157 | 158 | } completion:^(BOOL finished) { 159 | 160 | }]; 161 | 162 | } 163 | 164 | #pragma mark - Test view (No layout logic) 165 | 166 | - (NSArray*)labels 167 | { 168 | return @[@"colum", @"row", @"wrap", @"flex-start", @"flex-end", @"stretch", @"maximum/minimum dimensions", @"fixed"]; 169 | } 170 | 171 | // creates some test views 172 | - (NSArray*)createDummyViews 173 | { 174 | //Dum 175 | NSMutableArray *buttons = @[].mutableCopy; 176 | for (NSUInteger i = 0; i < self.labels.count; i++) { 177 | 178 | UIButton *b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 179 | [b setTitle:self.labels[i] forState:UIControlStateNormal]; 180 | [b setBackgroundColor:@[UIColor.tomatoColor, UIColor.steelBlueColor, UIColor.purpleColor][i%3]]; 181 | [b setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 182 | [b addTarget:self action:@selector(didPressButton:) forControlEvents:UIControlEventTouchUpInside]; 183 | b.layer.cornerRadius = 8; 184 | b.tag = i; 185 | [buttons addObject:b]; 186 | } 187 | 188 | return buttons.copy; 189 | } 190 | 191 | 192 | 193 | @end 194 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/CellDemoTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CellDemoTableViewController.h 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 10/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CellDemoTableViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/CellDemoTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CellDemoTableViewController.m 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 10/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | @import FlexboxKit; 10 | #import "UIColor+Demo.h" 11 | #import "CellDemoTableViewController.h" 12 | #import 13 | 14 | #pragma mark - Cell 15 | 16 | @interface FlexDemoTableViewCell : UITableViewCell 17 | @end 18 | 19 | @implementation FlexDemoTableViewCell 20 | 21 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier 22 | { 23 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 24 | 25 | self.backgroundColor = self.contentView.backgroundColor = UIColor.blackColor; 26 | 27 | // Dummy views (No layout) 28 | UIView *left = [[UIView alloc] initWithFrame:CGRectZero]; 29 | left.backgroundColor = UIColor.tomatoColor; 30 | left.layer.cornerRadius = (self.class.defaultHeight-8)/2; 31 | 32 | UIView *right = [[FLEXBOXContainerView alloc] initWithFrame:CGRectZero]; 33 | right.backgroundColor = UIColor.steelBlueColor; 34 | 35 | UILabel *time = [[UILabel alloc] initWithFrame:CGRectZero]; 36 | time.textColor = [UIColor whiteColor]; 37 | time.font = [UIFont boldSystemFontOfSize:11]; 38 | time.text = @"88:88"; 39 | time.backgroundColor = UIColor.purpleColor; 40 | time.textAlignment = NSTextAlignmentCenter; 41 | 42 | UILabel *title = [[UILabel alloc] initWithFrame:CGRectZero]; 43 | title.textColor = [UIColor whiteColor]; 44 | title.font = [UIFont boldSystemFontOfSize:16]; 45 | title.text = @"Lorem ipsum flexbox"; 46 | 47 | UILabel *caption = [[UILabel alloc] initWithFrame:CGRectZero]; 48 | caption.textColor = [UIColor whiteColor]; 49 | caption.font = [UIFont systemFontOfSize:13]; 50 | caption.text = @"Ex persius officiis appellantur vel, est viris admodum et est viris admodum."; 51 | 52 | 53 | // View hierarchy 54 | [self.contentView addSubview:left]; 55 | [self.contentView addSubview:right]; 56 | [self.contentView addSubview:time]; 57 | [right addSubview:title]; 58 | [right addSubview:caption]; 59 | 60 | 61 | // Flexbox layout 62 | object_setClass(self.contentView, FLEXBOXContainerView.class); 63 | self.contentView.flexDirection = FLEXBOXFlexDirectionRow; 64 | 65 | left.flexFixedSize = (CGSize){(self.class.defaultHeight-8),(self.class.defaultHeight-8)}; 66 | left.flexMargin = (UIEdgeInsets){0,12,0,12}; 67 | left.flexAlignSelf = FLEXBOXAlignmentCenter; 68 | 69 | right.flexContainer = YES; 70 | right.flex = 1; 71 | right.flexDirection = FLEXBOXFlexDirectionColumn; 72 | right.flexJustifyContent = FLEXBOXJustificationCenter; 73 | 74 | time.flexMargin = (UIEdgeInsets){0,12,0,12}; 75 | time.flexPadding = (UIEdgeInsets){4,4,4,4}; 76 | time.flexAlignSelf = FLEXBOXAlignmentCenter; 77 | 78 | title.flexMargin = (UIEdgeInsets){0,12,8,12}; 79 | caption.flexMargin = (UIEdgeInsets){0,12,0,12}; 80 | } 81 | 82 | return self; 83 | } 84 | 85 | + (CGFloat)defaultHeight 86 | { 87 | return 62; 88 | } 89 | 90 | @end 91 | 92 | #pragma mark - ViewController 93 | 94 | 95 | @interface CellDemoTableViewController () 96 | 97 | @end 98 | 99 | @implementation CellDemoTableViewController 100 | 101 | - (void)viewDidLoad 102 | { 103 | [super viewDidLoad]; 104 | 105 | 106 | [self.tableView registerClass:FlexDemoTableViewCell.class forCellReuseIdentifier:@"Cell"]; 107 | self.tableView.delegate = self; 108 | self.tableView.separatorColor = UIColor.clearColor; 109 | self.tableView.backgroundColor = UIColor.blackColor; 110 | 111 | // Uncomment the following line to preserve selection between presentations. 112 | self.clearsSelectionOnViewWillAppear = NO; 113 | 114 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 115 | // self.navigationItem.rightBarButtonItem = self.editButtonItem; 116 | } 117 | 118 | - (void)didReceiveMemoryWarning 119 | { 120 | [super didReceiveMemoryWarning]; 121 | // Dispose of any resources that can be recreated. 122 | } 123 | 124 | #pragma mark - Table view data source 125 | 126 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 127 | { 128 | // Return the number of sections. 129 | return 1; 130 | } 131 | 132 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 133 | { 134 | // Return the number of rows in the section. 135 | return 100; 136 | } 137 | 138 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 139 | { 140 | return [FlexDemoTableViewCell defaultHeight]; 141 | } 142 | 143 | - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 144 | { 145 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 146 | return cell; 147 | } 148 | 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/GridDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GridDemoViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/GridDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #include 10 | #import "UIColor+Demo.h" 11 | #import "GridDemoViewController.h" 12 | @import FlexboxKit; 13 | 14 | @interface GridDemoViewController () 15 | 16 | @property (nonatomic, strong) UIView *firstRow, *secondRow; 17 | @property (nonatomic, strong) NSArray *firstRowViews, *secondRowViews; 18 | 19 | @end 20 | 21 | @implementation GridDemoViewController 22 | 23 | - (void)viewDidLoad 24 | { 25 | [super viewDidLoad]; 26 | 27 | // the flexbox containers 28 | FLEXBOXContainerView *container = [[FLEXBOXContainerView alloc] initWithFrame:self.view.bounds]; 29 | container.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth; 30 | container.backgroundColor = [UIColor darkGrayColor]; 31 | container.flexDirection = FLEXBOXFlexDirectionColumn; 32 | 33 | self.firstRow = [[UIView alloc] initWithFrame:self.view.bounds]; 34 | self.firstRow.layer.borderColor = UIColor.purpleColor.CGColor; 35 | self.firstRow.layer.borderWidth = 4; 36 | self.firstRow.flexContainer = YES; 37 | 38 | self.secondRow = [[UIView alloc] initWithFrame:self.view.bounds]; 39 | self.secondRow.layer.borderColor = UIColor.purpleColor.CGColor; 40 | self.secondRow.layer.borderWidth = 4; 41 | self.secondRow.flexContainer = YES; 42 | 43 | self.firstRowViews = [self createFirstRowViews]; 44 | self.secondRowViews = [self createSecondRowViews]; 45 | 46 | [self.view addSubview:container]; 47 | [container addSubview:self.firstRow]; 48 | [container addSubview:self.secondRow]; 49 | 50 | for (UIView *v in self.firstRowViews) 51 | [self.firstRow addSubview:v]; 52 | 53 | for (UIView *v in self.secondRowViews) 54 | [self.secondRow addSubview:v]; 55 | 56 | [self layout:0]; 57 | } 58 | 59 | - (void)didPressButton:(UIButton*)sender 60 | { 61 | [self layout:sender.tag]; 62 | } 63 | 64 | #pragma mark - Different layouts 65 | 66 | - (void)layout:(NSInteger)index 67 | { 68 | for (FLEXBOXContainerView *c in @[self.firstRow, self.secondRow]) { 69 | c.flexAlignItems = FLEXBOXAlignmentCenter; 70 | c.flexDirection = FLEXBOXFlexDirectionRow; 71 | CGFloat containerGut = 20; 72 | c.flexMargin = (UIEdgeInsets){containerGut, containerGut, containerGut, containerGut};; 73 | } 74 | 75 | NSMutableArray *subviews = [NSMutableArray arrayWithArray:self.firstRowViews]; 76 | [subviews addObjectsFromArray:self.secondRowViews]; 77 | 78 | for (UIView *v in subviews) { 79 | CGFloat gut = 4; 80 | v.flexMargin = (UIEdgeInsets){gut, gut, gut, gut}; 81 | v.flexPadding = (UIEdgeInsets){gut, gut, gut, gut}; 82 | } 83 | 84 | [self.secondRowViews[0] setFlex:0]; 85 | [self.secondRowViews[0] setFlexFixedSize:(CGSize){120,60}]; 86 | 87 | switch (index) { 88 | 89 | case 0: { 90 | [self.firstRowViews[0] setFlex:1.0/2.0]; 91 | [self.firstRowViews[1] setFlex:1.0/6.0]; 92 | [self.firstRowViews[2] setFlex:1.0/6.0]; 93 | [self.firstRowViews[3] setFlex:1.0/6.0]; 94 | break; 95 | } 96 | 97 | case 1: { 98 | [self.firstRowViews[0] setFlex:1.0/2.0]; 99 | [self.firstRowViews[1] setFlex:1.0/2.0]; 100 | [self.firstRowViews[2] setFlex:1.0/8.0]; 101 | [self.firstRowViews[3] setFlex:1.0/8.0]; 102 | break; 103 | } 104 | 105 | case 2: { 106 | [self.firstRowViews[0] setFlex:0.75/4.0]; 107 | [self.firstRowViews[1] setFlex:0.75/4.0]; 108 | [self.firstRowViews[2] setFlex:0.75/4.0]; 109 | [self.firstRowViews[3] setFlex:0]; 110 | break; 111 | } 112 | 113 | case 3: { 114 | [self.firstRowViews[0] setFlex:1]; 115 | [self.firstRowViews[1] setFlex:1]; 116 | [self.firstRowViews[2] setFlex:1]; 117 | [self.firstRowViews[3] setFlex:1]; 118 | break; 119 | } 120 | 121 | default: 122 | break; 123 | } 124 | 125 | [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:0 options:0 animations:^{ 126 | [[self.firstRow superview] flexLayoutSubviews]; 127 | } completion:^(BOOL finished) { }]; 128 | } 129 | 130 | #pragma mark - Test view (No layout logic) 131 | 132 | // creates some test views 133 | - (NSArray*)createFirstRowViews 134 | { 135 | NSArray *labels = @[@"1", @"2", @"3", @"4"]; 136 | 137 | //Dum 138 | NSMutableArray *buttons = @[].mutableCopy; 139 | for (NSUInteger i = 0; i < labels.count; i++) { 140 | 141 | UIButton *b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 142 | [b setTitle:labels[i] forState:UIControlStateNormal]; 143 | [b setBackgroundColor:@[UIColor.tomatoColor, UIColor.steelBlueColor][i%2]]; 144 | [b setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 145 | [b addTarget:self action:@selector(didPressButton:) forControlEvents:UIControlEventTouchUpInside]; 146 | b.layer.cornerRadius = 8; 147 | b.tag = i; 148 | [buttons addObject:b]; 149 | } 150 | 151 | return buttons.copy; 152 | } 153 | 154 | - (NSArray*)createSecondRowViews 155 | { 156 | NSArray *labels = @[@"A fixed size item"]; 157 | 158 | //Dum 159 | NSMutableArray *buttons = @[].mutableCopy; 160 | for (NSUInteger i = 0; i < labels.count; i++) { 161 | 162 | UIButton *b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 163 | [b setTitle:labels[i] forState:UIControlStateNormal]; 164 | [b setBackgroundColor:@[UIColor.tomatoColor, UIColor.steelBlueColor][i%2]]; 165 | [b setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 166 | [b addTarget:self action:@selector(didPressButton:) forControlEvents:UIControlEventTouchUpInside]; 167 | b.layer.cornerRadius = 8; 168 | b.tag = 4; 169 | [buttons addObject:b]; 170 | } 171 | 172 | return buttons.copy; 173 | } 174 | 175 | @end 176 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.flexbox.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/UIColor+Demo.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Demo.h 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 28/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIColor (Demo) 12 | 13 | + (UIColor*)tomatoColor; 14 | + (UIColor*)steelBlueColor; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/UIColor+Demo.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Demo.m 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 28/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import "UIColor+Demo.h" 10 | 11 | @implementation UIColor (Demo) 12 | 13 | + (UIColor*)tomatoColor 14 | { 15 | return [UIColor colorWithRed:255.f/255.f green:99.f/255.f blue:71.f/255.f alpha:1.f]; 16 | } 17 | 18 | + (UIColor*)steelBlueColor 19 | { 20 | return [UIColor colorWithRed:0.f/255.f green:154.f/255.f blue:184.f/255.f alpha:1.f]; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FlexboxKitDemo 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemoTests/FlexboxKitDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FlexboxKitDemoTests.m 3 | // FlexboxKitDemoTests 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface FlexboxKitDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation FlexboxKitDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /FlexboxKitDemo/FlexboxKitDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.flexbox.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /FlexboxKitTests/FlexboxKitTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FlexboxKitTests.m 3 | // FlexboxKitTests 4 | // 5 | // Created by Alex Usbergo on 09/05/15. 6 | // Copyright (c) 2015 Alex Usbergo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface FlexboxKitTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation FlexboxKitTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /FlexboxKitTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.flexbox.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License for ios-flexboxkit software 2 | 3 | Copyright (c) 2015, Alex Usbergo, Inc. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name Facebook nor the names of its contributors may be used to 16 | endorse or promote products derived from this software without specific 17 | prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | 31 | BSD License For css-layout software (included in ios-flexboxkit) 32 | 33 | Copyright (c) 2014, Facebook, Inc. All rights reserved. 34 | 35 | Redistribution and use in source and binary forms, with or without modification, 36 | are permitted provided that the following conditions are met: 37 | 38 | * Redistributions of source code must retain the above copyright notice, this 39 | list of conditions and the following disclaimer. 40 | 41 | * Redistributions in binary form must reproduce the above copyright notice, 42 | this list of conditions and the following disclaimer in the documentation 43 | and/or other materials provided with the distribution. 44 | 45 | * Neither the name Facebook nor the names of its contributors may be used to 46 | endorse or promote products derived from this software without specific 47 | prior written permission. 48 | 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 50 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 51 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 52 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 53 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 54 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 55 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 56 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 58 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlexboxKit 2 | 3 | **Checkout [FlexboxLayout](https://github.com/alexdrone/FlexboxLayout) if you're interested in the Swift port** 4 | 5 | A simple UIKit extension to wrap the flexbox properties in regular *UIView*. This project is based on the robust Facebook's C implementation of Flexbox. 6 | 7 | The goal is to have a small standalone **UIKit** library to layout elements. It doesn't rely on the DOM model at all. 8 | 9 | 10 |

11 | ![Gif](demo.gif) 12 | 13 | 14 | 15 | #Usage 16 | 17 | The easiest way to use the flexbox layout facilities is to instantiate a `FLEXBOXContainerView`, set its flexbox properties (as exposed in the *UIView* category `UIVIew+FLEXBOX`), add all the 18 | subviews you want to it and additionaly set their flex properties. 19 | 20 | If you have subviews which themselves will have subviews that you wish to layout using the flexbox engine, you simply have to set the *UIView* category property `flexContainer` to `YES`, and so on. You can also have nested `FLEXBOXContainerView`s. 21 | 22 | e.g. Given a view (in this case a *UITableViewCell*) with these subviews: 23 | 24 | ```Objective-C 25 | 26 | FLEXBOXContainerView *contentView; 27 | UIView *left, *right; 28 | UILabel *title, *caption; 29 | 30 | ... 31 | 32 | [contentView addSubview:left]; 33 | [contentView addSubview:right]; 34 | [contentView addSubview:time]; 35 | 36 | [right addSubview:title]; 37 | [right addSubview:caption]; 38 | 39 | ``` 40 | 41 | The following flexbox layout code 42 | 43 | ```Objective-C 44 | 45 | contentView.flexDirection = FLEXBOXFlexDirectionRow; 46 | 47 | left.flexFixedSize = (CGSize){A_FIXED_SIZE, A_FIXED_SIZE}; 48 | left.flexMargin = (UIEdgeInsets){SOME_MARGIN, SOME_MARGIN, SOME_MARGIN, SOME_MARGIN}; 49 | left.flexAlignSelf = FLEXBOXAlignmentCenter; 50 | 51 | rigth.flexContainer = YES; 52 | right.flex = 1; 53 | right.flexJustifyContent = FLEXBOXJustificationCenter; 54 | 55 | time.flexMargin = (UIEdgeInsets){SOME_MARGIN, SOME_MARGIN, SOME_MARGIN, SOME_MARGIN}; 56 | time.flexPadding = (UIEdgeInsets){SOME_PADDING, SOME_PADDING, SOME_PADDING, SOME_PADDING}; 57 | time.flexAlignSelf = FLEXBOXAlignmentCenter; 58 | 59 | ``` 60 | Results in: 61 | 62 |

63 | ![Gif](cell-example.png) 64 | 65 | ##Advanced usage 66 | 67 | You can use **FlexboxKit** without using `FLEXBOXContainerView` by simply having a `-[UIView layoutSubviews]` implementation that calls the `-[UIView flexLayoutSubviews]` method defined in the *UIView* category `UIVIew+FLEXBOX`. 68 | 69 | e.g. 70 | 71 | ```Objective-C 72 | 73 | - (void)layoutSubviews 74 | { 75 | [super layoutSubviews]; 76 | [self flexLayoutSubviews]; 77 | } 78 | 79 | 80 | ``` 81 | 82 | If you wish to run the layout engine on a **background thread** you can do so by calling 83 | `[node layoutConstrainedToMaximumWidth:self.bounds.size.width]` in a background thread and then set the computed frames in the main thread. 84 | 85 | e.g. 86 | 87 | ```Objective-C 88 | 89 | - (void)flexLayoutSubviewsInBackground 90 | { 91 | __weak __typeof(self) weakSelf = self; 92 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 93 | 94 | __strong __typeof(self) strongSelf = weakSelf; 95 | 96 | //run the flexbox engine on a backgroun thread... 97 | strongSelf.flexNode.dimensions = strongSelf.bounds.size; 98 | [strongSelf.flexNode layoutConstrainedToMaximumWidth:strongSelf.bounds.size.width]; 99 | 100 | dispatch_async(dispatch_get_main_queue(), ^{ 101 | 102 | //assign the computed frames on the main thread... 103 | for (NSUInteger i = 0; i < strongSelf.flexNode.childrenCountBlock(); i++) { 104 | 105 | UIView *subview = self.subviews[i]; 106 | FLEXBOXNode *subnode = strongSelf.flexNode.childrenAtIndexBlock(i); 107 | subview.frame = CGRectIntegral(subnode.frame); 108 | } 109 | 110 | strongSelf.frame = (CGRect){strongSelf.flexNode.frame.origin, strongSelf.flexNode.frame.size}; 111 | }); 112 | 113 | }); 114 | 115 | } 116 | 117 | ``` 118 | 119 | 120 | # Attribuitions 121 | It uses Facebook's [flexbox implementation][css-layout] and was inspired by Josh Abernathy's 122 | [SwiftBox] and Robert Böhnke's [FLXView]. 123 | 124 | [css-layout]: https://github.com/facebook/css-layout 125 | [swiftbox]: https://github.com/joshaber/SwiftBox 126 | [flxview]: https://github.com/robb/FLXView 127 | -------------------------------------------------------------------------------- /cell-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexdrone/flexboxobjc_deprecated/db7e0dd588ad664d9d239a564219279fe6f05b35/cell-example.png -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexdrone/flexboxobjc_deprecated/db7e0dd588ad664d9d239a564219279fe6f05b35/demo.gif --------------------------------------------------------------------------------