├── DLConstraintLayoutDemo ├── en.lproj │ ├── InfoPlist.strings │ ├── MainStoryboard_iPhone.storyboard │ └── MainStoryboard_iPad.storyboard ├── Default.png ├── Default@2x.png ├── Default-568h@2x.png ├── DLCLAppDelegate.h ├── DLConstraintLayoutDemo-Prefix.pch ├── main.m ├── DLConstraintLayoutDemo-Info.plist └── DLCLAppDelegate.m ├── DLConstraintLayoutTests ├── en.lproj │ └── InfoPlist.strings ├── DLCLConstraintLayoutTests.m └── DLConstraintLayoutTests-Info.plist ├── DLConstraintLayoutDemoOSX ├── en.lproj │ └── InfoPlist.strings ├── DLConstraintLayoutDemoOSX-Prefix.pch ├── main.m ├── DLCLAppDelegate.h ├── DLCLAppDelegate.m └── DLConstraintLayoutDemoOSX-Info.plist ├── DLConstraintLayout ├── DLConstraintLayout-Prefix.pch ├── DLCLConstraintLayoutSolver.h ├── DLConstraintLayout+Protected.h ├── DLCLConstraintLayoutManager.h ├── CALayer+DLConstraintLayout.h ├── DLCLConstraintLayoutNode.h ├── DLConstraintLayout.h ├── DLCLConstraint+Protected.h ├── DLCLConstraint.h ├── DLCLConstraintLayoutNode.m ├── DLCLConstraintLayoutManager.m ├── DLConstraintLayout.m ├── CALayer+DLConstraintLayout.m ├── DLCLConstraint.m ├── DLCLConstraintLayoutSolver.m └── DLCLConstraintLayoutSolver.mm ├── DLConstraintLayout.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── project.pbxproj ├── DLConstraintLayoutDemoShared ├── DLCLViewController.h └── DLCLViewController.m ├── LICENSE └── README.md /DLConstraintLayoutDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /DLConstraintLayoutTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoOSX/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/DLConstraintLayout/HEAD/DLConstraintLayoutDemo/Default.png -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/DLConstraintLayout/HEAD/DLConstraintLayoutDemo/Default@2x.png -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/DLConstraintLayout/HEAD/DLConstraintLayoutDemo/Default-568h@2x.png -------------------------------------------------------------------------------- /DLConstraintLayout/DLConstraintLayout-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'DLConstraintLayout' target in the 'DLConstraintLayout' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /DLConstraintLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoOSX/DLConstraintLayoutDemoOSX-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'DLConstraintLayoutDemoOSX' target in the 'DLConstraintLayoutDemoOSX' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoOSX/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DLConstraintLayoutDemoOSX 4 | // 5 | // Created by Vincent Esche on 3/19/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **)argv); 14 | } 15 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/DLCLAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLAppDelegate.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DLCLAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoOSX/DLCLAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLAppDelegate.h 3 | // DLConstraintLayoutDemoOSX 4 | // 5 | // Created by Vincent Esche on 3/19/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DLCLAppDelegate : NSObject 12 | 13 | @property (assign) IBOutlet NSWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/DLConstraintLayoutDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'DLConstraintLayout' target in the 'DLConstraintLayout' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "DLCLAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([DLCLAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoOSX/DLCLAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLAppDelegate.m 3 | // DLConstraintLayoutDemoOSX 4 | // 5 | // Created by Vincent Esche on 3/19/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLCLAppDelegate.h" 10 | 11 | @implementation DLCLAppDelegate 12 | 13 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 14 | { 15 | // Insert code here to initialize your application 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /DLConstraintLayoutTests/DLCLConstraintLayoutTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutTests.m 3 | // DLCLConstraintLayoutTests 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "DLCLConstraint+Protected.h" 12 | 13 | @interface DLCLConstraintLayoutTests : SenTestCase 14 | 15 | @end 16 | 17 | @implementation DLCLConstraintLayoutTests 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraintLayoutSolver.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutSolver.h 3 | // DLConstraintLayout 4 | // 5 | // Created by vesche on 4/9/13. 6 | // Copyright (c) 2013 Regexident. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class CALayer; 12 | 13 | @interface DLCLConstraintLayoutSolver : NSObject 14 | 15 | @property (readonly, weak, nonatomic) CALayer *layer; 16 | 17 | - (id)initWithLayer:(CALayer *)layer; 18 | + (instancetype)solverWithLayer:(CALayer *)layer; 19 | 20 | - (void)solveLayout; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLConstraintLayout+Protected.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLConstraintLayout+Protected.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLConstraintLayout.h" 10 | 11 | #ifndef DLConstraintLayout_DLConstraintLayout_Protected_h 12 | #define DLConstraintLayout_DLConstraintLayout_Protected_h 13 | 14 | extern NSString * const kDLCAConstraintClassName; 15 | extern NSString * const kDLCAConstraintLayoutManagerClassName; 16 | 17 | BOOL DLCLClassImplementsProtocol(Class aClass, Protocol *aProtocol); 18 | 19 | #endif -------------------------------------------------------------------------------- /DLConstraintLayoutTests/DLConstraintLayoutTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | regexident.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraintLayoutManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutManager.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/14/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol DLCLConstraintLayoutManager 12 | 13 | + (instancetype)layoutManager; 14 | 15 | - (void)invalidateLayoutOfLayer:(CALayer *)layer; 16 | - (void)layoutSublayersOfLayer:(CALayer *)layer; 17 | - (CGSize)preferredSizeOfLayer:(CALayer *)layer; 18 | 19 | @end 20 | 21 | @interface DLCLConstraintLayoutManager : NSObject 22 | 23 | // Looks weird, but just consider all methods in the same named protocol to be listed in here. 24 | // Having them in a protocol makes it easier to dynamically check API compatibility via objc runtime. 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /DLConstraintLayout/CALayer+DLConstraintLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+DLConstraintLayout.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "DLConstraintLayout.h" 12 | 13 | @class DLCLConstraint; 14 | 15 | @protocol CALayer_DLConstraintLayout 16 | 17 | @optional 18 | 19 | - (id)layoutManager; 20 | - (void)setLayoutManager:(id)layoutManager; 21 | 22 | - (NSArray *)constraints; 23 | - (void)setConstraints:(NSArray *)constraints; 24 | 25 | - (void)addConstraint:(DLCLConstraint *)constraint; 26 | 27 | @end 28 | 29 | @interface CALayer (DLConstraintLayout) 30 | 31 | // the methods declared in protocol CALayer_DLCLConstraintLayout get added in category's load method 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoShared/DLCLViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLViewController.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #if TARGET_OS_IPHONE 10 | 11 | #import 12 | 13 | @interface DLCLViewController : UIViewController 14 | 15 | @property (readwrite, strong, nonatomic) IBOutlet UIView *contentView; 16 | @property (readwrite, strong, nonatomic) IBOutlet UISlider *slider; 17 | 18 | #else 19 | 20 | #import 21 | 22 | @interface DLCLViewController : NSViewController 23 | 24 | @property (readwrite, strong, nonatomic) IBOutlet NSView *contentView; 25 | @property (readwrite, strong, nonatomic) IBOutlet NSSlider *slider; 26 | 27 | #endif 28 | 29 | @property (readonly, strong, nonatomic) NSDictionary *layersByName; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraintLayoutNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutNode.h 3 | // DLConstraintLayout 4 | // 5 | // Created by vesche on 4/9/13. 6 | // Copyright (c) 2013 Regexident. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "DLCLConstraint+Protected.h" 12 | 13 | @interface DLCLConstraintLayoutNode : NSObject 14 | 15 | @property (readonly, weak, nonatomic) CALayer *layer; 16 | @property (readonly, assign, nonatomic) DLCLConstraintAxis axis; 17 | @property (readonly, strong, nonatomic) NSSet *constraints; 18 | @property (readonly, strong, nonatomic) NSSet *incoming; 19 | @property (readonly, strong, nonatomic) NSSet *outgoing; 20 | 21 | - (id)initWithAxis:(DLCLConstraintAxis)axis forLayer:(CALayer *)layer; 22 | + (id)nodeWithAxis:(DLCLConstraintAxis)axis forLayer:(CALayer *)layer; 23 | 24 | - (void)addConstraint:(DLCLConstraint *)constraint; 25 | 26 | - (BOOL)hasDependencyTo:(DLCLConstraintLayoutNode *)node; 27 | - (void)addDependencyTo:(DLCLConstraintLayoutNode *)node; 28 | - (void)removeDependencyTo:(DLCLConstraintLayoutNode *)node; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoOSX/DLConstraintLayoutDemoOSX-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | regexident.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2013 Vincent Esche. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLConstraintLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLConstraintLayout.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CALayer+DLConstraintLayout.h" 12 | #import "DLCLConstraint.h" 13 | #import "DLCLConstraintLayoutManager.h" 14 | 15 | #ifndef DLConstraintLayout_DLConstraintLayout_h 16 | #define DLConstraintLayout_DLConstraintLayout_h 17 | 18 | #if defined(DLCL_USE_NATIVE_CA_NAMESPACE) && TARGET_OS_IPHONE 19 | 20 | @compatibility_alias CAConstraint DLCLConstraint; 21 | @compatibility_alias CAConstraintLayoutManager DLCLConstraintLayoutManager; 22 | 23 | typedef DLCLConstraintAttribute CAConstraintAttribute; 24 | 25 | #define kCAConstraintMinX kDLCLConstraintMinX 26 | #define kCAConstraintMidX kDLCLConstraintMidX 27 | #define kCAConstraintMaxX kDLCLConstraintMaxX 28 | #define kCAConstraintWidth kDLCLConstraintWidth 29 | #define kCAConstraintMinY kDLCLConstraintMinY 30 | #define kCAConstraintMidY kDLCLConstraintMidY 31 | #define kCAConstraintMaxY kDLCLConstraintMaxY 32 | #define kCAConstraintHeight kDLCLConstraintHeight 33 | 34 | #endif 35 | 36 | @interface DLConstraintLayout : NSObject 37 | 38 | @end 39 | 40 | #endif 41 | 42 | /* 43 | Important: 44 | You will most likely have to add the "-lc++" linker flag in the loader bundle to have it compile with the CPP-solver enabled. 45 | Further more on iOS you will have to add the "-ObjC" linker flag in the loader bundle for categories to load properly. 46 | */ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Vincent Esche 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | 4. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes code by Vincent Esche." where would be replaced by the name of the specific source-code package being made use of. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/DLConstraintLayoutDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | regexident.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard_iPhone 29 | UIMainStoryboardFile~ipad 30 | MainStoryboard_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraint+Protected.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraint.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/14/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLCLConstraint.h" 10 | 11 | #ifndef DLConstraintLayout_DLCLConstraint_Protected_h 12 | #define DLConstraintLayout_DLCLConstraint_Protected_h 13 | 14 | typedef NS_ENUM(BOOL, DLCLConstraintAxis) { 15 | DLCLConstraintAxisX = 0, 16 | DLCLConstraintAxisY = 1 17 | }; 18 | 19 | typedef NS_ENUM(NSUInteger, DLCLConstraintAxisAttribute) { 20 | DLCLConstraintAxisAttributeMin = 0, 21 | DLCLConstraintAxisAttributeMid = 1, 22 | DLCLConstraintAxisAttributeMax = 2, 23 | DLCLConstraintAxisAttributeSize = 3 24 | }; 25 | 26 | typedef struct { 27 | DLCLConstraintAttribute attribute; 28 | DLCLConstraintAttribute source_attribute; 29 | __unsafe_unretained CALayer *source_layer; 30 | CGFloat scale; 31 | CGFloat offset; 32 | } DLCLConstraintStruct; 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | DLCLConstraintStruct DLCLConstraintStructMake(DLCLConstraintAttribute attribute, DLCLConstraintAttribute source_attribute, CALayer *source_layer, CGFloat scale, CGFloat offset); 39 | 40 | DLCLConstraintAxis DLCLConstraintAttributeGetAxis(DLCLConstraintAttribute attribute); 41 | DLCLConstraintAxisAttribute DLCLConstraintAttributeGetAxisAttribute(DLCLConstraintAttribute attribute); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | @interface DLCLConstraint () 48 | 49 | @property (readonly, assign, nonatomic) DLCLConstraintStruct constraintStruct; 50 | @property (readonly, strong, nonatomic) CALayer *sourceLayer; 51 | 52 | - (CALayer *)detectSourceLayerInSuperlayer:(CALayer *)superlayer; 53 | 54 | - (BOOL)isEqualToConstraint:(DLCLConstraint *)constraint; 55 | 56 | @end 57 | 58 | #endif -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraint.h: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraint.h 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/14/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #ifndef DLConstraintLayout_DLCLConstraint_h 12 | #define DLConstraintLayout_DLCLConstraint_h 13 | 14 | typedef enum : int { 15 | kDLCLConstraintMinX, 16 | kDLCLConstraintMidX, 17 | kDLCLConstraintMaxX, 18 | kDLCLConstraintWidth, 19 | kDLCLConstraintMinY, 20 | kDLCLConstraintMidY, 21 | kDLCLConstraintMaxY, 22 | kDLCLConstraintHeight, 23 | } DLCLConstraintAttribute; 24 | 25 | @protocol DLCLConstraint 26 | 27 | // These must match those from CAConstraint: 28 | // https://developer.apple.com/library/mac/DOCUMENTATION/GraphicsImaging/Reference/CAConstraint_class/Introduction/Introduction.html 29 | @property (readonly) DLCLConstraintAttribute attribute; 30 | @property (readonly) CGFloat offset; 31 | @property (readonly) CGFloat scale; 32 | @property (readonly) DLCLConstraintAttribute sourceAttribute; 33 | @property (readonly) NSString *sourceName; 34 | 35 | + (instancetype)constraintWithAttribute:(DLCLConstraintAttribute)attr relativeTo:(NSString *)srcLayer attribute:(DLCLConstraintAttribute)srcAttr scale:(CGFloat)scale offset:(CGFloat)offset; 36 | + (instancetype)constraintWithAttribute:(DLCLConstraintAttribute)attr relativeTo:(NSString *)srcLayer attribute:(DLCLConstraintAttribute)srcAttr offset:(CGFloat)offset; 37 | + (instancetype)constraintWithAttribute:(DLCLConstraintAttribute)attr relativeTo:(NSString *)srcLayer attribute:(DLCLConstraintAttribute)srcAttr; 38 | - (id)initWithAttribute:(DLCLConstraintAttribute)attr relativeTo:(NSString *)srcLayer attribute:(DLCLConstraintAttribute)srcAttr scale:(CGFloat)scale offset:(CGFloat)offset; 39 | 40 | @end 41 | 42 | @interface DLCLConstraint : NSObject 43 | 44 | // Looks weird, but just consider all methods in the same named protocol to be listed in here. 45 | // Having them in a protocol makes it easier to dynamically check API compatibility via objc runtime. 46 | 47 | @end 48 | 49 | #endif -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/DLCLAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLAppDelegate.m 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLCLAppDelegate.h" 10 | 11 | @implementation DLCLAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 14 | // Override point for customization after application launch. 15 | return YES; 16 | } 17 | 18 | - (void)applicationWillResignActive:(UIApplication *)application { 19 | // 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. 20 | // 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. 21 | } 22 | 23 | - (void)applicationDidEnterBackground:(UIApplication *)application { 24 | // 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. 25 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 26 | } 27 | 28 | - (void)applicationWillEnterForeground:(UIApplication *)application { 29 | // 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. 30 | } 31 | 32 | - (void)applicationDidBecomeActive:(UIApplication *)application { 33 | // 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. 34 | } 35 | 36 | - (void)applicationWillTerminate:(UIApplication *)application { 37 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraintLayoutNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutNode.m 3 | // DLConstraintLayout 4 | // 5 | // Created by vesche on 4/9/13. 6 | // Copyright (c) 2013 Regexident. All rights reserved. 7 | // 8 | 9 | #import "DLCLConstraintLayoutNode.h" 10 | 11 | #import "DLConstraintLayout+Protected.h" 12 | 13 | @interface DLCLConstraintLayoutNode () 14 | 15 | @property (readwrite, weak, nonatomic) CALayer *layer; 16 | @property (readwrite, assign, nonatomic) DLCLConstraintAxis axis; 17 | @property (readwrite, strong, nonatomic) NSMutableSet *mutableConstraints; 18 | @property (readwrite, strong, nonatomic) NSMutableSet *mutableIncoming; 19 | @property (readwrite, strong, nonatomic) NSMutableSet *mutableOutgoing; 20 | 21 | @end 22 | 23 | @implementation DLCLConstraintLayoutNode 24 | 25 | - (id)initWithAxis:(DLCLConstraintAxis)axis forLayer:(CALayer *)layer { 26 | self = [self init]; 27 | if (self) { 28 | self.layer = layer; 29 | self.axis = axis; 30 | self.mutableConstraints = [NSMutableSet set]; 31 | self.mutableIncoming = [NSMutableSet set]; 32 | self.mutableOutgoing = [NSMutableSet set]; 33 | } 34 | return self; 35 | } 36 | 37 | + (id)nodeWithAxis:(DLCLConstraintAxis)axis forLayer:(CALayer *)layer { 38 | return [[self alloc] initWithAxis:axis forLayer:layer]; 39 | } 40 | 41 | - (NSSet *)constraints { 42 | return [NSSet setWithSet:self.mutableConstraints]; 43 | } 44 | 45 | - (void)addConstraint:(DLCLConstraint *)constraint { 46 | [self.mutableConstraints addObject:constraint]; 47 | } 48 | 49 | - (NSSet *)incoming { 50 | return [NSSet setWithSet:self.mutableIncoming]; 51 | } 52 | 53 | - (NSSet *)outgoing { 54 | return [NSSet setWithSet:self.mutableOutgoing]; 55 | } 56 | 57 | - (BOOL)hasDependencyTo:(DLCLConstraintLayoutNode *)node { 58 | BOOL hasDependency = NO; 59 | for (DLCLConstraint *constraint in self.constraints) { 60 | CALayer *sourceLayer = constraint.sourceLayer; 61 | if (sourceLayer != node.layer) { 62 | continue; 63 | } 64 | DLCLConstraintAxis sourceAxis = DLCLConstraintAttributeGetAxis(constraint.sourceAttribute); 65 | for (DLCLConstraint *otherConstraint in self.constraints) { 66 | if (constraint == otherConstraint) { 67 | continue; 68 | } 69 | DLCLConstraintAxis otherAxis = DLCLConstraintAttributeGetAxis(otherConstraint.attribute); 70 | if (sourceAxis == otherAxis) { 71 | hasDependency = YES; 72 | break; 73 | } 74 | } 75 | } 76 | return hasDependency; 77 | } 78 | 79 | - (void)addDependencyTo:(DLCLConstraintLayoutNode *)node{ 80 | NSAssert(node, @"Method argument 'node' must not be nil."); 81 | [self.mutableIncoming addObject:node]; 82 | [node.mutableOutgoing addObject:self]; 83 | } 84 | 85 | - (void)removeDependencyTo:(DLCLConstraintLayoutNode *)node { 86 | NSAssert(node, @"Method argument 'node' must not be nil."); 87 | [self.mutableIncoming removeObject:node]; 88 | [node.mutableOutgoing removeObject:self]; 89 | } 90 | 91 | - (NSString *)description { 92 | NSMutableString *description = [NSMutableString stringWithFormat:@"<%@ %p ", [self class], self]; 93 | [description appendString:@"\nconstraints:\n"]; 94 | [description appendString:[self.constraints description]]; 95 | [description appendString:@"\nincoming:\n"]; 96 | [description appendString:[self.incoming description]]; 97 | [description appendString:@"\noutgoing:\n"]; 98 | [description appendString:[self.outgoing description]]; 99 | [description appendString:@"\n>"]; 100 | return description; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraintLayoutManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutManager.m 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/14/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLCLConstraintLayoutManager.h" 10 | 11 | #import 12 | 13 | #import "CALayer+DLConstraintLayout.h" 14 | #import "DLCLConstraint.h" 15 | #import "DLCLConstraint+Protected.h" 16 | #import "DLConstraintLayout+Protected.h" 17 | 18 | #import "DLCLConstraintLayoutSolver.h" 19 | 20 | @interface DLCLConstraintLayoutManager () 21 | 22 | @property (readwrite, strong, nonatomic) NSMapTable *solversByLayer; 23 | @property (readwrite, strong, nonatomic) NSHashTable *layersNeedingGraphUpdate; 24 | 25 | @end 26 | 27 | @implementation DLCLConstraintLayoutManager 28 | 29 | + (id)alloc { 30 | static BOOL didCheckNativeClass = NO; 31 | static Class nativeClass = Nil; 32 | static BOOL conformsToProtocol = YES; 33 | if (!didCheckNativeClass) { 34 | didCheckNativeClass = YES; 35 | nativeClass = NSClassFromString(kDLCAConstraintLayoutManagerClassName); 36 | conformsToProtocol = nativeClass && DLCLClassImplementsProtocol(nativeClass, @protocol(DLCLConstraintLayoutManager)); 37 | } 38 | return (conformsToProtocol) ? [nativeClass alloc] : [super alloc]; 39 | } 40 | 41 | + (instancetype)layoutManager { 42 | static id instance = nil; 43 | static dispatch_once_t onceToken; 44 | dispatch_once(&onceToken, ^{ 45 | if (!instance) { 46 | instance = [[self alloc] init]; 47 | } 48 | }); 49 | return instance; 50 | } 51 | 52 | - (id)init { 53 | self = [super init]; 54 | if (self) { 55 | self.solversByLayer = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsObjectPointerPersonality]; 56 | } 57 | return self; 58 | } 59 | 60 | - (void)invalidateLayoutOfLayer:(CALayer *)layer { 61 | NSAssert(layer, @"Method argument 'layer' must not be nil."); 62 | [self updateSolverForLayer:layer]; 63 | } 64 | 65 | - (void)layoutSublayersOfLayer:(CALayer *)layer { 66 | NSAssert(layer, @"Method argument 'layer' must not be nil."); 67 | #if defined(DEBUG) && defined(DLCL_BENCHMARK) && DLCL_BENCHMARK > 0 68 | NSUInteger iterations = DLCL_BENCHMARK; 69 | NSDate *startDate = [NSDate date]; 70 | for (NSUInteger iteration = 0; iteration < iterations; iteration++) { 71 | [[self solverForLayer:layer] solveLayout]; 72 | } 73 | NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:startDate]; 74 | NSLog(@"Took %.5f seconds to run %s %d times (@ %.5f seconds each, on average).", interval, __PRETTY_FUNCTION__, iterations, interval / iterations); 75 | #else 76 | [[self solverForLayer:layer] solveLayout]; 77 | #endif 78 | } 79 | 80 | - (CGSize)preferredSizeOfLayer:(CALayer *)layer { 81 | NSAssert(layer, @"Method argument 'layer' must not be nil."); 82 | return layer.bounds.size; 83 | } 84 | 85 | - (void)registerSolverForLayer:(CALayer *)layer { 86 | NSAssert(layer, @"Method argument 'layer' must not be nil."); 87 | [self.solversByLayer setObject:[NSNull null] forKey:layer]; 88 | } 89 | 90 | - (void)unregisterSolverForLayer:(CALayer *)layer { 91 | NSAssert(layer, @"Method argument 'layer' must not be nil."); 92 | [self.solversByLayer removeObjectForKey:layer]; 93 | } 94 | 95 | - (void)updateSolverForLayer:(CALayer *)layer { 96 | [self unregisterSolverForLayer:layer]; 97 | [self registerSolverForLayer:layer]; 98 | } 99 | 100 | - (DLCLConstraintLayoutSolver *)solverForLayer:(CALayer *)layer { 101 | NSAssert(layer, @"Method argument 'layer' must not be nil."); 102 | DLCLConstraintLayoutSolver *solver = [self.solversByLayer objectForKey:layer]; 103 | if (!solver) { 104 | return nil; 105 | } 106 | if ((NSNull *)solver == [NSNull null]) { 107 | solver = [DLCLConstraintLayoutSolver solverWithLayer:layer]; 108 | [self.solversByLayer setObject:solver forKey:layer]; 109 | } 110 | return solver; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLConstraintLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLConstraintLayout.m 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLConstraintLayout.h" 10 | 11 | #import 12 | 13 | NSString * const kDLCAConstraintClassName = @"CAConstraint"; 14 | NSString * const kDLCAConstraintLayoutManagerClassName = @"CAConstraintLayoutManager"; 15 | 16 | BOOL DLCLClassImplementsProtocolProperties(Class aClass, Protocol *aProtocol) { 17 | NSMutableDictionary *propertyAttributesByName = [NSMutableDictionary dictionary]; 18 | BOOL implementsProtocol = YES; 19 | unsigned int classPropertiesCount = 0; 20 | objc_property_t *classProperties = class_copyPropertyList(aClass, &classPropertiesCount); 21 | for (NSUInteger i = 0; i < classPropertiesCount; i++) { 22 | NSString *propertyName = [NSString stringWithCString:property_getName(classProperties[i]) encoding:NSUTF8StringEncoding]; 23 | NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(classProperties[i]) encoding:NSUTF8StringEncoding]; 24 | propertyAttributesByName[propertyName] = propertyAttributes; 25 | } 26 | free(classProperties); 27 | unsigned int protocolPropertiesCount = 0; 28 | objc_property_t *protocolProperties = protocol_copyPropertyList(aProtocol, &protocolPropertiesCount); 29 | for (NSUInteger i = 0; i < protocolPropertiesCount; i++) { 30 | NSString *propertyName = [NSString stringWithCString:property_getName(protocolProperties[i]) encoding:NSUTF8StringEncoding]; 31 | NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(protocolProperties[i]) encoding:NSUTF8StringEncoding]; 32 | if (![propertyAttributesByName[propertyName] isEqualToString:propertyAttributes]) { 33 | NSLog(@"Property '%@' in class '%@' does not match protocol '%@'.", propertyName, NSStringFromClass(aClass), NSStringFromProtocol(aProtocol)); 34 | implementsProtocol = NO; 35 | break; 36 | } 37 | } 38 | free(protocolProperties); 39 | return implementsProtocol; 40 | } 41 | 42 | BOOL DLCLClassImplementsProtocolMethods(Class aClass, Protocol *aProtocol, BOOL isInstanceMethod) { 43 | NSMutableDictionary *methodAttributesByName = [NSMutableDictionary dictionary]; 44 | BOOL implementsProtocol = YES; 45 | unsigned int classMethodsCount = 0; 46 | struct objc_method_description *classMethods = protocol_copyMethodDescriptionList(aProtocol, YES, isInstanceMethod, &classMethodsCount); 47 | for (NSUInteger i = 0; i < classMethodsCount; i++) { 48 | NSString *methodName = NSStringFromSelector(classMethods[i].name); 49 | NSString *methodAttributes = [NSString stringWithCString:classMethods[i].types encoding:NSUTF8StringEncoding]; 50 | methodAttributesByName[methodName] = methodAttributes; 51 | } 52 | free(classMethods); 53 | unsigned int protocolMethodsCount = 0; 54 | struct objc_method_description *protocolMethods = protocol_copyMethodDescriptionList(aProtocol, YES, isInstanceMethod, &protocolMethodsCount); 55 | for (NSUInteger i = 0; i < protocolMethodsCount; i++) { 56 | NSString *methodName = NSStringFromSelector(protocolMethods[i].name); 57 | NSString *methodAttributes = [NSString stringWithCString:protocolMethods[i].types encoding:NSUTF8StringEncoding]; 58 | if (![methodAttributesByName[methodName] isEqualToString:methodAttributes]) { 59 | NSLog(@"Method '%@' in class '%@' does not match protocol '%@'.", methodName, NSStringFromClass(aClass), NSStringFromProtocol(aProtocol)); 60 | implementsProtocol = NO; 61 | break; 62 | } 63 | } 64 | free(protocolMethods); 65 | return implementsProtocol; 66 | } 67 | 68 | BOOL DLCLClassImplementsProtocolClassMethods(Class aClass, Protocol *aProtocol) { 69 | return DLCLClassImplementsProtocolMethods(aClass, aProtocol, NO); 70 | } 71 | 72 | BOOL DLCLClassImplementsProtocolInstanceMethods(Class aClass, Protocol *aProtocol) { 73 | return DLCLClassImplementsProtocolMethods(aClass, aProtocol, YES); 74 | } 75 | 76 | BOOL DLCLClassImplementsProtocol(Class aClass, Protocol *aProtocol) { 77 | BOOL implementsProtocol = YES; 78 | implementsProtocol = implementsProtocol && DLCLClassImplementsProtocolProperties(aClass, aProtocol); 79 | implementsProtocol = implementsProtocol && DLCLClassImplementsProtocolClassMethods(aClass, aProtocol); 80 | implementsProtocol = implementsProtocol && DLCLClassImplementsProtocolInstanceMethods(aClass, aProtocol); 81 | return implementsProtocol; 82 | } 83 | 84 | @implementation DLConstraintLayout 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/en.lproj/MainStoryboard_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemo/en.lproj/MainStoryboard_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DLConstraintLayout [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 2 | 3 | Open Source, **API compatible** replacement of **CAConstraint**/**CAConstraintLayoutManager** for **iOS**. 4 | 5 | While Core Animation `CALayer`s on **OS X** support constraint-based layout handling, **iOS** lacks support for said technology, despite providing it for UIViews. 6 | 7 | **DLConstraintLayout** aims to **fill that gap** by providing **drop-in replacements** for the missing [`CAConstraint`](https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CAConstraint_class/Introduction/Introduction.html)/[`CAConstraintLayoutManager`](https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CAConstraintLayoutManager_class/Introduction/Introduction.html) classes for iOS. 8 | 9 | ## How to use it 10 | 11 | Let's assume for a moment that you have a `CALayer` hierarchy that you want to layout using constraints. 12 | 13 | On **OS X** you'd [end up with layout code](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreAnimation_guide/BuildingaLayerHierarchy/BuildingaLayerHierarchy.html#//apple_ref/doc/uid/TP40004514-CH6-SW2) akin to this: 14 | 15 | CALayer *layer = ...;**** 16 | 17 | layer.layoutManager = [CAConstraintLayoutManager layoutManager]; 18 | 19 | [layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY 20 | relativeTo:@"superlayer" 21 | attribute:kCAConstraintMidY]]; 22 | 23 | Alright, but how about **iOS**? 24 | 25 | Well, all you'd need to do is this: 26 | 27 | 1. Link your project against **libDLConstraintLayout.a** (while keeping [this](http://developer.apple.com/library/mac/#qa/qa1490/_index.html) in mind.). 28 | 2. Add `-ObjC` linker flag to project. 29 | 3. If `DLCL_USE_CPP_SOLVER` is defined (see *"ObjC vs. ObjC++"* discussion below), add `-lc++` linker flag to project. 30 | 2. Add `#import ` to your layout controller's `.m` file. 31 | 3. **Copy & paste** your code that's using **OS X**'s `CAConstraint`s into your iOS project and: 32 | 4. Either: **Replace all occurences** of the `CA` prefix with `DLCL…` (and `kCA…` with `kDLCL…` respectively). (Regex substitution: `s/(?<=\bk?)CA(?=Constraint)/DLCL/g`) 33 | 5. Or: **Add** `-DDLCL_USE_NATIVE_CA_NAMESPACE` to your project's **Other C Flags** and just **use the code and prefixes as is. No changes necessary.** 34 | 35 | The code **stays the same**! 36 | 37 | **That's it.** 38 | 39 | (For more info see the included iOS/OSX demos.) 40 | 41 | ## How it works 42 | 43 | **DLConstraintLayout** makes this all possible by providing the classes `DLCLConstraint` and `DLCLConstraintLayoutManager` as 100% API compatible replacements for their **OS X** counterparts `CAConstraint` and `CAConstraintLayoutManager` respectively. It then utilizes [`@compatibility_alias`](http://developer.apple.com/library/ios/#documentation/DeveloperTools/gcc-4.2.1/gcc/compatibility_005falias.html) and conditional `#define`s in order to allow you to address them the same way you'd do with `CAConstraint` and `CAConstraintLayoutManager` respectively. 44 | 45 | ## iOS API safety 46 | 47 | Before injecting its own layout logic into `CALayer` **DLConstraintLayout** will search for existing `CAConstraint` and `CAConstraintLayoutManager` classes and check them for API compatibility with their respective `DLCL…` counterparts. 48 | 49 | Three scenarios are possible: 50 | 51 | #### Scenario #1: No existing native classes found at runtime 52 | 53 | If there simply exist no native `CAConstraint(LayoutManager)` classes, then **DLConstraintLayout** will just proceed to inject its logic into `CALayer`. 54 | 55 | #### Scenario #2: Existing and API-compatible native classes found at runtime 56 | 57 | If there however exist native `CAConstraint(LayoutManager)` classes and their APIs match those from their respective counterparts in **DLConstraintLayout**, then injection is aborted and the counterparts' `+(id)alloc;` methods instead switch to returning native instances instead. (Which is exactly what you witness when playing with the **DLConstraintLayoutDemoOSX** demo app, btw.) 58 | 59 | #### Scenario #3: Existing but API-incompatible native classes found at runtime 60 | 61 | Last but not least if there exist native `CAConstraint(LayoutManager)` classes and their APIs happen to mismatch (as one cannot foresee if Apple will design constrained `CALayer` layout on iOS the same as on OS X, if ever at all.), then **DLConstraintLayout** will throw a `DLCLConstraintLayoutClassCollision` exception in `CALayer+DLConstraintLayout`'s `+(void)load;` method, terminating the app. 62 | 63 | ## **Objective-C** vs. **Objective-C++** 64 | 65 | **DLConstraintLayout** implements both a **Objective-C**, as well as a **Objective-C++** flavoured layout solver. While both share the very same API and behaviour, benchmarks showed the **Objective-C++** based solver to be (in some cases up to **an order of magnitude**) **faster than** the **Objective-C** one. 66 | 67 | To enable the **Objective-C++** implementation simply define `DLCL_USE_CPP_SOLVER` in the build settings of **libDLConstraintLayout.a** and add the `-lc++` linker flag to the linking project.**** 68 | 69 | ## Demos 70 | 71 | **DLConstraintLayout** contains an **iOS** demo target (**DLConstraintLayoutDemo**) as well as an **OS X** counterpart (**DLConstraintLayoutDemoOSX**) sharing the very same layout code ([`DLCLViewController.m`](https://github.com/regexident/DLConstraintLayout/blob/master/DLConstraintLayoutDemoShared/DLCLViewController.m)). 72 | 73 | ## ARC 74 | 75 | **DLConstraintLayout** uses **automatic reference counting (ARC)**. 76 | 77 | ## Dependencies 78 | 79 | None. 80 | 81 | ## Creator 82 | 83 | Vincent Esche ([@regexident](http://twitter.com/regexident)) 84 | 85 | ## License 86 | 87 | **DLConstraintLayout** is available under a **modified BSD-3 clause license** with the **additional requirement of attribution**. See the `LICENSE` file for more info. 88 | -------------------------------------------------------------------------------- /DLConstraintLayout/CALayer+DLConstraintLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+DLConstraintLayout.m 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "CALayer+DLConstraintLayout.h" 10 | 11 | #import 12 | #import "DLConstraintLayout+Protected.h" 13 | 14 | @interface DLCLConstraintLayoutManager () 15 | 16 | - (void)registerSolverForLayer:(CALayer *)superlayer; 17 | - (void)unregisterSolverForLayer:(CALayer *)superlayer; 18 | - (void)updateSolverForLayer:(CALayer *)layer; 19 | 20 | @end 21 | 22 | void * const kDLCLConstraintLayoutMarkerKey = (void * const) &kDLCLConstraintLayoutMarkerKey; 23 | void * const kDLCLConstraintLayoutManagerKey = (void * const) &kDLCLConstraintLayoutManagerKey; 24 | void * const kDLCLConstraintLayoutConstraintsKey = (void * const) &kDLCLConstraintLayoutConstraintsKey; 25 | 26 | void swizzleOrAddInstanceMethod_dlcl(Class class, SEL selectorA, SEL selectorB) { 27 | Method methodA = class_getInstanceMethod(class, selectorA); 28 | Method methodB = class_getInstanceMethod(class, selectorB); 29 | if (methodA) { 30 | method_exchangeImplementations(methodA, methodB); 31 | } else { 32 | class_addMethod(class, selectorA, class_getMethodImplementation(class, selectorB), method_getTypeEncoding(methodB)); 33 | } 34 | } 35 | 36 | @implementation CALayer (DLConstraintLayout) 37 | 38 | + (void)load { 39 | [CALayer enableConstraintLayout]; 40 | } 41 | 42 | + (BOOL)enableConstraintLayout { 43 | Class constraintClass = NSClassFromString(kDLCAConstraintClassName); 44 | Class constraintLayoutManagerClass = NSClassFromString(kDLCAConstraintLayoutManagerClassName); 45 | BOOL constraintClassImplementsProtocol = constraintClass && DLCLClassImplementsProtocol(constraintClass, @protocol(DLCLConstraint)); 46 | BOOL constraintLayoutManagerClassImplementsProtocol = constraintLayoutManagerClass && DLCLClassImplementsProtocol(constraintLayoutManagerClass, @protocol(DLCLConstraintLayoutManager)); 47 | if (constraintClassImplementsProtocol && constraintLayoutManagerClassImplementsProtocol) { 48 | return NO; 49 | } else if (constraintClass != Nil) { 50 | [[NSException exceptionWithName:@"DLCLConstraintLayoutClassCollision" 51 | reason:@"Found class 'CAConstraint' with incompatible interface." 52 | userInfo:nil] raise]; 53 | } else if (constraintLayoutManagerClass != Nil) { 54 | [[NSException exceptionWithName:@"DLCLConstraintLayoutClassCollision" 55 | reason:@"Found class 'CAConstraintLayoutManager' with incompatible interface." 56 | userInfo:nil] raise]; 57 | } 58 | // NSAssert(!NSClassFromString(@"CAConstraint"), @"Class CAConstraint already exists in runtime."); 59 | // NSAssert(!NSClassFromString(@"CAConstraintLayoutManager"), @"Class CAConstraintLayoutManager already exists in runtime."); 60 | 61 | Class layerClass = [CALayer class]; 62 | 63 | if (objc_getAssociatedObject(layerClass, kDLCLConstraintLayoutMarkerKey)) { 64 | return YES; // Class already swizzled. 65 | } 66 | 67 | // Set swizzling marker. 68 | objc_setAssociatedObject(layerClass, kDLCLConstraintLayoutMarkerKey, @YES, OBJC_ASSOCIATION_ASSIGN); 69 | 70 | // Add constraint layout methods: 71 | swizzleOrAddInstanceMethod_dlcl(layerClass, @selector(layoutManager), @selector(layoutManager_dlcl)); 72 | swizzleOrAddInstanceMethod_dlcl(layerClass, @selector(setLayoutManager:), @selector(setLayoutManager_dlcl:)); 73 | swizzleOrAddInstanceMethod_dlcl(layerClass, @selector(constraints), @selector(constraints_dlcl)); 74 | swizzleOrAddInstanceMethod_dlcl(layerClass, @selector(setConstraints:), @selector(setConstraints_dlcl:)); 75 | swizzleOrAddInstanceMethod_dlcl(layerClass, @selector(addConstraint:), @selector(addConstraint_dlcl:)); 76 | 77 | // Swizzle custom layout method: 78 | swizzleOrAddInstanceMethod_dlcl(layerClass, @selector(layoutSublayers), @selector(layoutSublayers_dlcl)); 79 | 80 | #if defined(DLCL_USE_CPP_SOLVER) && defined(DEBUG) 81 | NSLog(@"Objective-C++ constraint layout solver enabled."); 82 | #elif defined(DEBUG) 83 | NSLog(@"Objective-C constraint layout solver enabled."); 84 | #endif 85 | 86 | return YES; 87 | } 88 | 89 | - (id)layoutManager_dlcl { 90 | return objc_getAssociatedObject(self, kDLCLConstraintLayoutManagerKey); 91 | } 92 | 93 | - (void)setLayoutManager_dlcl:(id)layoutManager { 94 | if (layoutManager) { 95 | [(DLCLConstraintLayoutManager *)layoutManager registerSolverForLayer:self]; 96 | } else { 97 | [(DLCLConstraintLayoutManager *)layoutManager unregisterSolverForLayer:self]; 98 | } 99 | objc_setAssociatedObject(self, kDLCLConstraintLayoutManagerKey, layoutManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 100 | [self setNeedsLayout]; 101 | } 102 | 103 | - (NSArray *)constraints_dlcl { 104 | NSMutableSet *constraintsSet = objc_getAssociatedObject(self, kDLCLConstraintLayoutConstraintsKey); 105 | return (constraintsSet) ? [constraintsSet allObjects] : @[]; 106 | } 107 | 108 | - (void)setConstraints_dlcl:(NSArray *)constraints { 109 | NSMutableSet *constraintsSet = [NSMutableSet setWithArray:constraints]; 110 | objc_setAssociatedObject(self, kDLCLConstraintLayoutConstraintsKey, constraintsSet, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 111 | [self.layoutManager updateSolverForLayer:self.superlayer]; 112 | [self.superlayer setNeedsLayout]; 113 | } 114 | 115 | - (void)addConstraint_dlcl:(DLCLConstraint *)constraint { 116 | NSAssert(constraint, @"Method argument constraint must not be nil."); 117 | NSMutableSet *constraintsSet = objc_getAssociatedObject(self, kDLCLConstraintLayoutConstraintsKey); 118 | [self willChangeValueForKey:@"constraints"]; 119 | if (!constraintsSet) { 120 | constraintsSet = [NSMutableSet set]; 121 | objc_setAssociatedObject(self, kDLCLConstraintLayoutConstraintsKey, constraintsSet, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 122 | } 123 | [constraintsSet addObject:constraint]; 124 | [self didChangeValueForKey:@"constraints"]; 125 | [self.layoutManager updateSolverForLayer:self.superlayer]; 126 | [self.superlayer setNeedsLayout]; 127 | } 128 | 129 | - (void)layoutSublayers_dlcl { 130 | [self layoutSublayers_dlcl]; // calls original implementation after swizzling 131 | [self.layoutManager layoutSublayersOfLayer:self]; 132 | } 133 | 134 | @end -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraint.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraint.m 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/14/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLCLConstraint.h" 10 | #import "DLCLConstraint+Protected.h" 11 | 12 | #import "DLConstraintLayout+Protected.h" 13 | 14 | DLCLConstraintStruct DLCLConstraintStructMake(DLCLConstraintAttribute attribute, DLCLConstraintAttribute source_attribute, CALayer *source_layer, CGFloat scale, CGFloat offset) { 15 | return (DLCLConstraintStruct){attribute, source_attribute, source_layer, scale, offset}; 16 | } 17 | 18 | DLCLConstraintAxis DLCLConstraintAttributeGetAxis(DLCLConstraintAttribute attribute) { 19 | return (attribute <= kDLCLConstraintWidth) ? DLCLConstraintAxisX : DLCLConstraintAxisY; 20 | } 21 | 22 | DLCLConstraintAxisAttribute DLCLConstraintAttributeGetAxisAttribute(DLCLConstraintAttribute attribute) { 23 | DLCLConstraintAxis axis = DLCLConstraintAttributeGetAxis(attribute); 24 | return (DLCLConstraintAxisAttribute)((axis == DLCLConstraintAxisX) ? attribute : attribute - 4); 25 | } 26 | 27 | NSString *DLCLConstraintAttributeMaskDescription(int attributeMask) { 28 | NSString *strings[] = {@"minX", @"midX", @"maxX", @"width", @"minY", @"midY", @"maxY", @"height"}; 29 | NSMutableArray *attributeValues = [NSMutableArray array]; 30 | int i = 0; 31 | for (int z = 128; z > 0; z >>= 1, i++) { 32 | BOOL isSetBit = (attributeMask & z) == z; 33 | if (isSetBit) { 34 | [attributeValues insertObject:strings[7 - i] atIndex:0]; 35 | } 36 | } 37 | return [NSString stringWithFormat:@"{%@}", [attributeValues componentsJoinedByString:@", "]]; 38 | } 39 | 40 | @interface DLCLConstraint () 41 | 42 | @property (readwrite, copy, nonatomic) NSString *sourceName; 43 | 44 | @end 45 | 46 | @implementation DLCLConstraint 47 | 48 | + (instancetype)constraintWithAttribute:(DLCLConstraintAttribute)attribute relativeTo:(NSString *)sourceLayer attribute:(DLCLConstraintAttribute)sourceAttribute scale:(CGFloat)scale offset:(CGFloat)offset { 49 | return [(DLCLConstraint *)[self alloc] initWithAttribute:attribute 50 | relativeTo:sourceLayer 51 | attribute:sourceAttribute 52 | scale:scale 53 | offset:offset]; 54 | } 55 | 56 | + (instancetype)constraintWithAttribute:(DLCLConstraintAttribute)attribute relativeTo:(NSString *)sourceLayer attribute:(DLCLConstraintAttribute)sourceAttribute offset:(CGFloat)offset { 57 | return [(DLCLConstraint *)[self alloc] initWithAttribute:attribute 58 | relativeTo:sourceLayer 59 | attribute:sourceAttribute 60 | scale:1.0 61 | offset:offset]; 62 | } 63 | 64 | + (instancetype)constraintWithAttribute:(DLCLConstraintAttribute)attribute relativeTo:(NSString *)sourceLayer attribute:(DLCLConstraintAttribute)sourceAttribute { 65 | return [(DLCLConstraint *)[self alloc] initWithAttribute:attribute 66 | relativeTo:sourceLayer 67 | attribute:sourceAttribute 68 | scale:1.0 69 | offset:0.0]; 70 | } 71 | 72 | + (id)alloc { 73 | static BOOL didCheckNativeClass = NO; 74 | static Class nativeClass = Nil; 75 | static BOOL conformsToProtocol = YES; 76 | if (!didCheckNativeClass) { 77 | didCheckNativeClass = YES; 78 | nativeClass = NSClassFromString(kDLCAConstraintClassName); 79 | conformsToProtocol = nativeClass && DLCLClassImplementsProtocol(nativeClass, @protocol(DLCLConstraint)); 80 | } 81 | return (conformsToProtocol) ? [nativeClass alloc] : [super alloc]; 82 | } 83 | 84 | - (id)initWithAttribute:(DLCLConstraintAttribute)attribute relativeTo:(NSString *)sourceLayer attribute:(DLCLConstraintAttribute)sourceAttribute scale:(CGFloat)scale offset:(CGFloat)offset { 85 | NSAssert(attribute >= kDLCLConstraintMinX && attribute <= kDLCLConstraintHeight, @"Method argument 'attribute' must be of known value."); 86 | NSAssert(sourceAttribute >= kDLCLConstraintMinX && sourceAttribute <= kDLCLConstraintHeight, @"Method argument 'sourceAttribute' must be of known value."); 87 | self = [self init]; 88 | if (self) { 89 | self.constraintStruct = DLCLConstraintStructMake(attribute, sourceAttribute, nil, scale, offset); 90 | self.sourceName = sourceLayer; 91 | } 92 | return self; 93 | } 94 | 95 | - (void)setConstraintStruct:(DLCLConstraintStruct)constraintStruct { 96 | _constraintStruct = constraintStruct; 97 | } 98 | 99 | - (DLCLConstraintAttribute)attribute { 100 | return self.constraintStruct.attribute; 101 | } 102 | 103 | - (CGFloat)offset { 104 | return self.constraintStruct.offset; 105 | } 106 | 107 | - (CGFloat)scale { 108 | return self.constraintStruct.scale; 109 | } 110 | 111 | - (DLCLConstraintAttribute)sourceAttribute { 112 | return self.constraintStruct.source_attribute; 113 | } 114 | 115 | - (BOOL)isEqualToConstraint:(DLCLConstraint *)constraint { 116 | return (self.attribute == constraint.attribute && 117 | self.offset == constraint.offset && 118 | self.scale == constraint.scale && 119 | self.sourceAttribute == constraint.sourceAttribute && 120 | [self.sourceName isEqualToString:constraint.sourceName]); 121 | } 122 | 123 | - (BOOL)isEqual:(id)object { 124 | if (![object isMemberOfClass:[self class]]) { 125 | return NO; 126 | } 127 | return [self isEqualToConstraint:(DLCLConstraint *)object]; 128 | } 129 | 130 | - (CALayer *)sourceLayer { 131 | return self.constraintStruct.source_layer; 132 | } 133 | 134 | - (CALayer *)detectSourceLayerInSuperlayer:(CALayer *)superlayer { 135 | CALayer *sourceLayer = [self sourceLayerInSuperlayer:superlayer]; 136 | DLCLConstraintStruct constraintStruct = self.constraintStruct; 137 | constraintStruct.source_layer = sourceLayer; 138 | self.constraintStruct = constraintStruct; 139 | return sourceLayer; 140 | } 141 | 142 | - (CALayer *)sourceLayerInSuperlayer:(CALayer *)superlayer { 143 | NSString *sourceName = self.sourceName; 144 | if (!sourceName || [sourceName isEqualToString:@"superlayer"]) { 145 | return superlayer; 146 | } 147 | CALayer *sourceLayer = nil; 148 | for (CALayer *sublayer in superlayer.sublayers) { 149 | if ([sublayer.name isEqualToString:sourceName]) { 150 | sourceLayer = sublayer; 151 | break; 152 | } 153 | } 154 | return sourceLayer; 155 | } 156 | 157 | - (NSUInteger)hash { 158 | return ((NSUInteger)self.attribute ^ (NSUInteger)self.offset ^ (NSUInteger)self.scale ^ (NSUInteger)self.sourceAttribute ^ [self.sourceName hash]); 159 | } 160 | 161 | - (NSString *)description { 162 | NSString *attributes[] = {@"minX", @"midX", @"maxX", @"width", @"minY", @"midY", @"maxY", @"height"}; 163 | return [NSString stringWithFormat:@"<%@ %p attribute:%@ sourceAttribute:%@ offset:%.2f scale:%.2f sourceName:%@>", 164 | [self class], 165 | self, 166 | attributes[self.attribute], 167 | attributes[self.sourceAttribute], 168 | self.offset, 169 | self.scale, 170 | self.sourceName]; 171 | } 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraintLayoutSolver.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutSolver.m 3 | // DLConstraintLayout 4 | // 5 | // Created by vesche on 4/9/13. 6 | // Copyright (c) 2013 Regexident. All rights reserved. 7 | // 8 | 9 | #import "DLCLConstraintLayoutSolver.h" 10 | 11 | #import 12 | 13 | #import "DLConstraintLayout+Protected.h" 14 | #import "DLCLConstraintLayoutNode.h" 15 | #import "CALayer+DLConstraintLayout.h" 16 | 17 | @interface DLCLConstraintLayoutSolver () 18 | 19 | @property (readwrite, weak, nonatomic) CALayer *layer; 20 | @property (readwrite, strong, nonatomic) NSMutableArray *nodes; 21 | 22 | @end 23 | 24 | @implementation DLCLConstraintLayoutSolver 25 | 26 | - (id)initWithLayer:(CALayer *)layer { 27 | self = [self init]; 28 | if (self) { 29 | self.layer = layer; 30 | self.nodes = [NSMutableArray array]; 31 | 32 | [self generateNodesForLayer:self.layer]; 33 | [self addNodeDependencies]; 34 | [self sortNodesTopologically]; 35 | BOOL validLayout = [self validateSortedNodes]; 36 | NSAssert(validLayout, @"Circle detected. Constraint dependencies must not form cycles."); 37 | } 38 | return self; 39 | } 40 | 41 | + (instancetype)solverWithLayer:(CALayer *)layer { 42 | return [[self alloc] initWithLayer:layer]; 43 | } 44 | 45 | - (void)solveLayout { 46 | CALayer *superlayer = self.layer; 47 | for (DLCLConstraintLayoutNode *node in self.nodes) { 48 | [self solveNode:node inSuperlayer:superlayer]; 49 | } 50 | } 51 | 52 | - (void)generateNodesForLayer:(CALayer *)layer { 53 | [self.nodes removeAllObjects]; 54 | for (CALayer *sublayer in layer.sublayers) { 55 | DLCLConstraintLayoutNode *axisNodes[] = { 56 | [DLCLConstraintLayoutNode nodeWithAxis:DLCLConstraintAxisX forLayer:sublayer], 57 | [DLCLConstraintLayoutNode nodeWithAxis:DLCLConstraintAxisY forLayer:sublayer] 58 | }; 59 | for (DLCLConstraint *constraint in sublayer.constraints) { 60 | DLCLConstraintAxis axis = DLCLConstraintAttributeGetAxis(constraint.attribute); 61 | [axisNodes[axis] addConstraint:constraint]; 62 | } 63 | if ([axisNodes[DLCLConstraintAxisX].constraints count]) { 64 | [self.nodes addObject:axisNodes[DLCLConstraintAxisX]]; 65 | } 66 | if ([axisNodes[DLCLConstraintAxisY].constraints count]) { 67 | [self.nodes addObject:axisNodes[DLCLConstraintAxisY]]; 68 | } 69 | } 70 | } 71 | 72 | - (void)addNodeDependencies { 73 | NSMutableDictionary *nodesByAxis[] = { 74 | [NSMutableDictionary dictionary], 75 | [NSMutableDictionary dictionary] 76 | }; 77 | // Create lookup dictionaries: 78 | for (DLCLConstraintLayoutNode *node in self.nodes) { 79 | NSMutableDictionary *nodesByLayer = nodesByAxis[node.axis]; 80 | NSValue *pointerValue = [NSValue valueWithPointer:(void *)node.layer]; 81 | NSMutableSet *nodes = nodesByLayer[pointerValue]; 82 | if (!nodes) { 83 | nodes = [NSMutableSet set]; 84 | nodesByLayer[pointerValue] = nodes; 85 | } 86 | [nodes addObject:node]; 87 | } 88 | for (DLCLConstraintLayoutNode *node in self.nodes) { 89 | CALayer *superlayer = node.layer.superlayer; 90 | for (DLCLConstraint *constraint in node.constraints) { 91 | CALayer *sourceLayer = [constraint detectSourceLayerInSuperlayer:superlayer]; 92 | if (!sourceLayer) { 93 | continue; 94 | } 95 | DLCLConstraintAxis sourceAxis = DLCLConstraintAttributeGetAxis(constraint.sourceAttribute); 96 | NSMutableDictionary *nodesByLayer = nodesByAxis[sourceAxis]; 97 | NSMutableArray *sourceNodes = [nodesByLayer objectForKey:[NSValue valueWithPointer:(void *)sourceLayer]]; 98 | for (DLCLConstraintLayoutNode *sourceNode in sourceNodes) { 99 | if ([node hasDependencyTo:sourceNode]) { 100 | [node addDependencyTo:sourceNode]; 101 | } 102 | } 103 | } 104 | } 105 | } 106 | 107 | - (void)sortNodesTopologically { 108 | NSArray *nodes = [NSArray arrayWithArray:self.nodes]; 109 | [self.nodes removeAllObjects]; 110 | NSMutableArray *queue = [NSMutableArray array]; 111 | for (DLCLConstraintLayoutNode *node in nodes) { 112 | if (![node.incoming count]) { 113 | [queue addObject:node]; 114 | } 115 | } 116 | while ([queue count]) { 117 | DLCLConstraintLayoutNode *node = queue[0]; 118 | [queue removeObjectAtIndex:0]; 119 | [self.nodes addObject:node]; 120 | for (DLCLConstraintLayoutNode *outgoingNode in [NSSet setWithSet:node.outgoing]) { 121 | [outgoingNode removeDependencyTo:node]; 122 | if (![outgoingNode.incoming count]) { 123 | [queue addObject:outgoingNode]; 124 | } 125 | } 126 | } 127 | } 128 | 129 | - (BOOL)validateSortedNodes { 130 | for (DLCLConstraintLayoutNode *node in self.nodes) { 131 | if ([node.outgoing count] || [node.incoming count]) { 132 | return NO; 133 | } 134 | } 135 | return YES; 136 | } 137 | 138 | - (void)solveNode:(DLCLConstraintLayoutNode *)node inSuperlayer:(CALayer *)superlayer { 139 | CALayer *layer = node.layer; 140 | if (!layer) { 141 | return; 142 | } 143 | CGRect frame = layer.frame; 144 | NSMutableDictionary *sourceValuesByAxisAttribute = [NSMutableDictionary dictionary]; 145 | int axisAttributesMask = 0x0; 146 | for (DLCLConstraint *constraint in node.constraints) { 147 | DLCLConstraintAttribute attribute = constraint.attribute; 148 | DLCLConstraintAttribute sourceAttribute = constraint.sourceAttribute; 149 | DLCLConstraintAxisAttribute axisAttribute = DLCLConstraintAttributeGetAxisAttribute(attribute); 150 | CALayer *sourceLayer = constraint.sourceLayer; 151 | if (!sourceLayer) { 152 | continue; 153 | } 154 | axisAttributesMask |= (0x1 << (int)axisAttribute); 155 | CGRect sourceFrame = sourceLayer.frame; 156 | typedef CGFloat DLCLRectFunction(CGRect rect); 157 | DLCLRectFunction *rectFunctions[] = { 158 | &CGRectGetMinX, &CGRectGetMidX, &CGRectGetMaxX, &CGRectGetWidth, 159 | &CGRectGetMinY, &CGRectGetMidY, &CGRectGetMaxY, &CGRectGetHeight 160 | }; 161 | CGFloat sourceAttributeValue = rectFunctions[sourceAttribute](sourceFrame); 162 | sourceValuesByAxisAttribute[@((int)axisAttribute)] = @((sourceAttributeValue * constraint.scale) + constraint.offset); 163 | } 164 | layer.frame = [[self class] frame:(CGRect)frame afterSettingAttributeValues:sourceValuesByAxisAttribute onAxis:node.axis forMask:axisAttributesMask]; 165 | } 166 | 167 | + (CGRect)frame:(CGRect)frame afterSettingAttributeValues:(NSDictionary *)attributeValues onAxis:(DLCLConstraintAxis)axis forMask:(int)axisAttributesMask { 168 | NSNumber *minKey = @((int)DLCLConstraintAxisAttributeMin); 169 | NSNumber *midKey = @((int)DLCLConstraintAxisAttributeMid); 170 | NSNumber *maxKey = @((int)DLCLConstraintAxisAttributeMax); 171 | NSNumber *sizeKey = @((int)DLCLConstraintAxisAttributeSize); 172 | CGFloat minValue = (axis == DLCLConstraintAxisX) ? CGRectGetMinX(frame) : CGRectGetMinY(frame); 173 | CGFloat sizeValue = (axis == DLCLConstraintAxisX) ? CGRectGetWidth(frame) : CGRectGetHeight(frame); 174 | 175 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMin)) { 176 | minValue = [attributeValues[minKey] doubleValue]; // min 177 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMid)) { // min & mid 178 | sizeValue = ([attributeValues[midKey] doubleValue] - minValue) * 2; 179 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { // min & max 180 | sizeValue = ([attributeValues[maxKey] doubleValue] - minValue); 181 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeSize)) { // min & size 182 | sizeValue = [attributeValues[sizeKey] doubleValue]; 183 | } 184 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeSize)) { 185 | sizeValue = [attributeValues[sizeKey] doubleValue]; // size 186 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMid)) { // size & mid 187 | minValue = [attributeValues[midKey] doubleValue] - (sizeValue / 2); 188 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { // size & max 189 | minValue = [attributeValues[maxKey] doubleValue] - sizeValue; 190 | } 191 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMid)) { 192 | minValue = [attributeValues[midKey] doubleValue] - (sizeValue / 2); // mid 193 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { // mid & max 194 | sizeValue = ([attributeValues[maxKey] doubleValue] - [attributeValues[midKey] doubleValue]) * 2; 195 | minValue = [attributeValues[maxKey] doubleValue] - sizeValue; 196 | } 197 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { 198 | minValue = [attributeValues[maxKey] doubleValue] - sizeValue; // max 199 | } 200 | if (axis == DLCLConstraintAxisX) { 201 | frame.origin.x = minValue; 202 | frame.size.width = sizeValue; 203 | } else { 204 | frame.origin.y = minValue; 205 | frame.size.height = sizeValue; 206 | } 207 | return frame; 208 | } 209 | 210 | @end 211 | -------------------------------------------------------------------------------- /DLConstraintLayoutDemoShared/DLCLViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLViewController.m 3 | // DLConstraintLayout 4 | // 5 | // Created by Vincent Esche on 3/13/13. 6 | // Copyright (c) 2013 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import "DLCLViewController.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | 13 | #import 14 | 15 | #else 16 | 17 | #import "DLConstraintLayout.h" 18 | #import 19 | 20 | #endif 21 | 22 | NSString * const kSuperName = @"superlayer"; 23 | NSString * const kCenterName = @"center"; 24 | NSString * const kTopName = @"top"; 25 | NSString * const kBottomName = @"bottom"; 26 | NSString * const kLeftName = @"left"; 27 | NSString * const kRightName = @"right"; 28 | NSString * const kTopLeftName = @"topLeft"; 29 | NSString * const kTopRightName = @"topRight"; 30 | NSString * const kBottomLeftName = @"bottomLeft"; 31 | NSString * const kBottomRightName = @"bottomRight"; 32 | 33 | void DLCLConstrainLayer(CALayer *layer, CAConstraintAttribute attr, NSString *source, CAConstraintAttribute sourceAttr) { 34 | [layer addConstraint:[CAConstraint constraintWithAttribute:attr relativeTo:source attribute:sourceAttr]]; 35 | } 36 | 37 | @interface DLCLViewController () 38 | 39 | @property (readwrite, strong, nonatomic) NSDictionary *layersByName; 40 | 41 | @end 42 | 43 | @implementation DLCLViewController 44 | 45 | - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle { 46 | self = [super initWithNibName:nibName bundle:nibBundle]; 47 | if (self) { 48 | self.layersByName = [[self class] layersByName]; 49 | } 50 | return self; 51 | } 52 | 53 | - (id)initWithCoder:(NSCoder *)aDecoder { 54 | self = [super initWithCoder:aDecoder]; 55 | if (self) { 56 | self.layersByName = [[self class] layersByName]; 57 | } 58 | return self; 59 | } 60 | 61 | + (NSDictionary *)layersByName { 62 | static NSDictionary *layers = nil; 63 | layers = @{ 64 | kCenterName : [[self class] layerWithName:kCenterName hue:0.0 saturation:0.0 brightness:0.5], 65 | kTopLeftName : [[self class] layerWithName:kTopLeftName hue:0.888 saturation:0.885 brightness:0.988], 66 | kTopName : [[self class] layerWithName:kTopName hue:0.990 saturation:0.948 brightness:0.988], 67 | kTopRightName : [[self class] layerWithName:kTopRightName hue:0.082 saturation:0.854 brightness:0.992], 68 | kRightName : [[self class] layerWithName:kRightName hue:0.126 saturation:0.815 brightness:0.996], 69 | kBottomRightName : [[self class] layerWithName:kBottomRightName hue:0.206 saturation:0.794 brightness:0.992], 70 | kBottomName : [[self class] layerWithName:kBottomName hue:0.338 saturation:0.771 brightness:0.804], 71 | kBottomLeftName : [[self class] layerWithName:kBottomLeftName hue:0.591 saturation:0.917 brightness:0.949], 72 | kLeftName : [[self class] layerWithName:kLeftName hue:0.676 saturation:0.870 brightness:0.784] 73 | }; 74 | return layers; 75 | } 76 | 77 | + (CALayer *)layerWithName:(NSString *)name hue:(CGFloat)hue saturation:(CGFloat)saturation brightness:(CGFloat)brightness { 78 | CAGradientLayer *layer = [CAGradientLayer layer]; 79 | 80 | #if TARGET_OS_IPHONE 81 | UIColor *whiteColor = [UIColor colorWithWhite:1.0 alpha:1.0]; 82 | UIColor *blackColor = [UIColor colorWithWhite:0.0 alpha:1.0]; 83 | layer.startPoint = CGPointMake(0.5, 0.0); 84 | layer.endPoint = CGPointMake(0.5, 1.0); 85 | layer.backgroundColor = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0].CGColor; 86 | layer.borderColor = [UIColor colorWithHue:hue saturation:saturation brightness:brightness * 0.75 alpha:1.0].CGColor; 87 | #else 88 | NSColor *whiteColor = [NSColor colorWithCalibratedWhite:1.0 alpha:1.0]; 89 | NSColor *blackColor = [NSColor colorWithCalibratedWhite:0.0 alpha:1.0]; 90 | layer.startPoint = CGPointMake(0.5, 1.0); 91 | layer.endPoint = CGPointMake(0.5, 0.0); 92 | layer.backgroundColor = [NSColor colorWithCalibratedHue:hue saturation:saturation brightness:brightness alpha:1.0].CGColor; 93 | layer.borderColor = [NSColor colorWithCalibratedHue:hue saturation:saturation brightness:brightness * 0.75 alpha:1.0].CGColor; 94 | #endif 95 | layer.borderWidth = 1.0; 96 | layer.cornerRadius = 5.0; 97 | layer.colors = @[ 98 | (id)[whiteColor colorWithAlphaComponent:0.5].CGColor, 99 | (id)[whiteColor colorWithAlphaComponent:0.1].CGColor, 100 | (id)[blackColor colorWithAlphaComponent:0.0].CGColor, 101 | (id)[blackColor colorWithAlphaComponent:0.1].CGColor 102 | ]; 103 | layer.locations = @[@0.0, @0.5, @0.51, @1.0]; 104 | layer.name = name; 105 | return layer; 106 | } 107 | 108 | #if TARGET_OS_IPHONE 109 | 110 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation; { 111 | return YES; 112 | } 113 | 114 | - (void)viewDidLoad { 115 | [super viewDidLoad]; 116 | [self setupView]; 117 | [self setupSuperlayer:self.contentView.layer]; 118 | } 119 | 120 | #else 121 | 122 | - (void)setView:(NSView *)view { 123 | [super setView:view]; 124 | [self setupView]; 125 | } 126 | 127 | - (void)loadView { 128 | [super loadView]; 129 | [self setupView]; 130 | } 131 | 132 | #endif 133 | 134 | - (void)setupView { 135 | CGFloat centerWidth = 100.0; 136 | CGFloat centerHeight = 50.0; 137 | 138 | #if TARGET_OS_IPHONE 139 | self.view.layer.backgroundColor = [UIColor lightGrayColor].CGColor; 140 | self.slider.value = centerHeight; 141 | #else 142 | self.contentView.layer = [CALayer layer]; 143 | self.contentView.wantsLayer = YES; 144 | 145 | self.view.layer = [CALayer layer]; 146 | self.view.wantsLayer = YES; 147 | self.view.layer.backgroundColor = [NSColor lightGrayColor].CGColor; 148 | self.slider.doubleValue = centerHeight; 149 | #endif 150 | 151 | CALayer *center = self.layersByName[kCenterName]; 152 | center.frame = CGRectMake(0.0, 0.0, centerWidth, centerHeight); 153 | 154 | [self setupSuperlayer:self.contentView.layer]; 155 | } 156 | 157 | - (void)setupSuperlayer:(CALayer *)superlayer { 158 | superlayer.name = @"super"; 159 | 160 | superlayer.actions = @{@"sublayers" : [NSNull null]}; 161 | 162 | CAConstraintLayoutManager *layoutManager = [CAConstraintLayoutManager layoutManager]; 163 | 164 | NSDictionary *layersByName = self.layersByName; 165 | 166 | #if TARGET_OS_IPHONE 167 | CGFloat topOffset = 10.0; 168 | #else 169 | CGFloat topOffset = 0.0; 170 | #endif 171 | 172 | CALayer *center = layersByName[kCenterName]; 173 | [center addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY relativeTo:kSuperName attribute:kCAConstraintMidY]]; 174 | [center addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:kSuperName attribute:kCAConstraintMidX]]; 175 | [superlayer addSublayer:center]; 176 | 177 | CALayer *topLeft = self.layersByName[kTopLeftName]; 178 | [topLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:kLeftName attribute:kCAConstraintWidth]]; 179 | [topLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:kLeftName attribute:kCAConstraintMidX]]; 180 | [topLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:kLeftName attribute:kCAConstraintMinY offset:-10]]; 181 | [topLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:kSuperName attribute:kCAConstraintMinY offset:10 + topOffset]]; 182 | [superlayer addSublayer:topLeft]; 183 | 184 | CALayer *top = layersByName[kTopName]; 185 | [top addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:kCenterName attribute:kCAConstraintWidth]]; 186 | [top addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:kCenterName attribute:kCAConstraintMidX]]; 187 | [top addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:kCenterName attribute:kCAConstraintMinY offset:-10.0]]; 188 | [top addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:kSuperName attribute:kCAConstraintMinY offset:10.0 + topOffset]]; 189 | [superlayer addSublayer:top]; 190 | 191 | CALayer *topRight = layersByName[kTopRightName]; 192 | [topRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:kRightName attribute:kCAConstraintWidth]]; 193 | [topRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:kRightName attribute:kCAConstraintMidX]]; 194 | [topRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:kRightName attribute:kCAConstraintMinY offset:-10]]; 195 | [topRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:kSuperName attribute:kCAConstraintMinY offset:10 + topOffset]]; 196 | [superlayer addSublayer:topRight]; 197 | 198 | CALayer *right = layersByName[kRightName]; 199 | [right addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintHeight relativeTo:kCenterName attribute:kCAConstraintHeight scale:4.0 offset:0]]; 200 | [right addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY relativeTo:kCenterName attribute:kCAConstraintMidY]]; 201 | [right addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX relativeTo:kCenterName attribute:kCAConstraintMaxX offset:10]]; 202 | [right addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX relativeTo:kSuperName attribute:kCAConstraintMaxX offset:-10]]; 203 | [superlayer addSublayer:right]; 204 | 205 | CALayer *bottomRight = layersByName[kBottomRightName]; 206 | [bottomRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:kRightName attribute:kCAConstraintWidth]]; 207 | [bottomRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:kRightName attribute:kCAConstraintMidX]]; 208 | [bottomRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:kRightName attribute:kCAConstraintMaxY offset:10]]; 209 | [bottomRight addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:kSuperName attribute:kCAConstraintMaxY offset:-10]]; 210 | [superlayer addSublayer:bottomRight]; 211 | 212 | CALayer *bottom = layersByName[kBottomName]; 213 | [bottom addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:kCenterName attribute:kCAConstraintWidth]]; 214 | [bottom addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:kCenterName attribute:kCAConstraintMidX]]; 215 | [bottom addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:kCenterName attribute:kCAConstraintMaxY offset:10.0]]; 216 | [bottom addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:kSuperName attribute:kCAConstraintMaxY offset:-10.0]]; 217 | [superlayer addSublayer:bottom]; 218 | 219 | CALayer *bottomLeft = layersByName[kBottomLeftName]; 220 | [bottomLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:kLeftName attribute:kCAConstraintWidth]]; 221 | [bottomLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:kLeftName attribute:kCAConstraintMidX]]; 222 | [bottomLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY relativeTo:kLeftName attribute:kCAConstraintMaxY offset:10]]; 223 | [bottomLeft addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY relativeTo:kSuperName attribute:kCAConstraintMaxY offset:-10]]; 224 | [superlayer addSublayer:bottomLeft]; 225 | 226 | CALayer *left = layersByName[kLeftName]; 227 | [left addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintHeight relativeTo:kCenterName attribute:kCAConstraintHeight scale:3.0 offset:0]]; 228 | [left addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY relativeTo:kCenterName attribute:kCAConstraintMidY]]; 229 | [left addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX relativeTo:kCenterName attribute:kCAConstraintMinX offset:-10]]; 230 | [left addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX relativeTo:kSuperName attribute:kCAConstraintMinX offset:10]]; 231 | [superlayer addSublayer:left]; 232 | 233 | superlayer.layoutManager = layoutManager; 234 | 235 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void){ 236 | [center setBounds:CGRectMake(0.0, 0.0, 150.0, 50.0)]; 237 | }); 238 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void){ 239 | [center removeFromSuperlayer]; 240 | }); 241 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void){ 242 | [center setBounds:CGRectMake(0.0, 0.0, 50.0, 50.0)]; 243 | [superlayer addSublayer:center]; 244 | }); 245 | } 246 | 247 | - (IBAction)changeCenterHeight:(id)sender { 248 | CALayer *center = self.layersByName[kCenterName]; 249 | #if TARGET_OS_IPHONE 250 | CGFloat height = self.slider.value; 251 | #else 252 | CGFloat height = self.slider.doubleValue; 253 | #endif 254 | CGRect frame = [center frame]; 255 | frame.size.height = floor(height + 0.5); 256 | center.frame = frame; 257 | } 258 | 259 | @end 260 | -------------------------------------------------------------------------------- /DLConstraintLayout/DLCLConstraintLayoutSolver.mm: -------------------------------------------------------------------------------- 1 | // 2 | // DLCLConstraintLayoutSolver.mm 3 | // DLConstraintLayout 4 | // 5 | // Created by vesche on 4/9/13. 6 | // Copyright (c) 2013 Regexident. All rights reserved. 7 | // 8 | 9 | #import "DLCLConstraintLayoutSolver.h" 10 | 11 | #import 12 | 13 | #import "DLCLConstraint.h" 14 | #import "DLCLConstraint+Protected.h" 15 | #import "CALayer+DLConstraintLayout.h" 16 | 17 | #if defined(DLCL_USE_CPP_SOLVER) 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #else 26 | 27 | #import "DLCLConstraintLayoutNode.h" 28 | 29 | #endif 30 | 31 | #if defined(DLCL_USE_CPP_SOLVER) 32 | 33 | namespace dlcl { 34 | 35 | class constraint_layout_node { 36 | 37 | public: 38 | 39 | using layer_type = CALayer; 40 | using constraint_type = DLCLConstraint; 41 | using constraint_struct_type = DLCLConstraintStruct; 42 | using constraint_struct_vector_type = std::vector; 43 | using node_ptr_set_type = std::set; 44 | using node_pair_type = std::pair; 45 | using attribute_type = DLCLConstraintAttribute; 46 | using axis_type = DLCLConstraintAxis; 47 | using axis_attribute_type = DLCLConstraintAxisAttribute; 48 | 49 | constraint_layout_node(const layer_type *layer_ptr, axis_type axis) : layer_ptr(layer_ptr), axis(axis) { 50 | // intentionally left blank 51 | } 52 | 53 | const layer_type *get_layer_ptr() const { 54 | return this->layer_ptr; 55 | } 56 | 57 | const axis_type get_axis() const { 58 | return this->axis; 59 | } 60 | 61 | const constraint_struct_vector_type &get_constraints() const { 62 | return this->constraints; 63 | } 64 | 65 | template 66 | void enumerate_constraint_structs(const Enumerator &enumerator) const { 67 | bool stop = false; 68 | for (const constraint_struct_type &constraint_struct : this->constraints) { 69 | enumerator(constraint_struct, &stop); 70 | if (stop) { 71 | break; 72 | } 73 | } 74 | } 75 | 76 | template 77 | void enumerate_constraint_structs_in_layer(const layer_type *layer_ptr, const Enumerator &enumerator) { 78 | bool stop = false; 79 | for (constraint_type *constraint in layer_ptr.constraints) { 80 | if (stop) { 81 | break; 82 | } 83 | const DLCLConstraintStruct &constraintStruct = constraint.constraintStruct; 84 | layer_type *super_layer = layer_ptr.superlayer; 85 | if (!super_layer) { 86 | continue; 87 | } 88 | layer_type *identified_layer = [constraint detectSourceLayerInSuperlayer:super_layer]; 89 | if (!identified_layer) { 90 | // no layer with given name. Ignore constraint. 91 | continue; 92 | } 93 | enumerator(constraintStruct, &stop); 94 | } 95 | } 96 | 97 | void add_constraint(const constraint_struct_type &constraint_struct) { 98 | axis_type constraint_axis = DLCLConstraintAttributeGetAxis(constraint_struct.attribute); 99 | if (constraint_axis != this->axis) { 100 | return; 101 | } 102 | this->constraints.push_back(constraint_struct); 103 | } 104 | 105 | const node_ptr_set_type &get_incoming() const { 106 | return this->incoming; 107 | } 108 | 109 | const node_ptr_set_type &get_outgoing() const { 110 | return this->outgoing; 111 | } 112 | 113 | bool depends_on(const constraint_layout_node &node) const { 114 | bool depends = false; 115 | this->enumerate_constraint_structs([&](const constraint_struct_type &constraint_struct, bool *stop) { 116 | if (constraint_struct.source_layer != node.layer_ptr) { 117 | return; 118 | } 119 | node.enumerate_constraint_structs([&](const constraint_struct_type &other_constraint_struct, bool *stop) { 120 | axis_type constraint_source_axis = DLCLConstraintAttributeGetAxis(constraint_struct.source_attribute); 121 | axis_type other_constraint_axis = DLCLConstraintAttributeGetAxis(other_constraint_struct.attribute); 122 | if (constraint_source_axis == other_constraint_axis) { 123 | depends = true; 124 | return; 125 | } 126 | }); 127 | }); 128 | return depends; 129 | } 130 | 131 | static void add_dependency(constraint_layout_node &node, constraint_layout_node &dependency_node) { 132 | node.incoming.insert(&dependency_node); 133 | dependency_node.outgoing.insert(&node); 134 | } 135 | 136 | static void remove_dependency(constraint_layout_node &node, constraint_layout_node &dependency_node) { 137 | node.incoming.erase(&dependency_node); 138 | dependency_node.outgoing.erase(&node); 139 | } 140 | 141 | private: 142 | 143 | const layer_type *layer_ptr; 144 | const axis_type axis; 145 | constraint_struct_vector_type constraints; 146 | node_ptr_set_type incoming; 147 | node_ptr_set_type outgoing; 148 | }; 149 | 150 | class solver { 151 | using node_type = dlcl::constraint_layout_node; 152 | using node_pair_type = node_type::node_pair_type; 153 | using constraint_type = node_type::constraint_type; 154 | using constraint_struct_type = node_type::constraint_struct_type; 155 | using layer_type = node_type::layer_type; 156 | using frame_type = CGRect; 157 | using attribute_type = node_type::attribute_type; 158 | using axis_type = node_type::axis_type; 159 | using axis_attribute_type = node_type::axis_attribute_type; 160 | using value_by_axis_attribute_type = std::map; 161 | 162 | typedef std::vector node_vector_type; 163 | typedef std::vector node_ptr_vector_type; 164 | typedef std::set node_ptr_set_type; 165 | 166 | CALayer *root_layer; 167 | node_vector_type nodes; 168 | node_ptr_vector_type sorted_nodes; 169 | 170 | public: 171 | 172 | solver(CALayer *root_layer = nullptr) throw(std::runtime_error) : root_layer(root_layer) { 173 | this->generate_nodes(root_layer); 174 | this->add_node_dependencies(); 175 | this->sort_nodes_topologically(); 176 | this->validate_sorted_nodes(); // throws exception on dependency circles 177 | } 178 | 179 | void solve() { 180 | this->enumerate_sorted_nodes([&](node_type &node, bool *stop) { 181 | solver::solve_node(node); 182 | }); 183 | } 184 | 185 | private: 186 | 187 | template 188 | static void enumerate_sublayers(CALayer *layer, const Enumerator &enumerator) { 189 | bool stop = false; 190 | for (CALayer *sub_layer in layer.sublayers) { 191 | if (stop) { 192 | break; 193 | } 194 | enumerator(sub_layer, &stop); 195 | } 196 | } 197 | 198 | template 199 | void enumerate_nodes(const Enumerator &enumerator) { 200 | bool stop = false; 201 | for (auto &node : this->nodes) { 202 | enumerator(node, &stop); 203 | if (stop) { 204 | break; 205 | } 206 | } 207 | } 208 | 209 | template 210 | void enumerate_sorted_nodes(const Enumerator &enumerator) { 211 | bool stop = false; 212 | for (auto &node : this->sorted_nodes) { 213 | enumerator(*node, &stop); 214 | if (stop) { 215 | break; 216 | } 217 | } 218 | } 219 | 220 | template 221 | void enumerate_constraint_structs_in_layer(const layer_type *layer, const Enumerator &enumerator) { 222 | bool stop = false; 223 | for (constraint_type *constraint in layer.constraints) { 224 | if (stop) { 225 | break; 226 | } 227 | layer_type *super_layer = layer.superlayer; 228 | if (!super_layer) { 229 | continue; 230 | } 231 | const layer_type *identified_layer = [constraint detectSourceLayerInSuperlayer:super_layer]; 232 | if (!identified_layer) { 233 | // no layer with given name. Ignore constraint. 234 | continue; 235 | } 236 | enumerator(constraint.constraintStruct, &stop); 237 | } 238 | } 239 | 240 | void generate_nodes(CALayer *root_layer) { 241 | this->nodes.clear(); 242 | this->enumerate_sublayers(root_layer, [&](CALayer *sub_layer, bool *stop) { 243 | node_pair_type node_pair({constraint_layout_node(sub_layer, DLCLConstraintAxisX), constraint_layout_node(sub_layer, DLCLConstraintAxisY)}); 244 | this->enumerate_constraint_structs_in_layer(sub_layer, [&](const constraint_struct_type &constraint_struct, bool *stop) { 245 | DLCLConstraintAxis axis = DLCLConstraintAttributeGetAxis(constraint_struct.attribute); 246 | constraint_layout_node &node = (axis == DLCLConstraintAxisX) ? node_pair.first : node_pair.second; 247 | node.add_constraint(constraint_struct); 248 | }); 249 | if (!node_pair.first.get_constraints().empty()) { 250 | this->nodes.push_back(std::move(node_pair.first)); 251 | // do not touch node_pair.first from now on! 252 | } 253 | if (!node_pair.second.get_constraints().empty()) { 254 | this->nodes.push_back(std::move(node_pair.second)); 255 | // do not touch node_pair.second from now on! 256 | } 257 | }); 258 | } 259 | 260 | void add_node_dependencies() { 261 | using nodes_by_layer = std::map; 262 | nodes_by_layer node_maps_by_axis[] { 263 | nodes_by_layer(), 264 | nodes_by_layer() 265 | }; 266 | this->enumerate_nodes([&](node_type &node, bool *stop) { 267 | nodes_by_layer &nodes_on_axis = node_maps_by_axis[node.get_axis()]; 268 | nodes_on_axis[node.get_layer_ptr()].insert(&node); 269 | }); 270 | this->enumerate_nodes([&](node_type &node, bool *stop) { 271 | node.enumerate_constraint_structs([&](const constraint_struct_type &constraint_struct, bool *stop) { 272 | CALayer *source_layer = constraint_struct.source_layer; 273 | if (!source_layer) { 274 | return; 275 | } 276 | DLCLConstraintAxis axis = DLCLConstraintAttributeGetAxis(constraint_struct.attribute); 277 | nodes_by_layer &nodes_on_axis = node_maps_by_axis[axis]; 278 | if (!nodes_on_axis.count(source_layer)) { 279 | return; 280 | } 281 | for (auto &source_node_ptr : nodes_on_axis[source_layer]) { 282 | if (node.depends_on(*source_node_ptr)) { 283 | node_type::add_dependency(node, *source_node_ptr); 284 | } 285 | } 286 | }); 287 | }); 288 | } 289 | 290 | void sort_nodes_topologically() { 291 | this->sorted_nodes.clear(); 292 | std::queue queue; 293 | this->enumerate_nodes([&](node_type &node, bool *stop) { 294 | if (!node.get_incoming().size()) { 295 | queue.push((node_type *)&node); 296 | } 297 | }); 298 | while (!queue.empty()) { 299 | node_type &node = *queue.front(); 300 | queue.pop(); 301 | this->sorted_nodes.push_back(&node); 302 | node_ptr_set_type outgoing = node.get_outgoing(); 303 | for (auto &outgoing_node_ptr : outgoing) { 304 | node_type::remove_dependency(*outgoing_node_ptr, node); 305 | if (outgoing_node_ptr->get_incoming().empty()) { 306 | queue.push(outgoing_node_ptr); 307 | } 308 | } 309 | } 310 | } 311 | 312 | void validate_sorted_nodes() throw(std::runtime_error) { 313 | for (node_type *node_ptr : this->sorted_nodes) { 314 | if (!node_ptr->get_outgoing().empty() || !node_ptr->get_incoming().empty()) { 315 | throw std::runtime_error("Circle detected. Constraint dependencies must not form cycles."); 316 | } 317 | } 318 | } 319 | 320 | static void solve_node(node_type &node) { 321 | const CALayer *layer_ptr = node.get_layer_ptr(); 322 | if (!layer_ptr) { 323 | return; 324 | } 325 | value_by_axis_attribute_type source_values; 326 | int axis_attributes_mask = 0x0; 327 | node.enumerate_constraint_structs([&](const constraint_struct_type &constraint_struct, bool *stop) { 328 | attribute_type attribute = constraint_struct.attribute; 329 | attribute_type source_attribute = constraint_struct.source_attribute; 330 | axis_attribute_type axis_attribute = DLCLConstraintAttributeGetAxisAttribute(attribute); 331 | axis_attributes_mask |= (0x1 << (int)axis_attribute); 332 | frame_type source_layer_frame = constraint_struct.source_layer.frame; 333 | CGFloat source_attribute_value = get_attribute(source_layer_frame, source_attribute); 334 | source_values[axis_attribute] = (source_attribute_value * constraint_struct.scale) + constraint_struct.offset; 335 | }); 336 | layer_ptr.frame = frame_after_setting_attributes(layer_ptr.frame, axis_attributes_mask, node.get_axis(), source_values); 337 | } 338 | 339 | static frame_type frame_after_setting_attributes(frame_type frame, const int &axis_attributes_mask, const axis_type &axis, const value_by_axis_attribute_type &source) { 340 | CGFloat layer_min_value = (axis == DLCLConstraintAxisX) ? frame.origin.x : frame.origin.y; 341 | CGFloat layer_size_value = (axis == DLCLConstraintAxisX) ? frame.size.width : frame.size.height; 342 | if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMin)) { 343 | layer_min_value = source.at(DLCLConstraintAxisAttributeMin); // min 344 | if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMid)) { // min & mid 345 | layer_size_value = (source.at(DLCLConstraintAxisAttributeMid) - source.at(DLCLConstraintAxisAttributeMin)) * 2; 346 | } else if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMax)) { // min & max 347 | layer_size_value = (source.at(DLCLConstraintAxisAttributeMax) - source.at(DLCLConstraintAxisAttributeMin)); 348 | } else if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeSize)) { // min & size 349 | layer_size_value = source.at(DLCLConstraintAxisAttributeSize); 350 | } 351 | } else if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeSize)) { 352 | layer_size_value = source.at(DLCLConstraintAxisAttributeSize); // size 353 | if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMid)) { // size & mid 354 | layer_min_value = source.at(DLCLConstraintAxisAttributeMid) - (source.at(DLCLConstraintAxisAttributeSize) / 2); 355 | } else if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMax)) { // size & max 356 | layer_min_value = source.at(DLCLConstraintAxisAttributeMax) - source.at(DLCLConstraintAxisAttributeSize); 357 | } 358 | } else if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMid)) { 359 | layer_min_value = source.at(DLCLConstraintAxisAttributeMid) - (layer_size_value / 2); // mid 360 | if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMax)) { // mid & max 361 | layer_size_value = (source.at(DLCLConstraintAxisAttributeMax) - source.at(DLCLConstraintAxisAttributeMid)) * 2; 362 | layer_min_value = source.at(DLCLConstraintAxisAttributeMax) - layer_size_value; 363 | } 364 | } else if (axis_attributes_mask & (0x1 << DLCLConstraintAxisAttributeMax)) { 365 | layer_min_value = source.at(DLCLConstraintAxisAttributeMax) - layer_size_value; // max 366 | } 367 | if (axis == DLCLConstraintAxisX) { 368 | frame.origin.x = layer_min_value; 369 | } else { 370 | frame.origin.y = layer_min_value; 371 | } 372 | if (axis == DLCLConstraintAxisX) { 373 | frame.size.width = layer_size_value; 374 | } else { 375 | frame.size.height = layer_size_value; 376 | } 377 | return frame; 378 | } 379 | 380 | static CGFloat get_attribute(const frame_type &frame, const attribute_type &attribute) { 381 | return get_attribute(frame, DLCLConstraintAttributeGetAxis(attribute), DLCLConstraintAttributeGetAxisAttribute(attribute)); 382 | } 383 | 384 | static CGFloat get_attribute(const frame_type &frame, const axis_type &axis, const axis_attribute_type &axis_attribute) { 385 | CGFloat value; 386 | switch (axis_attribute) { 387 | case DLCLConstraintAxisAttributeMin: { value = (axis == DLCLConstraintAxisX) ? CGRectGetMinX(frame) : CGRectGetMinY(frame); break; } 388 | case DLCLConstraintAxisAttributeMid: { value = (axis == DLCLConstraintAxisX) ? CGRectGetMidX(frame) : CGRectGetMidY(frame); break; } 389 | case DLCLConstraintAxisAttributeMax: { value = (axis == DLCLConstraintAxisX) ? CGRectGetMaxX(frame) : CGRectGetMaxY(frame); break; } 390 | case DLCLConstraintAxisAttributeSize: { value = (axis == DLCLConstraintAxisX) ? CGRectGetWidth(frame) : CGRectGetHeight(frame); break; } 391 | default: { 392 | throw std::runtime_error("Unknown attribute."); 393 | break; 394 | } 395 | } 396 | return value; 397 | } 398 | 399 | }; 400 | 401 | } 402 | 403 | #endif 404 | 405 | #if defined(DLCL_USE_CPP_SOLVER) 406 | @interface DLCLConstraintLayoutSolver () 407 | 408 | @property (readwrite, weak, nonatomic) CALayer *layer; 409 | 410 | @end 411 | 412 | @implementation DLCLConstraintLayoutSolver { 413 | std::unique_ptr solver; 414 | } 415 | #else 416 | @interface DLCLConstraintLayoutSolver () 417 | 418 | @property (readwrite, weak, nonatomic) CALayer *layer; 419 | @property (readwrite, strong, nonatomic) NSMutableArray *nodes; 420 | 421 | @end 422 | 423 | @implementation DLCLConstraintLayoutSolver 424 | #endif 425 | 426 | - (id)initWithLayer:(CALayer *)layer { 427 | self = [self init]; 428 | if (self) { 429 | self.layer = layer; 430 | 431 | BOOL isCircleFree = YES; 432 | #if defined(DLCL_USE_CPP_SOLVER) 433 | try { 434 | std::unique_ptr unique_solver(new dlcl::solver(layer)); 435 | self->solver = std::move(unique_solver); 436 | } catch (const std::runtime_error &exception) { 437 | isCircleFree = NO; 438 | } 439 | #else 440 | self.nodes = [NSMutableArray array]; 441 | [self generateNodesForLayer:self.layer]; 442 | [self addNodeDependencies]; 443 | [self sortNodesTopologically]; 444 | isCircleFree = [self validateSortedNodes]; 445 | #endif 446 | if (!isCircleFree) { 447 | [NSException raise:@"DLCLConstraintLayoutSolverFoundCircularDependenciesException" 448 | format:@"Circle detected. Constraint dependencies must not form cycles."]; 449 | } 450 | } 451 | return self; 452 | } 453 | 454 | + (instancetype)solverWithLayer:(CALayer *)layer { 455 | return [[self alloc] initWithLayer:layer]; 456 | } 457 | 458 | - (void)solveLayout { 459 | #if defined(DLCL_USE_CPP_SOLVER) 460 | self->solver->solve(); 461 | #else 462 | CALayer *superlayer = self.layer; 463 | for (DLCLConstraintLayoutNode *node in self.nodes) { 464 | [self solveNode:node inSuperlayer:superlayer]; 465 | } 466 | #endif 467 | } 468 | 469 | #if !defined(DLCL_USE_CPP_SOLVER) 470 | 471 | - (void)generateNodesForLayer:(CALayer *)layer { 472 | [self.nodes removeAllObjects]; 473 | for (CALayer *sublayer in layer.sublayers) { 474 | DLCLConstraintLayoutNode *axisNodes[] = { 475 | [DLCLConstraintLayoutNode nodeWithAxis:DLCLConstraintAxisX forLayer:sublayer], 476 | [DLCLConstraintLayoutNode nodeWithAxis:DLCLConstraintAxisY forLayer:sublayer] 477 | }; 478 | for (DLCLConstraint *constraint in sublayer.constraints) { 479 | DLCLConstraintAxis axis = DLCLConstraintAttributeGetAxis(constraint.attribute); 480 | [axisNodes[axis] addConstraint:constraint]; 481 | } 482 | if ([axisNodes[DLCLConstraintAxisX].constraints count]) { 483 | [self.nodes addObject:axisNodes[DLCLConstraintAxisX]]; 484 | } 485 | if ([axisNodes[DLCLConstraintAxisY].constraints count]) { 486 | [self.nodes addObject:axisNodes[DLCLConstraintAxisY]]; 487 | } 488 | } 489 | } 490 | 491 | - (void)addNodeDependencies { 492 | NSMutableDictionary *nodesByAxis[] = { 493 | [NSMutableDictionary dictionary], 494 | [NSMutableDictionary dictionary] 495 | }; 496 | // Create lookup dictionaries: 497 | for (DLCLConstraintLayoutNode *node in self.nodes) { 498 | NSMutableDictionary *nodesByLayer = nodesByAxis[node.axis]; 499 | NSValue *pointerValue = [NSValue valueWithPointer:(void *)node.layer]; 500 | NSMutableSet *nodes = nodesByLayer[pointerValue]; 501 | if (!nodes) { 502 | nodes = [NSMutableSet set]; 503 | nodesByLayer[pointerValue] = nodes; 504 | } 505 | [nodes addObject:node]; 506 | } 507 | for (DLCLConstraintLayoutNode *node in self.nodes) { 508 | CALayer *superlayer = node.layer.superlayer; 509 | for (DLCLConstraint *constraint in node.constraints) { 510 | CALayer *sourceLayer = [constraint detectSourceLayerInSuperlayer:superlayer]; 511 | if (!sourceLayer) { 512 | continue; 513 | } 514 | DLCLConstraintAxis sourceAxis = DLCLConstraintAttributeGetAxis(constraint.sourceAttribute); 515 | NSMutableDictionary *nodesByLayer = nodesByAxis[sourceAxis]; 516 | NSMutableArray *sourceNodes = [nodesByLayer objectForKey:[NSValue valueWithPointer:(void *)sourceLayer]]; 517 | for (DLCLConstraintLayoutNode *sourceNode in sourceNodes) { 518 | if ([node hasDependencyTo:sourceNode]) { 519 | [node addDependencyTo:sourceNode]; 520 | } 521 | } 522 | } 523 | } 524 | } 525 | 526 | - (void)sortNodesTopologically { 527 | NSArray *nodes = [NSArray arrayWithArray:self.nodes]; 528 | [self.nodes removeAllObjects]; 529 | NSMutableArray *queue = [NSMutableArray array]; 530 | for (DLCLConstraintLayoutNode *node in nodes) { 531 | if (![node.incoming count]) { 532 | [queue addObject:node]; 533 | } 534 | } 535 | while ([queue count]) { 536 | DLCLConstraintLayoutNode *node = queue[0]; 537 | [queue removeObjectAtIndex:0]; 538 | [self.nodes addObject:node]; 539 | for (DLCLConstraintLayoutNode *outgoingNode in [NSSet setWithSet:node.outgoing]) { 540 | [outgoingNode removeDependencyTo:node]; 541 | if (![outgoingNode.incoming count]) { 542 | [queue addObject:outgoingNode]; 543 | } 544 | } 545 | } 546 | } 547 | 548 | - (BOOL)validateSortedNodes { 549 | for (DLCLConstraintLayoutNode *node in self.nodes) { 550 | if ([node.outgoing count] || [node.incoming count]) { 551 | return NO; 552 | } 553 | } 554 | return YES; 555 | } 556 | 557 | - (void)solveNode:(DLCLConstraintLayoutNode *)node inSuperlayer:(CALayer *)superlayer { 558 | CALayer *layer = node.layer; 559 | if (!layer) { 560 | return; 561 | } 562 | CGRect frame = layer.frame; 563 | NSMutableDictionary *sourceValuesByAxisAttribute = [NSMutableDictionary dictionary]; 564 | int axisAttributesMask = 0x0; 565 | for (DLCLConstraint *constraint in node.constraints) { 566 | DLCLConstraintAttribute attribute = constraint.attribute; 567 | DLCLConstraintAttribute sourceAttribute = constraint.sourceAttribute; 568 | DLCLConstraintAxisAttribute axisAttribute = DLCLConstraintAttributeGetAxisAttribute(attribute); 569 | CALayer *sourceLayer = constraint.sourceLayer; 570 | if (!sourceLayer) { 571 | continue; 572 | } 573 | axisAttributesMask |= (0x1 << (int)axisAttribute); 574 | CGRect sourceFrame = sourceLayer.frame; 575 | typedef CGFloat DLCLRectFunction(CGRect rect); 576 | DLCLRectFunction *rectFunctions[] = { 577 | &CGRectGetMinX, &CGRectGetMidX, &CGRectGetMaxX, &CGRectGetWidth, 578 | &CGRectGetMinY, &CGRectGetMidY, &CGRectGetMaxY, &CGRectGetHeight 579 | }; 580 | CGFloat sourceAttributeValue = rectFunctions[sourceAttribute](sourceFrame); 581 | sourceValuesByAxisAttribute[@((int)axisAttribute)] = @((sourceAttributeValue * constraint.scale) + constraint.offset); 582 | } 583 | layer.frame = [[self class] frame:(CGRect)frame afterSettingAttributeValues:sourceValuesByAxisAttribute onAxis:node.axis forMask:axisAttributesMask]; 584 | } 585 | 586 | + (CGRect)frame:(CGRect)frame afterSettingAttributeValues:(NSDictionary *)attributeValues onAxis:(DLCLConstraintAxis)axis forMask:(int)axisAttributesMask { 587 | NSNumber *minKey = @((int)DLCLConstraintAxisAttributeMin); 588 | NSNumber *midKey = @((int)DLCLConstraintAxisAttributeMid); 589 | NSNumber *maxKey = @((int)DLCLConstraintAxisAttributeMax); 590 | NSNumber *sizeKey = @((int)DLCLConstraintAxisAttributeSize); 591 | CGFloat minValue = (axis == DLCLConstraintAxisX) ? CGRectGetMinX(frame) : CGRectGetMinY(frame); 592 | CGFloat sizeValue = (axis == DLCLConstraintAxisX) ? CGRectGetWidth(frame) : CGRectGetHeight(frame); 593 | 594 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMin)) { 595 | minValue = [attributeValues[minKey] doubleValue]; // min 596 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMid)) { // min & mid 597 | sizeValue = ([attributeValues[midKey] doubleValue] - minValue) * 2; 598 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { // min & max 599 | sizeValue = ([attributeValues[maxKey] doubleValue] - minValue); 600 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeSize)) { // min & size 601 | sizeValue = [attributeValues[sizeKey] doubleValue]; 602 | } 603 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeSize)) { 604 | sizeValue = [attributeValues[sizeKey] doubleValue]; // size 605 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMid)) { // size & mid 606 | minValue = [attributeValues[midKey] doubleValue] - (sizeValue / 2); 607 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { // size & max 608 | minValue = [attributeValues[maxKey] doubleValue] - sizeValue; 609 | } 610 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMid)) { 611 | minValue = [attributeValues[midKey] doubleValue] - (sizeValue / 2); // mid 612 | if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { // mid & max 613 | sizeValue = ([attributeValues[maxKey] doubleValue] - [attributeValues[midKey] doubleValue]) * 2; 614 | minValue = [attributeValues[maxKey] doubleValue] - sizeValue; 615 | } 616 | } else if (axisAttributesMask & (0x1 << DLCLConstraintAxisAttributeMax)) { 617 | minValue = [attributeValues[maxKey] doubleValue] - sizeValue; // max 618 | } 619 | if (axis == DLCLConstraintAxisX) { 620 | frame.origin.x = minValue; 621 | frame.size.width = sizeValue; 622 | } else { 623 | frame.origin.y = minValue; 624 | frame.size.height = sizeValue; 625 | } 626 | return frame; 627 | } 628 | 629 | #endif 630 | 631 | @end 632 | -------------------------------------------------------------------------------- /DLConstraintLayout.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A4AF623318AB8CB7003344C0 /* DLCLConstraintLayoutSolver.mm in Sources */ = {isa = PBXBuildFile; fileRef = A4AF623218AB8CB7003344C0 /* DLCLConstraintLayoutSolver.mm */; }; 11 | A4AF623418AB8EB9003344C0 /* DLCLConstraintLayoutSolver.mm in Sources */ = {isa = PBXBuildFile; fileRef = A4AF623218AB8CB7003344C0 /* DLCLConstraintLayoutSolver.mm */; }; 12 | C25F4FCE16F8900D00A8671C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C25F4FCC16F8900D00A8671C /* InfoPlist.strings */; }; 13 | C25F4FD016F8900D00A8671C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C25F4FCF16F8900D00A8671C /* main.m */; }; 14 | C25F4FD716F8900D00A8671C /* DLCLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C25F4FD616F8900D00A8671C /* DLCLAppDelegate.m */; }; 15 | C25F4FDA16F8900E00A8671C /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C25F4FD816F8900E00A8671C /* MainMenu.xib */; }; 16 | C25F4FE916F8962A00A8671C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C25F4FE816F8962A00A8671C /* Cocoa.framework */; }; 17 | C25F4FEC16F897E500A8671C /* DLCLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C25F4FEB16F897E500A8671C /* DLCLViewController.m */; }; 18 | C25F4FED16F897E500A8671C /* DLCLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C25F4FEB16F897E500A8671C /* DLCLViewController.m */; }; 19 | C25F4FEF16F89BBF00A8671C /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C25F4FEE16F89BBF00A8671C /* QuartzCore.framework */; }; 20 | C25F4FF316F8E3B900A8671C /* libDLConstraintLayout.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AE216F0E404005F4627 /* libDLConstraintLayout.a */; }; 21 | C25F501C16FA582200A8671C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AA416F0E366005F4627 /* CoreGraphics.framework */; }; 22 | C25F501E16FBCBEC00A8671C /* DLConstraintLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = C2BF8AE916F0E404005F4627 /* DLConstraintLayout.m */; }; 23 | C2A672DA16F2CC24004062E8 /* libDLConstraintLayout.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AE216F0E404005F4627 /* libDLConstraintLayout.a */; }; 24 | C2A672DB16F2CC37004062E8 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AF916F0EA92005F4627 /* QuartzCore.framework */; }; 25 | C2BF8AA116F0E366005F4627 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AA016F0E366005F4627 /* UIKit.framework */; }; 26 | C2BF8AA316F0E366005F4627 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AA216F0E366005F4627 /* Foundation.framework */; }; 27 | C2BF8AA516F0E366005F4627 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AA416F0E366005F4627 /* CoreGraphics.framework */; }; 28 | C2BF8AAB16F0E366005F4627 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C2BF8AA916F0E366005F4627 /* InfoPlist.strings */; }; 29 | C2BF8AAD16F0E366005F4627 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2BF8AAC16F0E366005F4627 /* main.m */; }; 30 | C2BF8AB116F0E366005F4627 /* DLCLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C2BF8AB016F0E366005F4627 /* DLCLAppDelegate.m */; }; 31 | C2BF8AB316F0E366005F4627 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = C2BF8AB216F0E366005F4627 /* Default.png */; }; 32 | C2BF8AB516F0E366005F4627 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C2BF8AB416F0E366005F4627 /* Default@2x.png */; }; 33 | C2BF8AB716F0E366005F4627 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C2BF8AB616F0E366005F4627 /* Default-568h@2x.png */; }; 34 | C2BF8ABA16F0E366005F4627 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C2BF8AB816F0E366005F4627 /* MainStoryboard_iPhone.storyboard */; }; 35 | C2BF8ABD16F0E366005F4627 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C2BF8ABB16F0E366005F4627 /* MainStoryboard_iPad.storyboard */; }; 36 | C2BF8AC816F0E366005F4627 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AC716F0E366005F4627 /* SenTestingKit.framework */; }; 37 | C2BF8AC916F0E366005F4627 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AA016F0E366005F4627 /* UIKit.framework */; }; 38 | C2BF8ACA16F0E366005F4627 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AA216F0E366005F4627 /* Foundation.framework */; }; 39 | C2BF8AD216F0E366005F4627 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C2BF8AD016F0E366005F4627 /* InfoPlist.strings */; }; 40 | C2BF8AD516F0E366005F4627 /* DLCLConstraintLayoutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C2BF8AD416F0E366005F4627 /* DLCLConstraintLayoutTests.m */; }; 41 | C2BF8AE316F0E404005F4627 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AA216F0E366005F4627 /* Foundation.framework */; }; 42 | C2BF8AE816F0E404005F4627 /* DLConstraintLayout.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2BF8AE716F0E404005F4627 /* DLConstraintLayout.h */; }; 43 | C2BF8AEA16F0E404005F4627 /* DLConstraintLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = C2BF8AE916F0E404005F4627 /* DLConstraintLayout.m */; }; 44 | C2BF8AFA16F0EA92005F4627 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BF8AF916F0EA92005F4627 /* QuartzCore.framework */; }; 45 | C2EDF5D917A279B600F5528B /* CALayer+DLConstraintLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5D817A279B600F5528B /* CALayer+DLConstraintLayout.m */; }; 46 | C2EDF5DA17A279B600F5528B /* CALayer+DLConstraintLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5D817A279B600F5528B /* CALayer+DLConstraintLayout.m */; }; 47 | C2EDF5E417A279D100F5528B /* DLCLConstraint.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5DC17A279D100F5528B /* DLCLConstraint.m */; }; 48 | C2EDF5E517A279D100F5528B /* DLCLConstraint.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5DC17A279D100F5528B /* DLCLConstraint.m */; }; 49 | C2EDF5E617A279D100F5528B /* DLCLConstraintLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5DF17A279D100F5528B /* DLCLConstraintLayoutManager.m */; }; 50 | C2EDF5E717A279D100F5528B /* DLCLConstraintLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5DF17A279D100F5528B /* DLCLConstraintLayoutManager.m */; }; 51 | C2EDF5E817A279D100F5528B /* DLCLConstraintLayoutNode.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5E117A279D100F5528B /* DLCLConstraintLayoutNode.m */; }; 52 | C2EDF5E917A279D100F5528B /* DLCLConstraintLayoutNode.m in Sources */ = {isa = PBXBuildFile; fileRef = C2EDF5E117A279D100F5528B /* DLCLConstraintLayoutNode.m */; }; 53 | /* End PBXBuildFile section */ 54 | 55 | /* Begin PBXContainerItemProxy section */ 56 | C25F4FF116F8E3A900A8671C /* PBXContainerItemProxy */ = { 57 | isa = PBXContainerItemProxy; 58 | containerPortal = C2BF8A9516F0E366005F4627 /* Project object */; 59 | proxyType = 1; 60 | remoteGlobalIDString = C2BF8AE116F0E404005F4627; 61 | remoteInfo = DLConstraintLayout; 62 | }; 63 | C2A672D816F2CC20004062E8 /* PBXContainerItemProxy */ = { 64 | isa = PBXContainerItemProxy; 65 | containerPortal = C2BF8A9516F0E366005F4627 /* Project object */; 66 | proxyType = 1; 67 | remoteGlobalIDString = C2BF8AE116F0E404005F4627; 68 | remoteInfo = DLConstraintLayout; 69 | }; 70 | /* End PBXContainerItemProxy section */ 71 | 72 | /* Begin PBXCopyFilesBuildPhase section */ 73 | C2BF8AE016F0E404005F4627 /* CopyFiles */ = { 74 | isa = PBXCopyFilesBuildPhase; 75 | buildActionMask = 2147483647; 76 | dstPath = "include/${PRODUCT_NAME}"; 77 | dstSubfolderSpec = 16; 78 | files = ( 79 | C2BF8AE816F0E404005F4627 /* DLConstraintLayout.h in CopyFiles */, 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | /* End PBXCopyFilesBuildPhase section */ 84 | 85 | /* Begin PBXFileReference section */ 86 | A4AF623218AB8CB7003344C0 /* DLCLConstraintLayoutSolver.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = DLCLConstraintLayoutSolver.mm; path = DLConstraintLayout/DLCLConstraintLayoutSolver.mm; sourceTree = SOURCE_ROOT; }; 87 | C25F4FA816F88EDE00A8671C /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 88 | C25F4FA916F88EDE00A8671C /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 89 | C25F4FAA16F88EDE00A8671C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 90 | C25F4FC716F8900D00A8671C /* DLConstraintLayoutDemoOSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DLConstraintLayoutDemoOSX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 91 | C25F4FCB16F8900D00A8671C /* DLConstraintLayoutDemoOSX-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DLConstraintLayoutDemoOSX-Info.plist"; sourceTree = ""; }; 92 | C25F4FCD16F8900D00A8671C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 93 | C25F4FCF16F8900D00A8671C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 94 | C25F4FD116F8900D00A8671C /* DLConstraintLayoutDemoOSX-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DLConstraintLayoutDemoOSX-Prefix.pch"; sourceTree = ""; }; 95 | C25F4FD516F8900D00A8671C /* DLCLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DLCLAppDelegate.h; sourceTree = ""; }; 96 | C25F4FD616F8900D00A8671C /* DLCLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DLCLAppDelegate.m; sourceTree = ""; }; 97 | C25F4FD916F8900E00A8671C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 98 | C25F4FE816F8962A00A8671C /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; 99 | C25F4FEA16F897E400A8671C /* DLCLViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DLCLViewController.h; sourceTree = ""; }; 100 | C25F4FEB16F897E500A8671C /* DLCLViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DLCLViewController.m; sourceTree = ""; }; 101 | C25F4FEE16F89BBF00A8671C /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; 102 | C25F501D16FBBAB700A8671C /* DLConstraintLayout+Protected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "DLConstraintLayout+Protected.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 103 | C2BF8A9D16F0E366005F4627 /* DLConstraintLayoutDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DLConstraintLayoutDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 104 | C2BF8AA016F0E366005F4627 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 105 | C2BF8AA216F0E366005F4627 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 106 | C2BF8AA416F0E366005F4627 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 107 | C2BF8AAA16F0E366005F4627 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 108 | C2BF8AAC16F0E366005F4627 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 109 | C2BF8AAF16F0E366005F4627 /* DLCLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DLCLAppDelegate.h; sourceTree = ""; }; 110 | C2BF8AB016F0E366005F4627 /* DLCLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DLCLAppDelegate.m; sourceTree = ""; }; 111 | C2BF8AB216F0E366005F4627 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 112 | C2BF8AB416F0E366005F4627 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 113 | C2BF8AB616F0E366005F4627 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 114 | C2BF8AB916F0E366005F4627 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; }; 115 | C2BF8ABC16F0E366005F4627 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; }; 116 | C2BF8AC616F0E366005F4627 /* DLConstraintLayoutTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DLConstraintLayoutTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 117 | C2BF8AC716F0E366005F4627 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 118 | C2BF8ACF16F0E366005F4627 /* DLConstraintLayoutTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DLConstraintLayoutTests-Info.plist"; sourceTree = ""; }; 119 | C2BF8AD116F0E366005F4627 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 120 | C2BF8AD416F0E366005F4627 /* DLCLConstraintLayoutTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DLCLConstraintLayoutTests.m; sourceTree = ""; }; 121 | C2BF8AE216F0E404005F4627 /* libDLConstraintLayout.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDLConstraintLayout.a; sourceTree = BUILT_PRODUCTS_DIR; }; 122 | C2BF8AE616F0E404005F4627 /* DLConstraintLayout-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DLConstraintLayout-Prefix.pch"; sourceTree = ""; }; 123 | C2BF8AE716F0E404005F4627 /* DLConstraintLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DLConstraintLayout.h; sourceTree = ""; }; 124 | C2BF8AE916F0E404005F4627 /* DLConstraintLayout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DLConstraintLayout.m; sourceTree = ""; }; 125 | C2BF8AEE16F0E449005F4627 /* DLConstraintLayoutDemo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "DLConstraintLayoutDemo-Info.plist"; sourceTree = ""; }; 126 | C2BF8AEF16F0E449005F4627 /* DLConstraintLayoutDemo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DLConstraintLayoutDemo-Prefix.pch"; sourceTree = ""; }; 127 | C2BF8AF916F0EA92005F4627 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 128 | C2EDF5D717A279B600F5528B /* CALayer+DLConstraintLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "CALayer+DLConstraintLayout.h"; path = "DLConstraintLayout/CALayer+DLConstraintLayout.h"; sourceTree = SOURCE_ROOT; }; 129 | C2EDF5D817A279B600F5528B /* CALayer+DLConstraintLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "CALayer+DLConstraintLayout.m"; path = "DLConstraintLayout/CALayer+DLConstraintLayout.m"; sourceTree = SOURCE_ROOT; }; 130 | C2EDF5DB17A279D100F5528B /* DLCLConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DLCLConstraint.h; path = DLConstraintLayout/DLCLConstraint.h; sourceTree = SOURCE_ROOT; }; 131 | C2EDF5DC17A279D100F5528B /* DLCLConstraint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DLCLConstraint.m; path = DLConstraintLayout/DLCLConstraint.m; sourceTree = SOURCE_ROOT; }; 132 | C2EDF5DD17A279D100F5528B /* DLCLConstraint+Protected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "DLCLConstraint+Protected.h"; path = "DLConstraintLayout/DLCLConstraint+Protected.h"; sourceTree = SOURCE_ROOT; }; 133 | C2EDF5DE17A279D100F5528B /* DLCLConstraintLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DLCLConstraintLayoutManager.h; path = DLConstraintLayout/DLCLConstraintLayoutManager.h; sourceTree = SOURCE_ROOT; }; 134 | C2EDF5DF17A279D100F5528B /* DLCLConstraintLayoutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DLCLConstraintLayoutManager.m; path = DLConstraintLayout/DLCLConstraintLayoutManager.m; sourceTree = SOURCE_ROOT; }; 135 | C2EDF5E017A279D100F5528B /* DLCLConstraintLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DLCLConstraintLayoutNode.h; path = DLConstraintLayout/DLCLConstraintLayoutNode.h; sourceTree = SOURCE_ROOT; }; 136 | C2EDF5E117A279D100F5528B /* DLCLConstraintLayoutNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DLCLConstraintLayoutNode.m; path = DLConstraintLayout/DLCLConstraintLayoutNode.m; sourceTree = SOURCE_ROOT; }; 137 | C2EDF5E217A279D100F5528B /* DLCLConstraintLayoutSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DLCLConstraintLayoutSolver.h; path = DLConstraintLayout/DLCLConstraintLayoutSolver.h; sourceTree = SOURCE_ROOT; }; 138 | /* End PBXFileReference section */ 139 | 140 | /* Begin PBXFrameworksBuildPhase section */ 141 | C25F4FC416F8900D00A8671C /* Frameworks */ = { 142 | isa = PBXFrameworksBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | C25F4FEF16F89BBF00A8671C /* QuartzCore.framework in Frameworks */, 146 | C25F4FE916F8962A00A8671C /* Cocoa.framework in Frameworks */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | C2BF8A9A16F0E366005F4627 /* Frameworks */ = { 151 | isa = PBXFrameworksBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | C2A672DA16F2CC24004062E8 /* libDLConstraintLayout.a in Frameworks */, 155 | C2A672DB16F2CC37004062E8 /* QuartzCore.framework in Frameworks */, 156 | C2BF8AA116F0E366005F4627 /* UIKit.framework in Frameworks */, 157 | C2BF8AA316F0E366005F4627 /* Foundation.framework in Frameworks */, 158 | C2BF8AA516F0E366005F4627 /* CoreGraphics.framework in Frameworks */, 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | C2BF8AC216F0E366005F4627 /* Frameworks */ = { 163 | isa = PBXFrameworksBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | C25F501C16FA582200A8671C /* CoreGraphics.framework in Frameworks */, 167 | C2BF8AC816F0E366005F4627 /* SenTestingKit.framework in Frameworks */, 168 | C2BF8AC916F0E366005F4627 /* UIKit.framework in Frameworks */, 169 | C2BF8ACA16F0E366005F4627 /* Foundation.framework in Frameworks */, 170 | C25F4FF316F8E3B900A8671C /* libDLConstraintLayout.a in Frameworks */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | C2BF8ADF16F0E404005F4627 /* Frameworks */ = { 175 | isa = PBXFrameworksBuildPhase; 176 | buildActionMask = 2147483647; 177 | files = ( 178 | C2BF8AFA16F0EA92005F4627 /* QuartzCore.framework in Frameworks */, 179 | C2BF8AE316F0E404005F4627 /* Foundation.framework in Frameworks */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXFrameworksBuildPhase section */ 184 | 185 | /* Begin PBXGroup section */ 186 | C25F4FA716F88EDE00A8671C /* Other Frameworks */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | C25F4FA816F88EDE00A8671C /* AppKit.framework */, 190 | C25F4FA916F88EDE00A8671C /* CoreData.framework */, 191 | C25F4FAA16F88EDE00A8671C /* Foundation.framework */, 192 | ); 193 | name = "Other Frameworks"; 194 | sourceTree = ""; 195 | }; 196 | C25F4FC916F8900D00A8671C /* DLConstraintLayoutDemoOSX */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | C25F4FD516F8900D00A8671C /* DLCLAppDelegate.h */, 200 | C25F4FD616F8900D00A8671C /* DLCLAppDelegate.m */, 201 | C25F4FD816F8900E00A8671C /* MainMenu.xib */, 202 | C25F4FCA16F8900D00A8671C /* Supporting Files */, 203 | ); 204 | path = DLConstraintLayoutDemoOSX; 205 | sourceTree = ""; 206 | }; 207 | C25F4FCA16F8900D00A8671C /* Supporting Files */ = { 208 | isa = PBXGroup; 209 | children = ( 210 | C25F4FCB16F8900D00A8671C /* DLConstraintLayoutDemoOSX-Info.plist */, 211 | C25F4FCC16F8900D00A8671C /* InfoPlist.strings */, 212 | C25F4FCF16F8900D00A8671C /* main.m */, 213 | C25F4FD116F8900D00A8671C /* DLConstraintLayoutDemoOSX-Prefix.pch */, 214 | ); 215 | name = "Supporting Files"; 216 | sourceTree = ""; 217 | }; 218 | C25F4FDE16F8905000A8671C /* DLConstraintLayoutDemoShared */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | C25F4FEA16F897E400A8671C /* DLCLViewController.h */, 222 | C25F4FEB16F897E500A8671C /* DLCLViewController.m */, 223 | ); 224 | path = DLConstraintLayoutDemoShared; 225 | sourceTree = ""; 226 | }; 227 | C2BF8A9416F0E366005F4627 = { 228 | isa = PBXGroup; 229 | children = ( 230 | C2BF8AE416F0E404005F4627 /* DLConstraintLayout */, 231 | C2BF8ACD16F0E366005F4627 /* DLConstraintLayoutTests */, 232 | C25F4FDE16F8905000A8671C /* DLConstraintLayoutDemoShared */, 233 | C2BF8AA616F0E366005F4627 /* DLConstraintLayoutDemo */, 234 | C25F4FC916F8900D00A8671C /* DLConstraintLayoutDemoOSX */, 235 | C2BF8A9F16F0E366005F4627 /* Frameworks */, 236 | C2BF8A9E16F0E366005F4627 /* Products */, 237 | ); 238 | sourceTree = ""; 239 | }; 240 | C2BF8A9E16F0E366005F4627 /* Products */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | C2BF8A9D16F0E366005F4627 /* DLConstraintLayoutDemo.app */, 244 | C2BF8AC616F0E366005F4627 /* DLConstraintLayoutTests.octest */, 245 | C2BF8AE216F0E404005F4627 /* libDLConstraintLayout.a */, 246 | C25F4FC716F8900D00A8671C /* DLConstraintLayoutDemoOSX.app */, 247 | ); 248 | name = Products; 249 | sourceTree = ""; 250 | }; 251 | C2BF8A9F16F0E366005F4627 /* Frameworks */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | C2BF8AA016F0E366005F4627 /* UIKit.framework */, 255 | C2BF8AA216F0E366005F4627 /* Foundation.framework */, 256 | C2BF8AF916F0EA92005F4627 /* QuartzCore.framework */, 257 | C2BF8AA416F0E366005F4627 /* CoreGraphics.framework */, 258 | C2BF8AC716F0E366005F4627 /* SenTestingKit.framework */, 259 | C25F4FE816F8962A00A8671C /* Cocoa.framework */, 260 | C25F4FEE16F89BBF00A8671C /* QuartzCore.framework */, 261 | C25F4FA716F88EDE00A8671C /* Other Frameworks */, 262 | ); 263 | name = Frameworks; 264 | sourceTree = ""; 265 | }; 266 | C2BF8AA616F0E366005F4627 /* DLConstraintLayoutDemo */ = { 267 | isa = PBXGroup; 268 | children = ( 269 | C2BF8AAF16F0E366005F4627 /* DLCLAppDelegate.h */, 270 | C2BF8AB016F0E366005F4627 /* DLCLAppDelegate.m */, 271 | C2BF8AB816F0E366005F4627 /* MainStoryboard_iPhone.storyboard */, 272 | C2BF8ABB16F0E366005F4627 /* MainStoryboard_iPad.storyboard */, 273 | C2BF8AA716F0E366005F4627 /* Supporting Files */, 274 | ); 275 | path = DLConstraintLayoutDemo; 276 | sourceTree = ""; 277 | }; 278 | C2BF8AA716F0E366005F4627 /* Supporting Files */ = { 279 | isa = PBXGroup; 280 | children = ( 281 | C2BF8AEE16F0E449005F4627 /* DLConstraintLayoutDemo-Info.plist */, 282 | C2BF8AEF16F0E449005F4627 /* DLConstraintLayoutDemo-Prefix.pch */, 283 | C2BF8AA916F0E366005F4627 /* InfoPlist.strings */, 284 | C2BF8AAC16F0E366005F4627 /* main.m */, 285 | C2BF8AB216F0E366005F4627 /* Default.png */, 286 | C2BF8AB416F0E366005F4627 /* Default@2x.png */, 287 | C2BF8AB616F0E366005F4627 /* Default-568h@2x.png */, 288 | ); 289 | name = "Supporting Files"; 290 | sourceTree = ""; 291 | }; 292 | C2BF8ACD16F0E366005F4627 /* DLConstraintLayoutTests */ = { 293 | isa = PBXGroup; 294 | children = ( 295 | C2BF8AD416F0E366005F4627 /* DLCLConstraintLayoutTests.m */, 296 | C2BF8ACE16F0E366005F4627 /* Supporting Files */, 297 | ); 298 | path = DLConstraintLayoutTests; 299 | sourceTree = ""; 300 | }; 301 | C2BF8ACE16F0E366005F4627 /* Supporting Files */ = { 302 | isa = PBXGroup; 303 | children = ( 304 | C2BF8ACF16F0E366005F4627 /* DLConstraintLayoutTests-Info.plist */, 305 | C2BF8AD016F0E366005F4627 /* InfoPlist.strings */, 306 | ); 307 | name = "Supporting Files"; 308 | sourceTree = ""; 309 | }; 310 | C2BF8AE416F0E404005F4627 /* DLConstraintLayout */ = { 311 | isa = PBXGroup; 312 | children = ( 313 | C2BF8AE716F0E404005F4627 /* DLConstraintLayout.h */, 314 | C25F501D16FBBAB700A8671C /* DLConstraintLayout+Protected.h */, 315 | C2BF8AE916F0E404005F4627 /* DLConstraintLayout.m */, 316 | C2BF8AFD16F0EE37005F4627 /* Categories */, 317 | C2BF8AF216F0E5F6005F4627 /* Classes */, 318 | C2BF8AE516F0E404005F4627 /* Supporting Files */, 319 | ); 320 | path = DLConstraintLayout; 321 | sourceTree = ""; 322 | }; 323 | C2BF8AE516F0E404005F4627 /* Supporting Files */ = { 324 | isa = PBXGroup; 325 | children = ( 326 | C2BF8AE616F0E404005F4627 /* DLConstraintLayout-Prefix.pch */, 327 | ); 328 | name = "Supporting Files"; 329 | sourceTree = ""; 330 | }; 331 | C2BF8AF216F0E5F6005F4627 /* Classes */ = { 332 | isa = PBXGroup; 333 | children = ( 334 | C2EDF5DB17A279D100F5528B /* DLCLConstraint.h */, 335 | C2EDF5DC17A279D100F5528B /* DLCLConstraint.m */, 336 | C2EDF5DD17A279D100F5528B /* DLCLConstraint+Protected.h */, 337 | C2EDF5DE17A279D100F5528B /* DLCLConstraintLayoutManager.h */, 338 | C2EDF5DF17A279D100F5528B /* DLCLConstraintLayoutManager.m */, 339 | C2EDF5E017A279D100F5528B /* DLCLConstraintLayoutNode.h */, 340 | C2EDF5E117A279D100F5528B /* DLCLConstraintLayoutNode.m */, 341 | C2EDF5E217A279D100F5528B /* DLCLConstraintLayoutSolver.h */, 342 | A4AF623218AB8CB7003344C0 /* DLCLConstraintLayoutSolver.mm */, 343 | ); 344 | path = Classes; 345 | sourceTree = ""; 346 | }; 347 | C2BF8AFD16F0EE37005F4627 /* Categories */ = { 348 | isa = PBXGroup; 349 | children = ( 350 | C2EDF5D717A279B600F5528B /* CALayer+DLConstraintLayout.h */, 351 | C2EDF5D817A279B600F5528B /* CALayer+DLConstraintLayout.m */, 352 | ); 353 | path = Categories; 354 | sourceTree = ""; 355 | }; 356 | /* End PBXGroup section */ 357 | 358 | /* Begin PBXNativeTarget section */ 359 | C25F4FC616F8900D00A8671C /* DLConstraintLayoutDemoOSX */ = { 360 | isa = PBXNativeTarget; 361 | buildConfigurationList = C25F4FDB16F8900E00A8671C /* Build configuration list for PBXNativeTarget "DLConstraintLayoutDemoOSX" */; 362 | buildPhases = ( 363 | C25F4FC316F8900D00A8671C /* Sources */, 364 | C25F4FC416F8900D00A8671C /* Frameworks */, 365 | C25F4FC516F8900D00A8671C /* Resources */, 366 | ); 367 | buildRules = ( 368 | ); 369 | dependencies = ( 370 | ); 371 | name = DLConstraintLayoutDemoOSX; 372 | productName = DLConstraintLayoutDemoOSX; 373 | productReference = C25F4FC716F8900D00A8671C /* DLConstraintLayoutDemoOSX.app */; 374 | productType = "com.apple.product-type.application"; 375 | }; 376 | C2BF8A9C16F0E366005F4627 /* DLConstraintLayoutDemo */ = { 377 | isa = PBXNativeTarget; 378 | buildConfigurationList = C2BF8AD816F0E366005F4627 /* Build configuration list for PBXNativeTarget "DLConstraintLayoutDemo" */; 379 | buildPhases = ( 380 | C2BF8A9916F0E366005F4627 /* Sources */, 381 | C2BF8A9A16F0E366005F4627 /* Frameworks */, 382 | C2BF8A9B16F0E366005F4627 /* Resources */, 383 | ); 384 | buildRules = ( 385 | ); 386 | dependencies = ( 387 | C2A672D916F2CC20004062E8 /* PBXTargetDependency */, 388 | ); 389 | name = DLConstraintLayoutDemo; 390 | productName = DLConstraintLayout; 391 | productReference = C2BF8A9D16F0E366005F4627 /* DLConstraintLayoutDemo.app */; 392 | productType = "com.apple.product-type.application"; 393 | }; 394 | C2BF8AC516F0E366005F4627 /* DLConstraintLayoutTests */ = { 395 | isa = PBXNativeTarget; 396 | buildConfigurationList = C2BF8ADB16F0E366005F4627 /* Build configuration list for PBXNativeTarget "DLConstraintLayoutTests" */; 397 | buildPhases = ( 398 | C2BF8AC116F0E366005F4627 /* Sources */, 399 | C2BF8AC216F0E366005F4627 /* Frameworks */, 400 | C2BF8AC316F0E366005F4627 /* Resources */, 401 | C2BF8AC416F0E366005F4627 /* ShellScript */, 402 | ); 403 | buildRules = ( 404 | ); 405 | dependencies = ( 406 | C25F4FF216F8E3A900A8671C /* PBXTargetDependency */, 407 | ); 408 | name = DLConstraintLayoutTests; 409 | productName = DLConstraintLayoutTests; 410 | productReference = C2BF8AC616F0E366005F4627 /* DLConstraintLayoutTests.octest */; 411 | productType = "com.apple.product-type.bundle"; 412 | }; 413 | C2BF8AE116F0E404005F4627 /* DLConstraintLayout */ = { 414 | isa = PBXNativeTarget; 415 | buildConfigurationList = C2BF8AEB16F0E404005F4627 /* Build configuration list for PBXNativeTarget "DLConstraintLayout" */; 416 | buildPhases = ( 417 | C2BF8ADE16F0E404005F4627 /* Sources */, 418 | C2BF8ADF16F0E404005F4627 /* Frameworks */, 419 | C2BF8AE016F0E404005F4627 /* CopyFiles */, 420 | ); 421 | buildRules = ( 422 | ); 423 | dependencies = ( 424 | ); 425 | name = DLConstraintLayout; 426 | productName = DLConstraintLayout; 427 | productReference = C2BF8AE216F0E404005F4627 /* libDLConstraintLayout.a */; 428 | productType = "com.apple.product-type.library.static"; 429 | }; 430 | /* End PBXNativeTarget section */ 431 | 432 | /* Begin PBXProject section */ 433 | C2BF8A9516F0E366005F4627 /* Project object */ = { 434 | isa = PBXProject; 435 | attributes = { 436 | CLASSPREFIX = DLCL; 437 | LastUpgradeCheck = 0510; 438 | ORGANIZATIONNAME = Regexident; 439 | }; 440 | buildConfigurationList = C2BF8A9816F0E366005F4627 /* Build configuration list for PBXProject "DLConstraintLayout" */; 441 | compatibilityVersion = "Xcode 3.2"; 442 | developmentRegion = English; 443 | hasScannedForEncodings = 0; 444 | knownRegions = ( 445 | en, 446 | ); 447 | mainGroup = C2BF8A9416F0E366005F4627; 448 | productRefGroup = C2BF8A9E16F0E366005F4627 /* Products */; 449 | projectDirPath = ""; 450 | projectRoot = ""; 451 | targets = ( 452 | C2BF8AE116F0E404005F4627 /* DLConstraintLayout */, 453 | C2BF8AC516F0E366005F4627 /* DLConstraintLayoutTests */, 454 | C2BF8A9C16F0E366005F4627 /* DLConstraintLayoutDemo */, 455 | C25F4FC616F8900D00A8671C /* DLConstraintLayoutDemoOSX */, 456 | ); 457 | }; 458 | /* End PBXProject section */ 459 | 460 | /* Begin PBXResourcesBuildPhase section */ 461 | C25F4FC516F8900D00A8671C /* Resources */ = { 462 | isa = PBXResourcesBuildPhase; 463 | buildActionMask = 2147483647; 464 | files = ( 465 | C25F4FCE16F8900D00A8671C /* InfoPlist.strings in Resources */, 466 | C25F4FDA16F8900E00A8671C /* MainMenu.xib in Resources */, 467 | ); 468 | runOnlyForDeploymentPostprocessing = 0; 469 | }; 470 | C2BF8A9B16F0E366005F4627 /* Resources */ = { 471 | isa = PBXResourcesBuildPhase; 472 | buildActionMask = 2147483647; 473 | files = ( 474 | C2BF8AAB16F0E366005F4627 /* InfoPlist.strings in Resources */, 475 | C2BF8AB316F0E366005F4627 /* Default.png in Resources */, 476 | C2BF8AB516F0E366005F4627 /* Default@2x.png in Resources */, 477 | C2BF8AB716F0E366005F4627 /* Default-568h@2x.png in Resources */, 478 | C2BF8ABA16F0E366005F4627 /* MainStoryboard_iPhone.storyboard in Resources */, 479 | C2BF8ABD16F0E366005F4627 /* MainStoryboard_iPad.storyboard in Resources */, 480 | ); 481 | runOnlyForDeploymentPostprocessing = 0; 482 | }; 483 | C2BF8AC316F0E366005F4627 /* Resources */ = { 484 | isa = PBXResourcesBuildPhase; 485 | buildActionMask = 2147483647; 486 | files = ( 487 | C2BF8AD216F0E366005F4627 /* InfoPlist.strings in Resources */, 488 | ); 489 | runOnlyForDeploymentPostprocessing = 0; 490 | }; 491 | /* End PBXResourcesBuildPhase section */ 492 | 493 | /* Begin PBXShellScriptBuildPhase section */ 494 | C2BF8AC416F0E366005F4627 /* ShellScript */ = { 495 | isa = PBXShellScriptBuildPhase; 496 | buildActionMask = 2147483647; 497 | files = ( 498 | ); 499 | inputPaths = ( 500 | ); 501 | outputPaths = ( 502 | ); 503 | runOnlyForDeploymentPostprocessing = 0; 504 | shellPath = /bin/sh; 505 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 506 | }; 507 | /* End PBXShellScriptBuildPhase section */ 508 | 509 | /* Begin PBXSourcesBuildPhase section */ 510 | C25F4FC316F8900D00A8671C /* Sources */ = { 511 | isa = PBXSourcesBuildPhase; 512 | buildActionMask = 2147483647; 513 | files = ( 514 | C25F4FD016F8900D00A8671C /* main.m in Sources */, 515 | C25F4FD716F8900D00A8671C /* DLCLAppDelegate.m in Sources */, 516 | C25F4FED16F897E500A8671C /* DLCLViewController.m in Sources */, 517 | C25F501E16FBCBEC00A8671C /* DLConstraintLayout.m in Sources */, 518 | C2EDF5DA17A279B600F5528B /* CALayer+DLConstraintLayout.m in Sources */, 519 | A4AF623418AB8EB9003344C0 /* DLCLConstraintLayoutSolver.mm in Sources */, 520 | C2EDF5E517A279D100F5528B /* DLCLConstraint.m in Sources */, 521 | C2EDF5E717A279D100F5528B /* DLCLConstraintLayoutManager.m in Sources */, 522 | C2EDF5E917A279D100F5528B /* DLCLConstraintLayoutNode.m in Sources */, 523 | ); 524 | runOnlyForDeploymentPostprocessing = 0; 525 | }; 526 | C2BF8A9916F0E366005F4627 /* Sources */ = { 527 | isa = PBXSourcesBuildPhase; 528 | buildActionMask = 2147483647; 529 | files = ( 530 | C2BF8AAD16F0E366005F4627 /* main.m in Sources */, 531 | C2BF8AB116F0E366005F4627 /* DLCLAppDelegate.m in Sources */, 532 | C25F4FEC16F897E500A8671C /* DLCLViewController.m in Sources */, 533 | ); 534 | runOnlyForDeploymentPostprocessing = 0; 535 | }; 536 | C2BF8AC116F0E366005F4627 /* Sources */ = { 537 | isa = PBXSourcesBuildPhase; 538 | buildActionMask = 2147483647; 539 | files = ( 540 | C2BF8AD516F0E366005F4627 /* DLCLConstraintLayoutTests.m in Sources */, 541 | ); 542 | runOnlyForDeploymentPostprocessing = 0; 543 | }; 544 | C2BF8ADE16F0E404005F4627 /* Sources */ = { 545 | isa = PBXSourcesBuildPhase; 546 | buildActionMask = 2147483647; 547 | files = ( 548 | C2BF8AEA16F0E404005F4627 /* DLConstraintLayout.m in Sources */, 549 | C2EDF5D917A279B600F5528B /* CALayer+DLConstraintLayout.m in Sources */, 550 | C2EDF5E417A279D100F5528B /* DLCLConstraint.m in Sources */, 551 | C2EDF5E617A279D100F5528B /* DLCLConstraintLayoutManager.m in Sources */, 552 | C2EDF5E817A279D100F5528B /* DLCLConstraintLayoutNode.m in Sources */, 553 | A4AF623318AB8CB7003344C0 /* DLCLConstraintLayoutSolver.mm in Sources */, 554 | ); 555 | runOnlyForDeploymentPostprocessing = 0; 556 | }; 557 | /* End PBXSourcesBuildPhase section */ 558 | 559 | /* Begin PBXTargetDependency section */ 560 | C25F4FF216F8E3A900A8671C /* PBXTargetDependency */ = { 561 | isa = PBXTargetDependency; 562 | target = C2BF8AE116F0E404005F4627 /* DLConstraintLayout */; 563 | targetProxy = C25F4FF116F8E3A900A8671C /* PBXContainerItemProxy */; 564 | }; 565 | C2A672D916F2CC20004062E8 /* PBXTargetDependency */ = { 566 | isa = PBXTargetDependency; 567 | target = C2BF8AE116F0E404005F4627 /* DLConstraintLayout */; 568 | targetProxy = C2A672D816F2CC20004062E8 /* PBXContainerItemProxy */; 569 | }; 570 | /* End PBXTargetDependency section */ 571 | 572 | /* Begin PBXVariantGroup section */ 573 | C25F4FCC16F8900D00A8671C /* InfoPlist.strings */ = { 574 | isa = PBXVariantGroup; 575 | children = ( 576 | C25F4FCD16F8900D00A8671C /* en */, 577 | ); 578 | name = InfoPlist.strings; 579 | sourceTree = ""; 580 | }; 581 | C25F4FD816F8900E00A8671C /* MainMenu.xib */ = { 582 | isa = PBXVariantGroup; 583 | children = ( 584 | C25F4FD916F8900E00A8671C /* en */, 585 | ); 586 | name = MainMenu.xib; 587 | sourceTree = ""; 588 | }; 589 | C2BF8AA916F0E366005F4627 /* InfoPlist.strings */ = { 590 | isa = PBXVariantGroup; 591 | children = ( 592 | C2BF8AAA16F0E366005F4627 /* en */, 593 | ); 594 | name = InfoPlist.strings; 595 | sourceTree = ""; 596 | }; 597 | C2BF8AB816F0E366005F4627 /* MainStoryboard_iPhone.storyboard */ = { 598 | isa = PBXVariantGroup; 599 | children = ( 600 | C2BF8AB916F0E366005F4627 /* en */, 601 | ); 602 | name = MainStoryboard_iPhone.storyboard; 603 | sourceTree = ""; 604 | }; 605 | C2BF8ABB16F0E366005F4627 /* MainStoryboard_iPad.storyboard */ = { 606 | isa = PBXVariantGroup; 607 | children = ( 608 | C2BF8ABC16F0E366005F4627 /* en */, 609 | ); 610 | name = MainStoryboard_iPad.storyboard; 611 | sourceTree = ""; 612 | }; 613 | C2BF8AD016F0E366005F4627 /* InfoPlist.strings */ = { 614 | isa = PBXVariantGroup; 615 | children = ( 616 | C2BF8AD116F0E366005F4627 /* en */, 617 | ); 618 | name = InfoPlist.strings; 619 | sourceTree = ""; 620 | }; 621 | /* End PBXVariantGroup section */ 622 | 623 | /* Begin XCBuildConfiguration section */ 624 | C25F4FDC16F8900E00A8671C /* Debug */ = { 625 | isa = XCBuildConfiguration; 626 | buildSettings = { 627 | CLANG_ENABLE_OBJC_ARC = YES; 628 | COMBINE_HIDPI_IMAGES = YES; 629 | FRAMEWORK_SEARCH_PATHS = ( 630 | "$(inherited)", 631 | "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", 632 | ); 633 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 634 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 635 | GCC_PREFIX_HEADER = "DLConstraintLayoutDemoOSX/DLConstraintLayoutDemoOSX-Prefix.pch"; 636 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 637 | INFOPLIST_FILE = "DLConstraintLayoutDemoOSX/DLConstraintLayoutDemoOSX-Info.plist"; 638 | MACOSX_DEPLOYMENT_TARGET = 10.8; 639 | OTHER_LDFLAGS = ""; 640 | PRODUCT_NAME = "$(TARGET_NAME)"; 641 | SDKROOT = macosx; 642 | WRAPPER_EXTENSION = app; 643 | }; 644 | name = Debug; 645 | }; 646 | C25F4FDD16F8900E00A8671C /* Release */ = { 647 | isa = XCBuildConfiguration; 648 | buildSettings = { 649 | CLANG_ENABLE_OBJC_ARC = YES; 650 | COMBINE_HIDPI_IMAGES = YES; 651 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 652 | FRAMEWORK_SEARCH_PATHS = ( 653 | "$(inherited)", 654 | "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Library/Frameworks\"", 655 | ); 656 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 657 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 658 | GCC_PREFIX_HEADER = "DLConstraintLayoutDemoOSX/DLConstraintLayoutDemoOSX-Prefix.pch"; 659 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 660 | INFOPLIST_FILE = "DLConstraintLayoutDemoOSX/DLConstraintLayoutDemoOSX-Info.plist"; 661 | MACOSX_DEPLOYMENT_TARGET = 10.8; 662 | OTHER_LDFLAGS = ""; 663 | PRODUCT_NAME = "$(TARGET_NAME)"; 664 | SDKROOT = macosx; 665 | WRAPPER_EXTENSION = app; 666 | }; 667 | name = Release; 668 | }; 669 | C2BF8AD616F0E366005F4627 /* Debug */ = { 670 | isa = XCBuildConfiguration; 671 | buildSettings = { 672 | ALWAYS_SEARCH_USER_PATHS = NO; 673 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 674 | CLANG_CXX_LIBRARY = "libc++"; 675 | CLANG_ENABLE_OBJC_ARC = YES; 676 | CLANG_WARN_CONSTANT_CONVERSION = YES; 677 | CLANG_WARN_EMPTY_BODY = YES; 678 | CLANG_WARN_ENUM_CONVERSION = YES; 679 | CLANG_WARN_INT_CONVERSION = YES; 680 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 681 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 682 | COPY_PHASE_STRIP = NO; 683 | GCC_C_LANGUAGE_STANDARD = gnu99; 684 | GCC_DYNAMIC_NO_PIC = NO; 685 | GCC_OPTIMIZATION_LEVEL = 0; 686 | GCC_PREPROCESSOR_DEFINITIONS = ( 687 | "DEBUG=1", 688 | DLCL_USE_CPP_SOLVER, 689 | ); 690 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 691 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 692 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 693 | GCC_WARN_UNUSED_VARIABLE = YES; 694 | ONLY_ACTIVE_ARCH = YES; 695 | OTHER_CFLAGS = "-DDLCL_USE_NATIVE_CA_NAMESPACE"; 696 | SDKROOT = iphoneos; 697 | TARGETED_DEVICE_FAMILY = "1,2"; 698 | }; 699 | name = Debug; 700 | }; 701 | C2BF8AD716F0E366005F4627 /* Release */ = { 702 | isa = XCBuildConfiguration; 703 | buildSettings = { 704 | ALWAYS_SEARCH_USER_PATHS = NO; 705 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 706 | CLANG_CXX_LIBRARY = "libc++"; 707 | CLANG_ENABLE_OBJC_ARC = YES; 708 | CLANG_WARN_CONSTANT_CONVERSION = YES; 709 | CLANG_WARN_EMPTY_BODY = YES; 710 | CLANG_WARN_ENUM_CONVERSION = YES; 711 | CLANG_WARN_INT_CONVERSION = YES; 712 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 713 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 714 | COPY_PHASE_STRIP = YES; 715 | GCC_C_LANGUAGE_STANDARD = gnu99; 716 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 717 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 718 | GCC_WARN_UNUSED_VARIABLE = YES; 719 | OTHER_CFLAGS = ( 720 | "-DDLCL_USE_NATIVE_CA_NAMESPACE", 721 | "-DNS_BLOCK_ASSERTIONS=1", 722 | ); 723 | SDKROOT = iphoneos; 724 | TARGETED_DEVICE_FAMILY = "1,2"; 725 | VALIDATE_PRODUCT = YES; 726 | }; 727 | name = Release; 728 | }; 729 | C2BF8AD916F0E366005F4627 /* Debug */ = { 730 | isa = XCBuildConfiguration; 731 | buildSettings = { 732 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 733 | GCC_PREFIX_HEADER = "DLConstraintLayoutDemo/DLConstraintLayoutDemo-Prefix.pch"; 734 | INFOPLIST_FILE = "DLConstraintLayoutDemo/DLConstraintLayoutDemo-Info.plist"; 735 | OTHER_LDFLAGS = ( 736 | "-lc++", 737 | "-ObjC", 738 | ); 739 | PRODUCT_NAME = "$(TARGET_NAME)"; 740 | WRAPPER_EXTENSION = app; 741 | }; 742 | name = Debug; 743 | }; 744 | C2BF8ADA16F0E366005F4627 /* Release */ = { 745 | isa = XCBuildConfiguration; 746 | buildSettings = { 747 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 748 | GCC_PREFIX_HEADER = "DLConstraintLayoutDemo/DLConstraintLayoutDemo-Prefix.pch"; 749 | INFOPLIST_FILE = "DLConstraintLayoutDemo/DLConstraintLayoutDemo-Info.plist"; 750 | OTHER_LDFLAGS = ( 751 | "-lc++", 752 | "-ObjC", 753 | ); 754 | PRODUCT_NAME = "$(TARGET_NAME)"; 755 | WRAPPER_EXTENSION = app; 756 | }; 757 | name = Release; 758 | }; 759 | C2BF8ADC16F0E366005F4627 /* Debug */ = { 760 | isa = XCBuildConfiguration; 761 | buildSettings = { 762 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/DLConstraintLayoutDemo.app/DLConstraintLayoutDemo"; 763 | FRAMEWORK_SEARCH_PATHS = ( 764 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 765 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 766 | ); 767 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 768 | GCC_PREFIX_HEADER = "DLConstraintLayout/DLConstraintLayout-Prefix.pch"; 769 | INFOPLIST_FILE = "DLConstraintLayoutTests/DLConstraintLayoutTests-Info.plist"; 770 | PRODUCT_NAME = "$(TARGET_NAME)"; 771 | TEST_HOST = "$(BUNDLE_LOADER)"; 772 | WRAPPER_EXTENSION = octest; 773 | }; 774 | name = Debug; 775 | }; 776 | C2BF8ADD16F0E366005F4627 /* Release */ = { 777 | isa = XCBuildConfiguration; 778 | buildSettings = { 779 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/DLConstraintLayoutDemo.app/DLConstraintLayoutDemo"; 780 | FRAMEWORK_SEARCH_PATHS = ( 781 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 782 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 783 | ); 784 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 785 | GCC_PREFIX_HEADER = "DLConstraintLayout/DLConstraintLayout-Prefix.pch"; 786 | INFOPLIST_FILE = "DLConstraintLayoutTests/DLConstraintLayoutTests-Info.plist"; 787 | PRODUCT_NAME = "$(TARGET_NAME)"; 788 | TEST_HOST = "$(BUNDLE_LOADER)"; 789 | WRAPPER_EXTENSION = octest; 790 | }; 791 | name = Release; 792 | }; 793 | C2BF8AEC16F0E404005F4627 /* Debug */ = { 794 | isa = XCBuildConfiguration; 795 | buildSettings = { 796 | CLANG_ENABLE_OBJC_ARC = YES; 797 | DSTROOT = /tmp/DLConstraintLayout.dst; 798 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 799 | GCC_PREFIX_HEADER = "DLConstraintLayout/DLConstraintLayout-Prefix.pch"; 800 | GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; 801 | OTHER_LDFLAGS = "-ObjC"; 802 | PRODUCT_NAME = "$(TARGET_NAME)"; 803 | SKIP_INSTALL = YES; 804 | }; 805 | name = Debug; 806 | }; 807 | C2BF8AED16F0E404005F4627 /* Release */ = { 808 | isa = XCBuildConfiguration; 809 | buildSettings = { 810 | CLANG_ENABLE_OBJC_ARC = YES; 811 | DSTROOT = /tmp/DLConstraintLayout.dst; 812 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 813 | GCC_PREFIX_HEADER = "DLConstraintLayout/DLConstraintLayout-Prefix.pch"; 814 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 815 | OTHER_LDFLAGS = "-ObjC"; 816 | PRODUCT_NAME = "$(TARGET_NAME)"; 817 | SKIP_INSTALL = YES; 818 | }; 819 | name = Release; 820 | }; 821 | /* End XCBuildConfiguration section */ 822 | 823 | /* Begin XCConfigurationList section */ 824 | C25F4FDB16F8900E00A8671C /* Build configuration list for PBXNativeTarget "DLConstraintLayoutDemoOSX" */ = { 825 | isa = XCConfigurationList; 826 | buildConfigurations = ( 827 | C25F4FDC16F8900E00A8671C /* Debug */, 828 | C25F4FDD16F8900E00A8671C /* Release */, 829 | ); 830 | defaultConfigurationIsVisible = 0; 831 | defaultConfigurationName = Release; 832 | }; 833 | C2BF8A9816F0E366005F4627 /* Build configuration list for PBXProject "DLConstraintLayout" */ = { 834 | isa = XCConfigurationList; 835 | buildConfigurations = ( 836 | C2BF8AD616F0E366005F4627 /* Debug */, 837 | C2BF8AD716F0E366005F4627 /* Release */, 838 | ); 839 | defaultConfigurationIsVisible = 0; 840 | defaultConfigurationName = Release; 841 | }; 842 | C2BF8AD816F0E366005F4627 /* Build configuration list for PBXNativeTarget "DLConstraintLayoutDemo" */ = { 843 | isa = XCConfigurationList; 844 | buildConfigurations = ( 845 | C2BF8AD916F0E366005F4627 /* Debug */, 846 | C2BF8ADA16F0E366005F4627 /* Release */, 847 | ); 848 | defaultConfigurationIsVisible = 0; 849 | defaultConfigurationName = Release; 850 | }; 851 | C2BF8ADB16F0E366005F4627 /* Build configuration list for PBXNativeTarget "DLConstraintLayoutTests" */ = { 852 | isa = XCConfigurationList; 853 | buildConfigurations = ( 854 | C2BF8ADC16F0E366005F4627 /* Debug */, 855 | C2BF8ADD16F0E366005F4627 /* Release */, 856 | ); 857 | defaultConfigurationIsVisible = 0; 858 | defaultConfigurationName = Release; 859 | }; 860 | C2BF8AEB16F0E404005F4627 /* Build configuration list for PBXNativeTarget "DLConstraintLayout" */ = { 861 | isa = XCConfigurationList; 862 | buildConfigurations = ( 863 | C2BF8AEC16F0E404005F4627 /* Debug */, 864 | C2BF8AED16F0E404005F4627 /* Release */, 865 | ); 866 | defaultConfigurationIsVisible = 0; 867 | defaultConfigurationName = Release; 868 | }; 869 | /* End XCConfigurationList section */ 870 | }; 871 | rootObject = C2BF8A9516F0E366005F4627 /* Project object */; 872 | } 873 | --------------------------------------------------------------------------------