Authored by Jonas Budelmann

Merge pull request #107 from kovpas/master

Implemented support for new NSLayoutConstraint's active property
  1 +v0.6.0
  2 +======
  3 +
  4 +#### - Improved support of iOS 8
  5 +
  6 +As of iOS 8 there is `active` property of `NSLayoutConstraint` available, which allows to (de)activate constraint without searching closest common superview.
  7 +
  8 +#### - Added support of iPhone 6 and iPhone 6+ to test project
  9 +
1 v0.5.3 10 v0.5.3
2 ====== 11 ======
3 12
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 8
9 /* Begin PBXBuildFile section */ 9 /* Begin PBXBuildFile section */
10 114413091924B6EE008E702E /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 114413081924B6EE008E702E /* Default-568h@2x.png */; }; 10 114413091924B6EE008E702E /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 114413081924B6EE008E702E /* Default-568h@2x.png */; };
  11 + 3C02224919D0C4EC00507321 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3C02224819D0C4EC00507321 /* Images.xcassets */; };
11 3DB1CAD5184538E200E91FC5 /* MASExampleArrayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB1CAD4184538E200E91FC5 /* MASExampleArrayView.m */; }; 12 3DB1CAD5184538E200E91FC5 /* MASExampleArrayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB1CAD4184538E200E91FC5 /* MASExampleArrayView.m */; };
12 4BEB55B61957394E008C862B /* MASExampleRemakeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BEB55B51957394E008C862B /* MASExampleRemakeView.m */; }; 13 4BEB55B61957394E008C862B /* MASExampleRemakeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BEB55B51957394E008C862B /* MASExampleRemakeView.m */; };
13 6C87DADA5AB046D9A3181A65 /* libPods-Masonry iOS Examples.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BDC1B8303EED42A2B01B94B1 /* libPods-Masonry iOS Examples.a */; }; 14 6C87DADA5AB046D9A3181A65 /* libPods-Masonry iOS Examples.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BDC1B8303EED42A2B01B94B1 /* libPods-Masonry iOS Examples.a */; };
@@ -33,6 +34,7 @@ @@ -33,6 +34,7 @@
33 34
34 /* Begin PBXFileReference section */ 35 /* Begin PBXFileReference section */
35 114413081924B6EE008E702E /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; }; 36 114413081924B6EE008E702E /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
  37 + 3C02224819D0C4EC00507321 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
36 3DB1CAD3184538E200E91FC5 /* MASExampleArrayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleArrayView.h; sourceTree = "<group>"; }; 38 3DB1CAD3184538E200E91FC5 /* MASExampleArrayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleArrayView.h; sourceTree = "<group>"; };
37 3DB1CAD4184538E200E91FC5 /* MASExampleArrayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleArrayView.m; sourceTree = "<group>"; }; 39 3DB1CAD4184538E200E91FC5 /* MASExampleArrayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleArrayView.m; sourceTree = "<group>"; };
38 4BEB55B41957394E008C862B /* MASExampleRemakeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleRemakeView.h; sourceTree = "<group>"; }; 40 4BEB55B41957394E008C862B /* MASExampleRemakeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleRemakeView.h; sourceTree = "<group>"; };
@@ -127,6 +129,7 @@ @@ -127,6 +129,7 @@
127 DD52F23A179CAD57005CD195 /* MASAppDelegate.m */, 129 DD52F23A179CAD57005CD195 /* MASAppDelegate.m */,
128 DD52F257179CADCB005CD195 /* Controllers */, 130 DD52F257179CADCB005CD195 /* Controllers */,
129 DD52F256179CADC4005CD195 /* Views */, 131 DD52F256179CADC4005CD195 /* Views */,
  132 + 3C02224819D0C4EC00507321 /* Images.xcassets */,
130 DD52F231179CAD57005CD195 /* Supporting Files */, 133 DD52F231179CAD57005CD195 /* Supporting Files */,
131 ); 134 );
132 path = "Masonry iOS Examples"; 135 path = "Masonry iOS Examples";
@@ -239,6 +242,7 @@ @@ -239,6 +242,7 @@
239 isa = PBXResourcesBuildPhase; 242 isa = PBXResourcesBuildPhase;
240 buildActionMask = 2147483647; 243 buildActionMask = 2147483647;
241 files = ( 244 files = (
  245 + 3C02224919D0C4EC00507321 /* Images.xcassets in Resources */,
242 DD52F235179CAD57005CD195 /* InfoPlist.strings in Resources */, 246 DD52F235179CAD57005CD195 /* InfoPlist.strings in Resources */,
243 114413091924B6EE008E702E /* Default-568h@2x.png in Resources */, 247 114413091924B6EE008E702E /* Default-568h@2x.png in Resources */,
244 ); 248 );
@@ -379,6 +383,7 @@ @@ -379,6 +383,7 @@
379 isa = XCBuildConfiguration; 383 isa = XCBuildConfiguration;
380 baseConfigurationReference = B086DD7D31DD4B49ADC08504 /* Pods-Masonry iOS Examples.xcconfig */; 384 baseConfigurationReference = B086DD7D31DD4B49ADC08504 /* Pods-Masonry iOS Examples.xcconfig */;
381 buildSettings = { 385 buildSettings = {
  386 + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
382 GCC_PRECOMPILE_PREFIX_HEADER = YES; 387 GCC_PRECOMPILE_PREFIX_HEADER = YES;
383 GCC_PREFIX_HEADER = "Masonry iOS Examples/Masonry iOS Examples-Prefix.pch"; 388 GCC_PREFIX_HEADER = "Masonry iOS Examples/Masonry iOS Examples-Prefix.pch";
384 INFOPLIST_FILE = "Masonry iOS Examples/Masonry iOS Examples-Info.plist"; 389 INFOPLIST_FILE = "Masonry iOS Examples/Masonry iOS Examples-Info.plist";
@@ -391,6 +396,7 @@ @@ -391,6 +396,7 @@
391 isa = XCBuildConfiguration; 396 isa = XCBuildConfiguration;
392 baseConfigurationReference = B086DD7D31DD4B49ADC08504 /* Pods-Masonry iOS Examples.xcconfig */; 397 baseConfigurationReference = B086DD7D31DD4B49ADC08504 /* Pods-Masonry iOS Examples.xcconfig */;
393 buildSettings = { 398 buildSettings = {
  399 + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
394 GCC_PRECOMPILE_PREFIX_HEADER = YES; 400 GCC_PRECOMPILE_PREFIX_HEADER = YES;
395 GCC_PREFIX_HEADER = "Masonry iOS Examples/Masonry iOS Examples-Prefix.pch"; 401 GCC_PREFIX_HEADER = "Masonry iOS Examples/Masonry iOS Examples-Prefix.pch";
396 INFOPLIST_FILE = "Masonry iOS Examples/Masonry iOS Examples-Info.plist"; 402 INFOPLIST_FILE = "Masonry iOS Examples/Masonry iOS Examples-Info.plist";
  1 +{
  2 + "images" : [
  3 + {
  4 + "extent" : "full-screen",
  5 + "idiom" : "iphone",
  6 + "subtype" : "736h",
  7 + "filename" : "Default-736h@3x.png",
  8 + "minimum-system-version" : "8.0",
  9 + "orientation" : "portrait",
  10 + "scale" : "3x"
  11 + },
  12 + {
  13 + "extent" : "full-screen",
  14 + "idiom" : "iphone",
  15 + "subtype" : "667h",
  16 + "filename" : "Default-667h@2x.png",
  17 + "minimum-system-version" : "8.0",
  18 + "orientation" : "portrait",
  19 + "scale" : "2x"
  20 + },
  21 + {
  22 + "orientation" : "portrait",
  23 + "idiom" : "iphone",
  24 + "extent" : "full-screen",
  25 + "minimum-system-version" : "7.0",
  26 + "filename" : "Default@2x.png",
  27 + "scale" : "2x"
  28 + },
  29 + {
  30 + "extent" : "full-screen",
  31 + "idiom" : "iphone",
  32 + "subtype" : "retina4",
  33 + "filename" : "Default-568h@2x.png",
  34 + "minimum-system-version" : "7.0",
  35 + "orientation" : "portrait",
  36 + "scale" : "2x"
  37 + },
  38 + {
  39 + "orientation" : "portrait",
  40 + "idiom" : "iphone",
  41 + "extent" : "full-screen",
  42 + "filename" : "Default_iOS6.png",
  43 + "scale" : "1x"
  44 + },
  45 + {
  46 + "orientation" : "portrait",
  47 + "idiom" : "iphone",
  48 + "extent" : "full-screen",
  49 + "filename" : "Default_iOS6@2x.png",
  50 + "scale" : "2x"
  51 + },
  52 + {
  53 + "orientation" : "portrait",
  54 + "idiom" : "iphone",
  55 + "extent" : "full-screen",
  56 + "filename" : "Default_iOS6-568h@2x.png",
  57 + "subtype" : "retina4",
  58 + "scale" : "2x"
  59 + }
  60 + ],
  61 + "info" : {
  62 + "version" : 1,
  63 + "author" : "xcode"
  64 + }
  65 +}
1 Pod::Spec.new do |s| 1 Pod::Spec.new do |s|
2 s.name = 'Masonry' 2 s.name = 'Masonry'
3 - s.version = '0.5.3' 3 + s.version = '0.6.0'
4 s.license = 'MIT' 4 s.license = 'MIT'
5 s.summary = 'Harness the power of Auto Layout NSLayoutConstraints with a simplified, chainable and expressive syntax.' 5 s.summary = 'Harness the power of Auto Layout NSLayoutConstraints with a simplified, chainable and expressive syntax.'
6 s.homepage = 'https://github.com/cloudkite/Masonry' 6 s.homepage = 'https://github.com/cloudkite/Masonry'
7 s.author = { 'Jonas Budelmann' => 'jonas.budelmann@gmail.com' } 7 s.author = { 'Jonas Budelmann' => 'jonas.budelmann@gmail.com' }
8 s.social_media_url = "http://twitter.com/cloudkite" 8 s.social_media_url = "http://twitter.com/cloudkite"
9 9
10 - s.source = { :git => 'https://github.com/cloudkite/Masonry.git', :tag => 'v0.5.3' } 10 + s.source = { :git => 'https://github.com/cloudkite/Masonry.git', :tag => 'v0.6.0' }
11 11
12 s.description = %{ 12 s.description = %{
13 Masonry is a light-weight layout framework which wraps AutoLayout with a nicer syntax. 13 Masonry is a light-weight layout framework which wraps AutoLayout with a nicer syntax.
@@ -149,6 +149,18 @@ @@ -149,6 +149,18 @@
149 149
150 #pragma mark - MASConstraint 150 #pragma mark - MASConstraint
151 151
  152 +- (void)activate {
  153 + for (MASConstraint *constraint in self.childConstraints) {
  154 + [constraint activate];
  155 + }
  156 +}
  157 +
  158 +- (void)deactivate {
  159 + for (MASConstraint *constraint in self.childConstraints) {
  160 + [constraint deactivate];
  161 + }
  162 +}
  163 +
152 - (void)install { 164 - (void)install {
153 for (MASConstraint *constraint in self.childConstraints) { 165 for (MASConstraint *constraint in self.childConstraints) {
154 constraint.updateExisting = self.updateExisting; 166 constraint.updateExisting = self.updateExisting;
@@ -108,12 +108,12 @@ @@ -108,12 +108,12 @@
108 - (MASConstraint *)with; 108 - (MASConstraint *)with;
109 109
110 /** 110 /**
111 - * optional semantic property which has no effect but improves the readability of constraint 111 + * Optional semantic property which has no effect but improves the readability of constraint
112 */ 112 */
113 - (MASConstraint *)and; 113 - (MASConstraint *)and;
114 114
115 /** 115 /**
116 - * creates a new MASCompositeConstraint with the called attribute and reciever 116 + * Creates a new MASCompositeConstraint with the called attribute and reciever
117 */ 117 */
118 - (MASConstraint *)left; 118 - (MASConstraint *)left;
119 - (MASConstraint *)top; 119 - (MASConstraint *)top;
@@ -172,6 +172,17 @@ @@ -172,6 +172,17 @@
172 #endif 172 #endif
173 173
174 /** 174 /**
  175 + * Activates an NSLayoutConstraint if it's supported by an OS.
  176 + * Invokes install otherwise.
  177 + */
  178 +- (void)activate;
  179 +
  180 +/**
  181 + * Deactivates previously installed/activated NSLayoutConstraint.
  182 + */
  183 +- (void)deactivate;
  184 +
  185 +/**
175 * Creates a NSLayoutConstraint and adds it to the appropriate view. 186 * Creates a NSLayoutConstraint and adds it to the appropriate view.
176 */ 187 */
177 - (void)install; 188 - (void)install;
@@ -234,6 +234,10 @@ @@ -234,6 +234,10 @@
234 234
235 #endif 235 #endif
236 236
  237 +- (void)activate { MASMethodNotImplemented(); }
  238 +
  239 +- (void)deactivate { MASMethodNotImplemented(); }
  240 +
237 - (void)install { MASMethodNotImplemented(); } 241 - (void)install { MASMethodNotImplemented(); }
238 242
239 - (void)uninstall { MASMethodNotImplemented(); } 243 - (void)uninstall { MASMethodNotImplemented(); }
@@ -102,8 +102,21 @@ static char kInstalledConstraintsKey; @@ -102,8 +102,21 @@ static char kInstalledConstraintsKey;
102 self.hasLayoutRelation = YES; 102 self.hasLayoutRelation = YES;
103 } 103 }
104 104
  105 +- (BOOL)supportsActiveProperty {
  106 + return [self.layoutConstraint respondsToSelector:@selector(isActive)];
  107 +}
  108 +
  109 +- (BOOL)isActive {
  110 + BOOL active = YES;
  111 + if ([self supportsActiveProperty]) {
  112 + active = [self.layoutConstraint isActive];
  113 + }
  114 +
  115 + return active;
  116 +}
  117 +
105 - (BOOL)hasBeenInstalled { 118 - (BOOL)hasBeenInstalled {
106 - return self.layoutConstraint != nil; 119 + return (self.layoutConstraint != nil) && [self isActive];
107 } 120 }
108 121
109 - (void)setSecondViewAttribute:(id)secondViewAttribute { 122 - (void)setSecondViewAttribute:(id)secondViewAttribute {
@@ -272,10 +285,34 @@ static char kInstalledConstraintsKey; @@ -272,10 +285,34 @@ static char kInstalledConstraintsKey;
272 285
273 #pragma mark - MASConstraint 286 #pragma mark - MASConstraint
274 287
  288 +- (void)activate {
  289 + if ([self supportsActiveProperty] && self.layoutConstraint) {
  290 + if (self.hasBeenInstalled) {
  291 + return;
  292 + }
  293 + self.layoutConstraint.active = YES;
  294 + [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
  295 + } else {
  296 + [self install];
  297 + }
  298 +}
  299 +
  300 +- (void)deactivate {
  301 + if ([self.layoutConstraint respondsToSelector:@selector(setActive:)]) {
  302 + self.layoutConstraint.active = NO;
  303 + [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
  304 + } else {
  305 + [self uninstall];
  306 + }
  307 +}
  308 +
275 - (void)install { 309 - (void)install {
276 - NSAssert(!self.hasBeenInstalled, @"Cannot install constraint more than once"); 310 + if (self.hasBeenInstalled) {
  311 + return;
  312 + }
277 313
278 MAS_VIEW *firstLayoutItem = self.firstViewAttribute.view; 314 MAS_VIEW *firstLayoutItem = self.firstViewAttribute.view;
  315 +
279 NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute; 316 NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
280 MAS_VIEW *secondLayoutItem = self.secondViewAttribute.view; 317 MAS_VIEW *secondLayoutItem = self.secondViewAttribute.view;
281 NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute; 318 NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;
@@ -351,6 +388,7 @@ static char kInstalledConstraintsKey; @@ -351,6 +388,7 @@ static char kInstalledConstraintsKey;
351 [self.installedView removeConstraint:self.layoutConstraint]; 388 [self.installedView removeConstraint:self.layoutConstraint];
352 self.layoutConstraint = nil; 389 self.layoutConstraint = nil;
353 self.installedView = nil; 390 self.installedView = nil;
  391 +
354 [self.firstViewAttribute.view.mas_installedConstraints removeObject:self]; 392 [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
355 } 393 }
356 394
@@ -110,10 +110,10 @@ @@ -110,10 +110,10 @@
110 [description appendFormat:@" * %g", self.multiplier]; 110 [description appendFormat:@" * %g", self.multiplier];
111 } 111 }
112 112
113 - if (self.constant) {  
114 if (self.secondAttribute == NSLayoutAttributeNotAnAttribute) { 113 if (self.secondAttribute == NSLayoutAttributeNotAnAttribute) {
115 [description appendFormat:@" %g", self.constant]; 114 [description appendFormat:@" %g", self.constant];
116 } else { 115 } else {
  116 + if (self.constant) {
117 [description appendFormat:@" %@ %g", (self.constant < 0 ? @"-" : @"+"), ABS(self.constant)]; 117 [description appendFormat:@" %@ %g", (self.constant < 0 ? @"-" : @"+"), ABS(self.constant)];
118 } 118 }
119 } 119 }
@@ -152,6 +152,26 @@ SpecBegin(MASCompositeConstraint) { @@ -152,6 +152,26 @@ SpecBegin(MASCompositeConstraint) {
152 expect(superview.constraints).to.haveCountOf(0); 152 expect(superview.constraints).to.haveCountOf(0);
153 } 153 }
154 154
  155 +- (void)testActivateDeactivate {
  156 + NSArray *children = @[
  157 + [[MASViewConstraint alloc] initWithFirstViewAttribute:view.mas_leading],
  158 + [[MASViewConstraint alloc] initWithFirstViewAttribute:view.mas_trailing]
  159 + ];
  160 + composite = [[MASCompositeConstraint alloc] initWithChildren:children];
  161 + composite.delegate = delegate;
  162 + MAS_VIEW *newView = MAS_VIEW.new;
  163 + [superview addSubview:newView];
  164 +
  165 + //first equality statement
  166 + composite.equalTo(newView);
  167 + [composite install];
  168 +
  169 + expect(superview.constraints).to.haveCountOf(2);
  170 + [composite deactivate];
  171 + expect(superview.constraints).to.haveCountOf(0);
  172 + [composite activate];
  173 + expect(superview.constraints).to.haveCountOf(2);
  174 +}
155 175
156 - (void)testAttributeChainingShouldCallDelegate { 176 - (void)testAttributeChainingShouldCallDelegate {
157 NSArray *children = @[ 177 NSArray *children = @[
@@ -514,7 +514,7 @@ SpecBegin(MASViewConstraint) { @@ -514,7 +514,7 @@ SpecBegin(MASViewConstraint) {
514 constraint.lessThanOrEqualTo(secondViewAttribute); 514 constraint.lessThanOrEqualTo(secondViewAttribute);
515 515
516 expect(^{ 516 expect(^{
517 - id result = constraint.bottom; 517 + __unused id result = constraint.bottom;
518 }).to.raise(@"NSInternalInconsistencyException"); 518 }).to.raise(@"NSInternalInconsistencyException");
519 } 519 }
520 520