123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- #import "NSLayoutConstraint+PureLayout.h"
- #import "ALView+PureLayout.h"
- #import "NSArray+PureLayout.h"
- #import "PureLayout+Internal.h"
- #pragma mark - NSLayoutConstraint+PureLayout
- @implementation NSLayoutConstraint (PureLayout)
- #pragma mark Batch Constraint Creation
- static PL__NSMutableArray_of(PL__NSMutableArray_of(NSLayoutConstraint *) *) *_al_arraysOfCreatedConstraints = nil;
- static BOOL _al_isInstallingCreatedConstraints = NO;
- + (PL__NSMutableArray_of(PL__NSMutableArray_of(NSLayoutConstraint *) *) *)al_arraysOfCreatedConstraints
- {
- NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread.");
- if (!_al_arraysOfCreatedConstraints) {
- _al_arraysOfCreatedConstraints = [NSMutableArray new];
- }
- return _al_arraysOfCreatedConstraints;
- }
- + (PL__NSMutableArray_of(NSLayoutConstraint *) *)al_currentArrayOfCreatedConstraints
- {
- return [[self al_arraysOfCreatedConstraints] lastObject];
- }
- + (BOOL)al_preventAutomaticConstraintInstallation
- {
- return (_al_isInstallingCreatedConstraints == NO) && ([[self al_arraysOfCreatedConstraints] count] > 0);
- }
- + (PL__NSArray_of(NSLayoutConstraint *) *)autoCreateAndInstallConstraints:(__attribute__((noescape)) ALConstraintsBlock)block
- {
- NSArray *createdConstraints = [self autoCreateConstraintsWithoutInstalling:block];
- _al_isInstallingCreatedConstraints = YES;
- [createdConstraints autoInstallConstraints];
- _al_isInstallingCreatedConstraints = NO;
- return createdConstraints;
- }
- + (PL__NSArray_of(NSLayoutConstraint *) *)autoCreateConstraintsWithoutInstalling:(__attribute__((noescape)) ALConstraintsBlock)block
- {
- NSAssert(block, @"The constraints block cannot be nil.");
- NSArray *createdConstraints = nil;
- if (block) {
- [[self al_arraysOfCreatedConstraints] addObject:[NSMutableArray new]];
- block();
- createdConstraints = [self al_currentArrayOfCreatedConstraints];
- [[self al_arraysOfCreatedConstraints] removeLastObject];
- }
- return createdConstraints;
- }
- #pragma mark Set Priority For Constraints
- static PL__NSMutableArray_of(NSNumber *) *_al_globalConstraintPriorities = nil;
- + (PL__NSMutableArray_of(NSNumber *) *)al_globalConstraintPriorities
- {
- NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread.");
- if (!_al_globalConstraintPriorities) {
- _al_globalConstraintPriorities = [NSMutableArray new];
- }
- return _al_globalConstraintPriorities;
- }
- + (ALLayoutPriority)al_currentGlobalConstraintPriority
- {
- PL__NSMutableArray_of(NSNumber *) *globalConstraintPriorities = [self al_globalConstraintPriorities];
- if ([globalConstraintPriorities count] == 0) {
- return ALLayoutPriorityRequired;
- }
- return [[globalConstraintPriorities lastObject] floatValue];
- }
- + (BOOL)al_isExecutingPriorityConstraintsBlock
- {
- return [[self al_globalConstraintPriorities] count] > 0;
- }
- + (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(__attribute__((noescape)) ALConstraintsBlock)block
- {
- NSAssert(block, @"The constraints block cannot be nil.");
- if (block) {
- [[self al_globalConstraintPriorities] addObject:@(priority)];
- block();
- [[self al_globalConstraintPriorities] removeLastObject];
- }
- }
- #pragma mark Identify Constraints
- #if PL__PureLayout_MinBaseSDK_iOS_8_0 || PL__PureLayout_MinBaseSDK_OSX_10_10
- static PL__NSMutableArray_of(NSString *) *_al_globalConstraintIdentifiers = nil;
- + (PL__NSMutableArray_of(NSString *) *)al_globalConstraintIdentifiers
- {
- NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread.");
- if (!_al_globalConstraintIdentifiers) {
- _al_globalConstraintIdentifiers = [NSMutableArray new];
- }
- return _al_globalConstraintIdentifiers;
- }
- + (NSString *)al_currentGlobalConstraintIdentifier
- {
- PL__NSMutableArray_of(NSString *) *globalConstraintIdentifiers = [self al_globalConstraintIdentifiers];
- if ([globalConstraintIdentifiers count] == 0) {
- return nil;
- }
- return [globalConstraintIdentifiers lastObject];
- }
- + (void)autoSetIdentifier:(NSString *)identifier forConstraints:(__attribute__((noescape)) ALConstraintsBlock)block
- {
- NSAssert(block, @"The constraints block cannot be nil.");
- NSAssert(identifier, @"The identifier string cannot be nil.");
- if (block) {
- if (identifier) {
- [[self al_globalConstraintIdentifiers] addObject:identifier];
- }
- block();
- if (identifier) {
- [[self al_globalConstraintIdentifiers] removeLastObject];
- }
- }
- }
- - (instancetype)autoIdentify:(NSString *)identifier
- {
- if ([self respondsToSelector:@selector(setIdentifier:)]) {
- self.identifier = identifier;
- }
- return self;
- }
- #endif
- #pragma mark Install & Remove Constraints
- - (void)autoInstall
- {
- #if PL__PureLayout_MinBaseSDK_iOS_8_0 || PL__PureLayout_MinBaseSDK_OSX_10_10
- if ([self respondsToSelector:@selector(setActive:)]) {
- [NSLayoutConstraint al_applyGlobalStateToConstraint:self];
- if ([NSLayoutConstraint al_preventAutomaticConstraintInstallation]) {
- [[NSLayoutConstraint al_currentArrayOfCreatedConstraints] addObject:self];
- } else {
- self.active = YES;
- }
- return;
- }
- #endif
-
- NSAssert(self.firstItem || self.secondItem, @"Can't install a constraint with nil firstItem and secondItem.");
- if (self.firstItem) {
- if (self.secondItem) {
- NSAssert([self.firstItem isKindOfClass:[ALView class]] && [self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if both items are views.");
- ALView *commonSuperview = [self.firstItem al_commonSuperviewWithView:self.secondItem];
- [commonSuperview al_addConstraint:self];
- } else {
- NSAssert([self.firstItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view.");
- [self.firstItem al_addConstraint:self];
- }
- } else {
- NSAssert([self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view.");
- [self.secondItem al_addConstraint:self];
- }
- }
- - (void)autoRemove
- {
- #if PL__PureLayout_MinBaseSDK_iOS_8_0 || PL__PureLayout_MinBaseSDK_OSX_10_10
- if ([self respondsToSelector:@selector(setActive:)]) {
- self.active = NO;
- return;
- }
- #endif
-
- if (self.secondItem) {
- ALView *commonSuperview = [self.firstItem al_commonSuperviewWithView:self.secondItem];
- while (commonSuperview) {
- if ([commonSuperview.constraints containsObject:self]) {
- [commonSuperview removeConstraint:self];
- return;
- }
- commonSuperview = commonSuperview.superview;
- }
- }
- else {
- [self.firstItem removeConstraint:self];
- return;
- }
- NSAssert(nil, @"Failed to remove constraint: %@", self);
- }
- #pragma mark Internal Methods
- + (void)al_applyGlobalStateToConstraint:(NSLayoutConstraint *)constraint
- {
- if ([NSLayoutConstraint al_isExecutingPriorityConstraintsBlock]) {
- constraint.priority = [NSLayoutConstraint al_currentGlobalConstraintPriority];
- }
- #if PL__PureLayout_MinBaseSDK_iOS_8_0 || PL__PureLayout_MinBaseSDK_OSX_10_10
- NSString *globalConstraintIdentifier = [NSLayoutConstraint al_currentGlobalConstraintIdentifier];
- if (globalConstraintIdentifier) {
- [constraint autoIdentify:globalConstraintIdentifier];
- }
- #endif
- }
- + (NSLayoutAttribute)al_layoutAttributeForAttribute:(ALAttribute)attribute
- {
- NSLayoutAttribute layoutAttribute = NSLayoutAttributeNotAnAttribute;
- switch (attribute) {
- case ALEdgeLeft:
- layoutAttribute = NSLayoutAttributeLeft;
- break;
- case ALEdgeRight:
- layoutAttribute = NSLayoutAttributeRight;
- break;
- case ALEdgeTop:
- layoutAttribute = NSLayoutAttributeTop;
- break;
- case ALEdgeBottom:
- layoutAttribute = NSLayoutAttributeBottom;
- break;
- case ALEdgeLeading:
- layoutAttribute = NSLayoutAttributeLeading;
- break;
- case ALEdgeTrailing:
- layoutAttribute = NSLayoutAttributeTrailing;
- break;
- case ALDimensionWidth:
- layoutAttribute = NSLayoutAttributeWidth;
- break;
- case ALDimensionHeight:
- layoutAttribute = NSLayoutAttributeHeight;
- break;
- case ALAxisVertical:
- layoutAttribute = NSLayoutAttributeCenterX;
- break;
- case ALAxisHorizontal:
- layoutAttribute = NSLayoutAttributeCenterY;
- break;
- case ALAxisBaseline:
- layoutAttribute = NSLayoutAttributeBaseline;
- break;
- #if PL__PureLayout_MinBaseSDK_iOS_8_0
- case ALAxisFirstBaseline:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALAxisFirstBaseline is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeFirstBaseline;
- break;
- case ALMarginLeft:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeLeftMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeLeftMargin;
- break;
- case ALMarginRight:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeRightMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeRightMargin;
- break;
- case ALMarginTop:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeTopMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeTopMargin;
- break;
- case ALMarginBottom:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeBottomMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeBottomMargin;
- break;
- case ALMarginLeading:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeLeadingMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeLeadingMargin;
- break;
- case ALMarginTrailing:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeTrailingMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeTrailingMargin;
- break;
- case ALMarginAxisVertical:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALAxisVerticalMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeCenterXWithinMargins;
- break;
- case ALMarginAxisHorizontal:
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"ALAxisHorizontalMargin is only supported on iOS 8.0 or higher.");
- layoutAttribute = NSLayoutAttributeCenterYWithinMargins;
- break;
- #endif
- default:
- NSAssert(nil, @"Not a valid ALAttribute.");
- break;
- }
- return layoutAttribute;
- }
- + (ALLayoutConstraintAxis)al_constraintAxisForAxis:(ALAxis)axis
- {
- ALLayoutConstraintAxis constraintAxis;
- switch (axis) {
- case ALAxisVertical:
- constraintAxis = ALLayoutConstraintAxisVertical;
- break;
- case ALAxisHorizontal:
- case ALAxisBaseline:
- #if PL__PureLayout_MinBaseSDK_iOS_8_0
- case ALAxisFirstBaseline:
- #endif
- constraintAxis = ALLayoutConstraintAxisHorizontal;
- break;
- default:
- NSAssert(nil, @"Not a valid ALAxis.");
- constraintAxis = ALLayoutConstraintAxisHorizontal;
- break;
- }
- return constraintAxis;
- }
- #if PL__PureLayout_MinBaseSDK_iOS_8_0
- + (ALMargin)al_marginForEdge:(ALEdge)edge
- {
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"Margin attributes are only supported on iOS 8.0 or higher.");
- ALMargin margin;
- switch (edge) {
- case ALEdgeLeft:
- margin = ALMarginLeft;
- break;
- case ALEdgeRight:
- margin = ALMarginRight;
- break;
- case ALEdgeTop:
- margin = ALMarginTop;
- break;
- case ALEdgeBottom:
- margin = ALMarginBottom;
- break;
- case ALEdgeLeading:
- margin = ALMarginLeading;
- break;
- case ALEdgeTrailing:
- margin = ALMarginTrailing;
- break;
- default:
- NSAssert(nil, @"Not a valid ALEdge.");
- margin = ALMarginLeft;
- break;
- }
- return margin;
- }
- + (ALMarginAxis)al_marginAxisForAxis:(ALAxis)axis
- {
- NSAssert(PL__PureLayout_MinSysVer_iOS_8_0, @"Margin attributes are only supported on iOS 8.0 or higher.");
- ALMarginAxis marginAxis;
- switch (axis) {
- case ALAxisVertical:
- marginAxis = ALMarginAxisVertical;
- break;
- case ALAxisHorizontal:
- marginAxis = ALMarginAxisHorizontal;
- break;
- case ALAxisBaseline:
- case ALAxisFirstBaseline:
- NSAssert(nil, @"The baseline axis attributes do not have corresponding margin axis attributes.");
- marginAxis = ALMarginAxisVertical;
- break;
- default:
- NSAssert(nil, @"Not a valid ALAxis.");
- marginAxis = ALMarginAxisVertical;
- break;
- }
- return marginAxis;
- }
- #endif
- @end
|