浏览代码

Merge pull request #107 from kovpas/master

Implemented support for new NSLayoutConstraint's active property
Jonas Budelmann 10 年之前
父节点
当前提交
2c55faf089

+ 9 - 0
CHANGELOG.md

@@ -1,3 +1,12 @@
+v0.6.0
+======
+
+#### - Improved support of iOS 8
+
+As of iOS 8 there is `active` property of `NSLayoutConstraint` available, which allows to (de)activate constraint without searching closest common superview.
+
+#### - Added support of iPhone 6 and iPhone 6+ to test project
+
 v0.5.3
 ======
 

+ 6 - 0
Examples/Masonry iOS Examples.xcodeproj/project.pbxproj

@@ -8,6 +8,7 @@
 
 /* Begin PBXBuildFile section */
 		114413091924B6EE008E702E /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 114413081924B6EE008E702E /* Default-568h@2x.png */; };
+		3C02224919D0C4EC00507321 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3C02224819D0C4EC00507321 /* Images.xcassets */; };
 		3DB1CAD5184538E200E91FC5 /* MASExampleArrayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB1CAD4184538E200E91FC5 /* MASExampleArrayView.m */; };
 		4BEB55B61957394E008C862B /* MASExampleRemakeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BEB55B51957394E008C862B /* MASExampleRemakeView.m */; };
 		6C87DADA5AB046D9A3181A65 /* libPods-Masonry iOS Examples.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BDC1B8303EED42A2B01B94B1 /* libPods-Masonry iOS Examples.a */; };
@@ -33,6 +34,7 @@
 
 /* Begin PBXFileReference section */
 		114413081924B6EE008E702E /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
+		3C02224819D0C4EC00507321 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
 		3DB1CAD3184538E200E91FC5 /* MASExampleArrayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleArrayView.h; sourceTree = "<group>"; };
 		3DB1CAD4184538E200E91FC5 /* MASExampleArrayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleArrayView.m; sourceTree = "<group>"; };
 		4BEB55B41957394E008C862B /* MASExampleRemakeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleRemakeView.h; sourceTree = "<group>"; };
@@ -127,6 +129,7 @@
 				DD52F23A179CAD57005CD195 /* MASAppDelegate.m */,
 				DD52F257179CADCB005CD195 /* Controllers */,
 				DD52F256179CADC4005CD195 /* Views */,
+				3C02224819D0C4EC00507321 /* Images.xcassets */,
 				DD52F231179CAD57005CD195 /* Supporting Files */,
 			);
 			path = "Masonry iOS Examples";
@@ -239,6 +242,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				3C02224919D0C4EC00507321 /* Images.xcassets in Resources */,
 				DD52F235179CAD57005CD195 /* InfoPlist.strings in Resources */,
 				114413091924B6EE008E702E /* Default-568h@2x.png in Resources */,
 			);
@@ -379,6 +383,7 @@
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = B086DD7D31DD4B49ADC08504 /* Pods-Masonry iOS Examples.xcconfig */;
 			buildSettings = {
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = "Masonry iOS Examples/Masonry iOS Examples-Prefix.pch";
 				INFOPLIST_FILE = "Masonry iOS Examples/Masonry iOS Examples-Info.plist";
@@ -391,6 +396,7 @@
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = B086DD7D31DD4B49ADC08504 /* Pods-Masonry iOS Examples.xcconfig */;
 			buildSettings = {
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = "Masonry iOS Examples/Masonry iOS Examples-Prefix.pch";
 				INFOPLIST_FILE = "Masonry iOS Examples/Masonry iOS Examples-Info.plist";

+ 65 - 0
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Contents.json

@@ -0,0 +1,65 @@
+{
+  "images" : [
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "736h",
+      "filename" : "Default-736h@3x.png",
+      "minimum-system-version" : "8.0",
+      "orientation" : "portrait",
+      "scale" : "3x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "667h",
+      "filename" : "Default-667h@2x.png",
+      "minimum-system-version" : "8.0",
+      "orientation" : "portrait",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "filename" : "Default@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "retina4",
+      "filename" : "Default-568h@2x.png",
+      "minimum-system-version" : "7.0",
+      "orientation" : "portrait",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "filename" : "Default_iOS6.png",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "filename" : "Default_iOS6@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "filename" : "Default_iOS6-568h@2x.png",
+      "subtype" : "retina4",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

二进制
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png


二进制
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Default-667h@2x.png


二进制
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Default-736h@3x.png


二进制
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Default@2x.png


二进制
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Default_iOS6-568h@2x.png


二进制
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Default_iOS6.png


二进制
Examples/Masonry iOS Examples/Images.xcassets/LaunchImage.launchimage/Default_iOS6@2x.png


+ 2 - 2
Masonry.podspec

@@ -1,13 +1,13 @@
 Pod::Spec.new do |s|
   s.name     = 'Masonry'
-  s.version  = '0.5.3'
+  s.version  = '0.6.0'
   s.license  = 'MIT'
   s.summary  = 'Harness the power of Auto Layout NSLayoutConstraints with a simplified, chainable and expressive syntax.'
   s.homepage = 'https://github.com/cloudkite/Masonry'
   s.author   = { 'Jonas Budelmann' => 'jonas.budelmann@gmail.com' }
   s.social_media_url = "http://twitter.com/cloudkite"
 
-  s.source   = { :git => 'https://github.com/cloudkite/Masonry.git', :tag => 'v0.5.3' }
+  s.source   = { :git => 'https://github.com/cloudkite/Masonry.git', :tag => 'v0.6.0' }
 
   s.description = %{
     Masonry is a light-weight layout framework which wraps AutoLayout with a nicer syntax.

+ 12 - 0
Masonry/MASCompositeConstraint.m

@@ -149,6 +149,18 @@
 
 #pragma mark - MASConstraint
 
+- (void)activate {
+    for (MASConstraint *constraint in self.childConstraints) {
+        [constraint activate];
+    }
+}
+
+- (void)deactivate {
+    for (MASConstraint *constraint in self.childConstraints) {
+        [constraint deactivate];
+    }
+}
+
 - (void)install {
     for (MASConstraint *constraint in self.childConstraints) {
         constraint.updateExisting = self.updateExisting;

+ 13 - 2
Masonry/MASConstraint.h

@@ -108,12 +108,12 @@
 - (MASConstraint *)with;
 
 /**
- *	optional semantic property which has no effect but improves the readability of constraint
+ *	Optional semantic property which has no effect but improves the readability of constraint
  */
 - (MASConstraint *)and;
 
 /**
- *	creates a new MASCompositeConstraint with the called attribute and reciever
+ *	Creates a new MASCompositeConstraint with the called attribute and reciever
  */
 - (MASConstraint *)left;
 - (MASConstraint *)top;
@@ -171,6 +171,17 @@
 @property (nonatomic, copy, readonly) MASConstraint *animator;
 #endif
 
+/**
+ *  Activates an NSLayoutConstraint if it's supported by an OS. 
+ *  Invokes install otherwise.
+ */
+- (void)activate;
+
+/**
+ *  Deactivates previously installed/activated NSLayoutConstraint.
+ */
+- (void)deactivate;
+
 /**
  *	Creates a NSLayoutConstraint and adds it to the appropriate view.
  */

+ 4 - 0
Masonry/MASConstraint.m

@@ -234,6 +234,10 @@
 
 #endif
 
+- (void)activate { MASMethodNotImplemented(); }
+
+- (void)deactivate { MASMethodNotImplemented(); }
+
 - (void)install { MASMethodNotImplemented(); }
 
 - (void)uninstall { MASMethodNotImplemented(); }

+ 40 - 2
Masonry/MASViewConstraint.m

@@ -102,8 +102,21 @@ static char kInstalledConstraintsKey;
     self.hasLayoutRelation = YES;
 }
 
+- (BOOL)supportsActiveProperty {
+    return [self.layoutConstraint respondsToSelector:@selector(isActive)];
+}
+
+- (BOOL)isActive {
+    BOOL active = YES;
+    if ([self supportsActiveProperty]) {
+        active = [self.layoutConstraint isActive];
+    }
+
+    return active;
+}
+
 - (BOOL)hasBeenInstalled {
-    return self.layoutConstraint != nil;
+    return (self.layoutConstraint != nil) && [self isActive];
 }
 
 - (void)setSecondViewAttribute:(id)secondViewAttribute {
@@ -272,10 +285,34 @@ static char kInstalledConstraintsKey;
 
 #pragma mark - MASConstraint
 
+- (void)activate {
+    if ([self supportsActiveProperty] && self.layoutConstraint) {
+        if (self.hasBeenInstalled) {
+            return;
+        }
+        self.layoutConstraint.active = YES;
+        [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
+    } else {
+        [self install];
+    }
+}
+
+- (void)deactivate {
+    if ([self.layoutConstraint respondsToSelector:@selector(setActive:)]) {
+        self.layoutConstraint.active = NO;
+        [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
+    } else {
+        [self uninstall];
+    }
+}
+
 - (void)install {
-    NSAssert(!self.hasBeenInstalled, @"Cannot install constraint more than once");
+    if (self.hasBeenInstalled) {
+        return;
+    }
     
     MAS_VIEW *firstLayoutItem = self.firstViewAttribute.view;
+    
     NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
     MAS_VIEW *secondLayoutItem = self.secondViewAttribute.view;
     NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;
@@ -351,6 +388,7 @@ static char kInstalledConstraintsKey;
     [self.installedView removeConstraint:self.layoutConstraint];
     self.layoutConstraint = nil;
     self.installedView = nil;
+    
     [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
 }
 

+ 4 - 4
Masonry/NSLayoutConstraint+MASDebugAdditions.m

@@ -110,10 +110,10 @@
         [description appendFormat:@" * %g", self.multiplier];
     }
     
-    if (self.constant) {
-        if (self.secondAttribute == NSLayoutAttributeNotAnAttribute) {
-            [description appendFormat:@" %g", self.constant];
-        } else {
+    if (self.secondAttribute == NSLayoutAttributeNotAnAttribute) {
+        [description appendFormat:@" %g", self.constant];
+    } else {
+        if (self.constant) {
             [description appendFormat:@" %@ %g", (self.constant < 0 ? @"-" : @"+"), ABS(self.constant)];
         }
     }

+ 20 - 0
Tests/Specs/MASCompositeConstraintSpec.m

@@ -152,6 +152,26 @@ SpecBegin(MASCompositeConstraint) {
     expect(superview.constraints).to.haveCountOf(0);
 }
 
+- (void)testActivateDeactivate {
+    NSArray *children = @[
+                          [[MASViewConstraint alloc] initWithFirstViewAttribute:view.mas_leading],
+                          [[MASViewConstraint alloc] initWithFirstViewAttribute:view.mas_trailing]
+                          ];
+    composite = [[MASCompositeConstraint alloc] initWithChildren:children];
+    composite.delegate = delegate;
+    MAS_VIEW *newView = MAS_VIEW.new;
+    [superview addSubview:newView];
+    
+    //first equality statement
+    composite.equalTo(newView);
+    [composite install];
+    
+    expect(superview.constraints).to.haveCountOf(2);
+    [composite deactivate];
+    expect(superview.constraints).to.haveCountOf(0);
+    [composite activate];
+    expect(superview.constraints).to.haveCountOf(2);
+}
 
 - (void)testAttributeChainingShouldCallDelegate {
     NSArray *children = @[

+ 1 - 1
Tests/Specs/MASViewConstraintSpec.m

@@ -514,7 +514,7 @@ SpecBegin(MASViewConstraint) {
     constraint.lessThanOrEqualTo(secondViewAttribute);
     
     expect(^{
-        id result = constraint.bottom;
+        __unused id result = constraint.bottom;
     }).to.raise(@"NSInternalInconsistencyException");
 }