From a868d0a6bbb812f1e7625185d72ab4fa28db64ce Mon Sep 17 00:00:00 2001 From: Nikolay Tymchenko Date: Sun, 27 Apr 2014 16:15:48 +0400 Subject: [PATCH 1/2] Added mas_remakeConstraints --- Masonry/MASConstraintMaker.h | 5 ++++ Masonry/MASConstraintMaker.m | 6 +++++ Masonry/MASViewConstraint.h | 10 ++++++++ Masonry/MASViewConstraint.m | 34 ++++++++++++++++++++++++- Masonry/NSArray+MASAdditions.h | 11 ++++++++ Masonry/NSArray+MASAdditions.m | 9 +++++++ Masonry/NSArray+MASShorthandAdditions.h | 5 ++++ Masonry/View+MASAdditions.h | 11 ++++++++ Masonry/View+MASAdditions.m | 8 ++++++ Masonry/View+MASShorthandAdditions.h | 5 ++++ 10 files changed, 103 insertions(+), 1 deletion(-) diff --git a/Masonry/MASConstraintMaker.h b/Masonry/MASConstraintMaker.h index f68eff9d..d8e7fc25 100644 --- a/Masonry/MASConstraintMaker.h +++ b/Masonry/MASConstraintMaker.h @@ -79,6 +79,11 @@ typedef NS_OPTIONS(NSInteger, MASAttribute) { */ @property (nonatomic, assign) BOOL updateExisting; +/** + * Whether or not to remove existing constraints prior to installing + */ +@property (nonatomic, assign) BOOL removeExisting; + /** * initialises the maker with a default view * diff --git a/Masonry/MASConstraintMaker.m b/Masonry/MASConstraintMaker.m index f24690cd..abcf8a7a 100644 --- a/Masonry/MASConstraintMaker.m +++ b/Masonry/MASConstraintMaker.m @@ -32,6 +32,12 @@ - (id)initWithView:(MAS_VIEW *)view { } - (NSArray *)install { + if (self.removeExisting) { + NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view]; + for (MASConstraint *constraint in installedConstraints) { + [constraint uninstall]; + } + } NSArray *constraints = self.constraints.copy; for (MASConstraint *constraint in constraints) { constraint.updateExisting = self.updateExisting; diff --git a/Masonry/MASViewConstraint.h b/Masonry/MASViewConstraint.h index b920b276..5c78f7ad 100644 --- a/Masonry/MASViewConstraint.h +++ b/Masonry/MASViewConstraint.h @@ -9,6 +9,7 @@ #import "MASViewAttribute.h" #import "MASConstraint.h" #import "MASLayoutConstraint.h" +#import "MASUtilities.h" /** * A single constraint. @@ -35,4 +36,13 @@ */ - (id)initWithFirstViewAttribute:(MASViewAttribute *)firstViewAttribute; +/** + * Returns all MASViewConstraints installed with this view as a first item. + * + * @param view A view to retrieve constraints for. + * + * @return An array of MASViewConstraints. + */ ++ (NSArray *)installedConstraintsForView:(MAS_VIEW *)view; + @end diff --git a/Masonry/MASViewConstraint.m b/Masonry/MASViewConstraint.m index ef6ede3d..d9f3060f 100644 --- a/Masonry/MASViewConstraint.m +++ b/Masonry/MASViewConstraint.m @@ -10,6 +10,29 @@ #import "MASCompositeConstraint.h" #import "MASLayoutConstraint.h" #import "View+MASAdditions.h" +#import + +@interface MAS_VIEW (MASConstraints) + +@property (nonatomic, readonly) NSMutableSet *mas_installedConstraints; + +@end + +@implementation MAS_VIEW (MASConstraints) + +static char kInstalledConstraintsKey; + +- (NSMutableSet *)mas_installedConstraints { + NSMutableSet *constraints = objc_getAssociatedObject(self, &kInstalledConstraintsKey); + if (!constraints) { + constraints = [NSMutableSet set]; + objc_setAssociatedObject(self, &kInstalledConstraintsKey, constraints, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + return constraints; +} + +@end + @interface MASViewConstraint () @@ -51,7 +74,13 @@ - (id)copyWithZone:(NSZone *)zone { return constraint; } -#pragma mark - private +#pragma mark - Public + ++ (NSArray *)installedConstraintsForView:(MAS_VIEW *)view { + return [view.mas_installedConstraints allObjects]; +} + +#pragma mark - Private - (void)setLayoutConstant:(CGFloat)layoutConstant { _layoutConstant = layoutConstant; @@ -344,6 +373,8 @@ - (void)install { [self.installedView addConstraint:layoutConstraint]; self.layoutConstraint = layoutConstraint; } + + [firstLayoutItem.mas_installedConstraints addObject:self]; } - (MASLayoutConstraint *)layoutConstraintSimiliarTo:(MASLayoutConstraint *)layoutConstraint { @@ -369,6 +400,7 @@ - (void)uninstall { [self.installedView removeConstraint:self.layoutConstraint]; self.layoutConstraint = nil; self.installedView = nil; + [self.firstViewAttribute.view.mas_installedConstraints removeObject:self]; } @end diff --git a/Masonry/NSArray+MASAdditions.h b/Masonry/NSArray+MASAdditions.h index be93ab29..189d51f1 100644 --- a/Masonry/NSArray+MASAdditions.h +++ b/Masonry/NSArray+MASAdditions.h @@ -33,4 +33,15 @@ */ - (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block; +/** + * Creates a MASConstraintMaker with each view in the callee. + * Any constraints defined are added to each view or the appropriate superview once the block has finished executing on each view. + * All constraints previously installed for the views will be removed. + * + * @param block scope within which you can build up the constraints which you wish to apply to each view. + * + * @return Array of created/updated MASConstraints + */ +- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block; + @end diff --git a/Masonry/NSArray+MASAdditions.m b/Masonry/NSArray+MASAdditions.m index e7fabe1a..dbbe6713 100644 --- a/Masonry/NSArray+MASAdditions.m +++ b/Masonry/NSArray+MASAdditions.m @@ -29,4 +29,13 @@ - (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block { return constraints; } +- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block { + NSMutableArray *constraints = [NSMutableArray array]; + for (MAS_VIEW *view in self) { + NSAssert([view isKindOfClass:[MAS_VIEW class]], @"All objects in the array must be views"); + [constraints addObjectsFromArray:[view mas_remakeConstraints:block]]; + } + return constraints; +} + @end diff --git a/Masonry/NSArray+MASShorthandAdditions.h b/Masonry/NSArray+MASShorthandAdditions.h index 03c1b724..8b473697 100644 --- a/Masonry/NSArray+MASShorthandAdditions.h +++ b/Masonry/NSArray+MASShorthandAdditions.h @@ -18,6 +18,7 @@ - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *make))block; - (NSArray *)updateConstraints:(void(^)(MASConstraintMaker *make))block; +- (NSArray *)remakeConstraints:(void(^)(MASConstraintMaker *make))block; @end @@ -31,6 +32,10 @@ return [self mas_updateConstraints:block]; } +- (NSArray *)remakeConstraints:(void(^)(MASConstraintMaker *))block { + return [self mas_remakeConstraints:block]; +} + @end #endif diff --git a/Masonry/View+MASAdditions.h b/Masonry/View+MASAdditions.h index 0b055d70..7c29a0f3 100644 --- a/Masonry/View+MASAdditions.h +++ b/Masonry/View+MASAdditions.h @@ -67,4 +67,15 @@ */ - (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block; +/** + * Creates a MASConstraintMaker with the callee view. + * Any constraints defined are added to the view or the appropriate superview once the block has finished executing. + * All constraints previously installed for the view will be removed. + * + * @param block scope within which you can build up the constraints which you wish to apply to the view. + * + * @return Array of created/updated MASConstraints + */ +- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block; + @end diff --git a/Masonry/View+MASAdditions.m b/Masonry/View+MASAdditions.m index ad538613..d91d9fd8 100644 --- a/Masonry/View+MASAdditions.m +++ b/Masonry/View+MASAdditions.m @@ -26,6 +26,14 @@ - (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *))block { return [constraintMaker install]; } +- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block { + self.translatesAutoresizingMaskIntoConstraints = NO; + MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self]; + constraintMaker.removeExisting = YES; + block(constraintMaker); + return [constraintMaker install]; +} + #pragma mark - NSLayoutAttribute properties - (MASViewAttribute *)mas_left { diff --git a/Masonry/View+MASShorthandAdditions.h b/Masonry/View+MASShorthandAdditions.h index 5e4e51ac..e5e5a212 100644 --- a/Masonry/View+MASShorthandAdditions.h +++ b/Masonry/View+MASShorthandAdditions.h @@ -31,6 +31,7 @@ - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *make))block; - (NSArray *)updateConstraints:(void(^)(MASConstraintMaker *make))block; +- (NSArray *)remakeConstraints:(void(^)(MASConstraintMaker *make))block; @end @@ -62,6 +63,10 @@ MAS_ATTR_FORWARD(attribute); return [self mas_updateConstraints:block]; } +- (NSArray *)remakeConstraints:(void(^)(MASConstraintMaker *))block { + return [self mas_remakeConstraints:block]; +} + @end #endif From 0133f34d1896b0db35eb2cee1d51f5873bb2715e Mon Sep 17 00:00:00 2001 From: Nikolay Tymchenko Date: Tue, 29 Apr 2014 02:43:15 +0400 Subject: [PATCH 2/2] Added tests for maker.removeExisting --- Tests/Specs/MASConstraintMakerSpec.m | 22 ++++++++++++++++++++++ Tests/Specs/NSArray+MASAdditionsSpec.m | 7 +++++++ Tests/Specs/View+MASAdditionsSpec.m | 9 +++++++++ 3 files changed, 38 insertions(+) diff --git a/Tests/Specs/MASConstraintMakerSpec.m b/Tests/Specs/MASConstraintMakerSpec.m index 274a87b5..99f01b62 100644 --- a/Tests/Specs/MASConstraintMakerSpec.m +++ b/Tests/Specs/MASConstraintMakerSpec.m @@ -172,6 +172,28 @@ - (void)testDoNotUpdateConstraints { expect(constraint2.constant).to.equal(20); } +- (void)testRemoveConstraints { + MAS_VIEW *newView = MAS_VIEW.new; + [superview addSubview:newView]; + + maker.left.equalTo(newView).offset(10); + maker.right.equalTo(newView).offset(20); + maker.width.equalTo(newView).offset(30); + [maker install]; + + expect(superview.constraints).to.haveCountOf(3); + expect([MASViewConstraint installedConstraintsForView:view]).to.haveCountOf(3); + + maker.removeExisting = YES; + maker.height.equalTo(newView).offset(100); + [maker install]; + + expect(superview.constraints).to.haveCountOf(1); + expect([MASViewConstraint installedConstraintsForView:view]).to.haveCountOf(1); + NSLayoutConstraint *constraint1 = superview.constraints[0]; + expect(constraint1.constant).to.equal(100); +} + - (void)testCreateNewViewAttributes { expect(maker.left).notTo.beIdenticalTo(maker.left); expect(maker.right).notTo.beIdenticalTo(maker.right); diff --git a/Tests/Specs/NSArray+MASAdditionsSpec.m b/Tests/Specs/NSArray+MASAdditionsSpec.m index 90a10f0a..efec2f2d 100644 --- a/Tests/Specs/NSArray+MASAdditionsSpec.m +++ b/Tests/Specs/NSArray+MASAdditionsSpec.m @@ -52,4 +52,11 @@ - (void)testShouldSetUpdateExistingForArray { }]; } +- (void)testShouldSetRemoveExistingForArray { + NSArray *views = @[ MAS_VIEW.new ]; + [views mas_remakeConstraints:^(MASConstraintMaker *make) { + expect(make.removeExisting).to.beTruthy(); + }]; +} + SpecEnd diff --git a/Tests/Specs/View+MASAdditionsSpec.m b/Tests/Specs/View+MASAdditionsSpec.m index 5210cac8..0b30b261 100644 --- a/Tests/Specs/View+MASAdditionsSpec.m +++ b/Tests/Specs/View+MASAdditionsSpec.m @@ -28,4 +28,13 @@ - (void)testSetUpdateExisting { expect(newView.translatesAutoresizingMaskIntoConstraints).to.beFalsy(); } +- (void)testSetRemoveExisting { + MAS_VIEW *newView = MAS_VIEW.new; + [newView mas_remakeConstraints:^(MASConstraintMaker *make) { + expect(make.removeExisting).to.beTruthy(); + }]; + + expect(newView.translatesAutoresizingMaskIntoConstraints).to.beFalsy(); +} + SpecEnd \ No newline at end of file