Authored by Jonas Budelmann

Merge branch 'master' of https://github.com/cloudkite/Masonry

Pod::Spec.new do |s|
s.name = 'Masonry'
s.version = '0.1.0'
s.version = '0.1.5'
s.license = 'MIT'
s.summary = 'A light-weight layout framework which makes creating iOS AutoLayout NSLayoutConstraints in code quick, readable and descriptive.'
s.homepage = 'https://github.com/cloudkite/Masonry'
s.author = { 'Jonas Budelmann' => 'jonas.budelmann@gmail.com' }
s.source = { :git => 'https://github.com/cloudkite/Masonry.git', :tag => 'v0.1.0' }
s.source = { :git => 'https://github.com/cloudkite/Masonry.git', :tag => 'v0.1.5' }
s.description = %{
Masonary is a light-weight layout framework which wraps AutoLayout with a nicer syntax.
... ...
... ... @@ -28,6 +28,12 @@
DD52F268179CB346005CD195 /* MASViewAttribute.h in Headers */ = {isa = PBXBuildFile; fileRef = DD52F1E1179CAACA005CD195 /* MASViewAttribute.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD52F269179CB34A005CD195 /* MASViewConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = DD52F1E3179CAACA005CD195 /* MASViewConstraint.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD52F26A179CB365005CD195 /* MASCompositeConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = DD52F1DC179CAACA005CD195 /* MASCompositeConstraint.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD7CC16E17ACCF22007A469E /* NSLayoutConstraint+MASDebugAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DD7CC16C17ACCF21007A469E /* NSLayoutConstraint+MASDebugAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD7CC16F17ACCF22007A469E /* NSLayoutConstraint+MASDebugAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DD7CC16D17ACCF22007A469E /* NSLayoutConstraint+MASDebugAdditions.m */; };
DD7CC17217ACDC7A007A469E /* NSObject+MASKeyAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DD7CC17017ACDC7A007A469E /* NSObject+MASKeyAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD7CC17317ACDC7A007A469E /* NSObject+MASKeyAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DD7CC17117ACDC7A007A469E /* NSObject+MASKeyAdditions.m */; };
DD93AAF317ACB647008F7D21 /* MASLayoutConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = DD93AAF117ACB647008F7D21 /* MASLayoutConstraint.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD93AAF417ACB647008F7D21 /* MASLayoutConstraint.m in Sources */ = {isa = PBXBuildFile; fileRef = DD93AAF217ACB647008F7D21 /* MASLayoutConstraint.m */; };
DDE2653F179D24E600D48565 /* UIView+MASShorthandAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DDE2653D179D24E600D48565 /* UIView+MASShorthandAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
F0D61B353FCC42358F962A3C /* libPods-MasonryTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DE643A835A4447F4807FDBFA /* libPods-MasonryTests.a */; };
/* End PBXBuildFile section */
... ... @@ -81,6 +87,12 @@
DD52F1E5179CAACA005CD195 /* UIView+MASAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+MASAdditions.h"; sourceTree = "<group>"; };
DD52F1E6179CAACA005CD195 /* UIView+MASAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+MASAdditions.m"; sourceTree = "<group>"; };
DD52F1ED179CAAEE005CD195 /* Masonry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Masonry.h; sourceTree = "<group>"; };
DD7CC16C17ACCF21007A469E /* NSLayoutConstraint+MASDebugAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+MASDebugAdditions.h"; sourceTree = "<group>"; };
DD7CC16D17ACCF22007A469E /* NSLayoutConstraint+MASDebugAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+MASDebugAdditions.m"; sourceTree = "<group>"; };
DD7CC17017ACDC7A007A469E /* NSObject+MASKeyAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MASKeyAdditions.h"; sourceTree = "<group>"; };
DD7CC17117ACDC7A007A469E /* NSObject+MASKeyAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MASKeyAdditions.m"; sourceTree = "<group>"; };
DD93AAF117ACB647008F7D21 /* MASLayoutConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASLayoutConstraint.h; sourceTree = "<group>"; };
DD93AAF217ACB647008F7D21 /* MASLayoutConstraint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASLayoutConstraint.m; sourceTree = "<group>"; };
DDE2653D179D24E600D48565 /* UIView+MASShorthandAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+MASShorthandAdditions.h"; sourceTree = "<group>"; };
DE643A835A4447F4807FDBFA /* libPods-MasonryTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MasonryTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
... ... @@ -195,6 +207,10 @@
DD52F1E5179CAACA005CD195 /* UIView+MASAdditions.h */,
DD52F1E6179CAACA005CD195 /* UIView+MASAdditions.m */,
DDE2653D179D24E600D48565 /* UIView+MASShorthandAdditions.h */,
DD7CC17017ACDC7A007A469E /* NSObject+MASKeyAdditions.h */,
DD7CC17117ACDC7A007A469E /* NSObject+MASKeyAdditions.m */,
DD7CC16C17ACCF21007A469E /* NSLayoutConstraint+MASDebugAdditions.h */,
DD7CC16D17ACCF22007A469E /* NSLayoutConstraint+MASDebugAdditions.m */,
);
name = Additions;
sourceTree = "<group>";
... ... @@ -211,6 +227,8 @@
DD52F1E2179CAACA005CD195 /* MASViewAttribute.m */,
DD52F1E3179CAACA005CD195 /* MASViewConstraint.h */,
DD52F1E4179CAACA005CD195 /* MASViewConstraint.m */,
DD93AAF117ACB647008F7D21 /* MASLayoutConstraint.h */,
DD93AAF217ACB647008F7D21 /* MASLayoutConstraint.m */,
);
name = Modules;
sourceTree = "<group>";
... ... @@ -229,7 +247,10 @@
DD52F267179CB342005CD195 /* MASConstraintMaker.h in Headers */,
DD52F268179CB346005CD195 /* MASViewAttribute.h in Headers */,
DD52F269179CB34A005CD195 /* MASViewConstraint.h in Headers */,
DD93AAF317ACB647008F7D21 /* MASLayoutConstraint.h in Headers */,
DD52F26A179CB365005CD195 /* MASCompositeConstraint.h in Headers */,
DD7CC17217ACDC7A007A469E /* NSObject+MASKeyAdditions.h in Headers */,
DD7CC16E17ACCF22007A469E /* NSLayoutConstraint+MASDebugAdditions.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ... @@ -367,6 +388,9 @@
DD52F1E9179CAACA005CD195 /* MASViewAttribute.m in Sources */,
DD52F1EA179CAACA005CD195 /* MASViewConstraint.m in Sources */,
DD52F1EB179CAACA005CD195 /* UIView+MASAdditions.m in Sources */,
DD93AAF417ACB647008F7D21 /* MASLayoutConstraint.m in Sources */,
DD7CC16F17ACCF22007A469E /* NSLayoutConstraint+MASDebugAdditions.m in Sources */,
DD7CC17317ACDC7A007A469E /* NSObject+MASKeyAdditions.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ...
... ... @@ -13,15 +13,49 @@ typedef NS_ENUM(NSInteger, MASCompositeConstraintType) {
MASCompositeConstraintTypeEdges, //top, left, bottom, right
MASCompositeConstraintTypeSize, //width, height
MASCompositeConstraintTypeCenter, //centerX, centerY
MASCompositeConstraintTypeUnknown, //could be mixture of any attributes
};
/**
* A group of MASConstraint objects
* conforms to MASConstraint
*/
@interface MASCompositeConstraint : NSObject <MASConstraint>
/**
* Usually MASConstraintMaker but could be a parent MASConstraint
*/
@property (nonatomic, weak) id<MASConstraintDelegate> delegate;
/**
* default first item for any child MASConstraints
*/
@property (nonatomic, weak, readonly) UIView *view;
/**
* type of Composite, used internally to generate child MASViewConstraits
*/
@property (nonatomic, assign, readonly) MASCompositeConstraintType type;
/**
* Creates a composite and automatically generates child MASViewConstraints
* Appriopriate to the type
*
* @param view first item view
* @param type determines what kind of child constraints to generate
*
* @return a composite constraint
*/
- (id)initWithView:(UIView *)view type:(MASCompositeConstraintType)type;
/**
* Creates a composite with a predefined array of children
*
* @param view first item view
* @param children child MASConstraints
*
* @return a composite constraint
*/
- (id)initWithView:(UIView *)view children:(NSArray *)children;
@end
... ...
... ... @@ -9,6 +9,7 @@
#import "MASCompositeConstraint.h"
#import "UIView+MASAdditions.h"
#import "MASViewConstraint.h"
#import "NSObject+MASKeyAdditions.h"
@interface MASCompositeConstraint () <MASConstraintDelegate>
... ... @@ -34,6 +35,7 @@
self = [super init];
if (!self) return nil;
_type = MASCompositeConstraintTypeUnknown;
_view = view;
_childConstraints = [children mutableCopy];
... ... @@ -61,6 +63,8 @@
self.view.mas_centerX, self.view.mas_centerY
];
break;
default:
break;
}
for (MASViewAttribute *viewAttribute in viewAttributes) {
... ... @@ -192,6 +196,19 @@
return self;
}
#pragma mark - debug helpers
- (id<MASConstraint> (^)(id))key {
return ^id(id key) {
self.mas_key = key;
int i = 0;
for (id<MASConstraint> constraint in self.childConstraints) {
constraint.key([NSString stringWithFormat:@"%@[%d]", key, i++]);
}
return self;
};
}
#pragma mark - MASConstraint
- (void)commit {
... ...
... ... @@ -17,33 +17,101 @@ enum {
};
typedef float MASLayoutPriority;
/**
* Enables Constraints to be created with chainable syntax
* Constraint can represent single NSLayoutConstraint (MASViewConstraint)
* or a group of NSLayoutConstraints (MASComposisteConstraint)
*/
@protocol MASConstraint <NSObject>
//NSLayoutConstraint constant proxies
/**
* Modifies the NSLayoutConstraint constant,
* only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
* NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, NSLayoutAttributeRight
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^insets)(UIEdgeInsets insets);
/**
* Modifies the NSLayoutConstraint constant,
* only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
* NSLayoutAttributeWidth, NSLayoutAttributeHeight
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^sizeOffset)(CGSize offset);
/**
* Modifies the NSLayoutConstraint constant,
* only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
* NSLayoutAttributeCenterX, NSLayoutAttributeCenterY
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^centerOffset)(CGPoint offset);
/**
* Modifies the NSLayoutConstraint constant
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^offset)(CGFloat offset);
//NSLayoutConstraint multiplier proxies
/**
* Sets the NSLayoutConstraint multiplier property
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^percent)(CGFloat percent);
//MASLayoutPriority proxies
/**
* Sets the NSLayoutConstraint priority to a float or MASLayoutPriority
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^priority)(MASLayoutPriority priority);
/**
* Sets the NSLayoutConstraint priority to MASLayoutPriorityLow
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^priorityLow)();
/**
* Sets the NSLayoutConstraint priority to MASLayoutPriorityMedium
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^priorityMedium)();
/**
* Sets the NSLayoutConstraint priority to MASLayoutPriorityHigh
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^priorityHigh)();
//NSLayoutRelation proxies
/**
* Sets the constraint relation to NSLayoutRelationEqual
* returns a block which accepts one of the following:
* MASViewAttribute, UIView, NSNumber, NSArray
* see readme for more details.
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^equalTo)(id attr);
/**
* Sets the constraint relation to NSLayoutRelationGreaterThanOrEqual
* returns a block which accepts one of the following:
* MASViewAttribute, UIView, NSNumber, NSArray
* see readme for more details.
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^greaterThanOrEqualTo)(id attr);
/**
* Sets the constraint relation to NSLayoutRelationLessThanOrEqual
* returns a block which accepts one of the following:
* MASViewAttribute, UIView, NSNumber, NSArray
* see readme for more details.
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^lessThanOrEqualTo)(id attr);
//semantic properties
/**
* optional semantic property which has no effect but improves the readability of constraint
*/
@property (nonatomic, copy, readonly) id<MASConstraint> with;
/**
Creates a NSLayoutConstraint. The constraint is added to the first view or the or the closest common superview of the first and second view.
* Sets the constraint debug name
*/
@property (nonatomic, copy, readonly) id<MASConstraint> (^key)(id key);
/**
* Creates a NSLayoutConstraint. The constraint is added to the first view or the or the closest common superview of the first and second view.
*/
- (void)commit;
... ... @@ -52,7 +120,9 @@ typedef float MASLayoutPriority;
@protocol MASConstraintDelegate <NSObject>
/**
Notifies the delegate when the constraint is has the minimum set of properties, has a NSLayoutRelation and view
* Notifies the delegate when the constraint is has the minimum set of properties.
*
* @param constraint a constraint that has at least a NSLayoutRelation and view
*/
- (void)addConstraint:(id<MASConstraint>)constraint;
... ...
... ... @@ -11,6 +11,10 @@
@interface MASConstraintMaker : NSObject
/**
* The following properties return a new MASViewConstraint
* with the first item set to the makers associated view and the appropriate MASViewAttribute
*/
@property (nonatomic, strong, readonly) id<MASConstraint> left;
@property (nonatomic, strong, readonly) id<MASConstraint> top;
@property (nonatomic, strong, readonly) id<MASConstraint> right;
... ... @@ -23,11 +27,39 @@
@property (nonatomic, strong, readonly) id<MASConstraint> centerY;
@property (nonatomic, strong, readonly) id<MASConstraint> baseline;
/**
* Creates a MASCompositeConstraint with type MASCompositeConstraintTypeEdges
* which generates the appropriate MASViewConstraint children (top, left, bottom, right)
* with the first item set to the makers associated view
*/
@property (nonatomic, strong, readonly) id<MASConstraint> edges;
/**
* Creates a MASCompositeConstraint with type MASCompositeConstraintTypeSize
* which generates the appropriate MASViewConstraint children (width, height)
* with the first item set to the makers associated view
*/
@property (nonatomic, strong, readonly) id<MASConstraint> size;
/**
* Creates a MASCompositeConstraint with type MASCompositeConstraintTypeCenter
* which generates the appropriate MASViewConstraint children (centerX, centerY)
* with the first item set to the makers associated view
*/
@property (nonatomic, strong, readonly) id<MASConstraint> center;
/**
* initialises the maker with a default view
*
* @param view any MASConstrait are created with this view as the first item
*
* @return a new MASConstraintMaker
*/
- (id)initWithView:(UIView *)view;
/**
* Calls commit method on any MASConstraints which requested to be added view MASConstraintDelegate
*/
- (void)commit;
@end
... ...
//
// MASLayoutConstraint.h
// Masonry
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
* When you are debugging or printing the constraints attached to a view this subclass
* makes it easier to identify which constraints have been created via Masonry
*/
@interface MASLayoutConstraint : NSLayoutConstraint
@end
... ...
//
// MASLayoutConstraint.m
// Masonry
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import "MASLayoutConstraint.h"
@implementation MASLayoutConstraint
@end
... ...
... ... @@ -16,9 +16,9 @@
- (id)initWithView:(UIView *)view layoutAttribute:(NSLayoutAttribute)layoutAttribute;
/**
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
@return YES if layoutAttribute is equal to NSLayoutAttributeWidth or NSLayoutAttributeHeight
* Determine whether the layoutAttribute is a size attribute
*
* @return YES if layoutAttribute is equal to NSLayoutAttributeWidth or NSLayoutAttributeHeight
*/
- (BOOL)isSizeAttribute;
... ...
... ... @@ -8,13 +8,37 @@
#import "MASViewAttribute.h"
#import "MASConstraint.h"
#import "MASLayoutConstraint.h"
@interface MASViewConstraint : NSObject <MASConstraint, NSCopying>
/**
* Usually MASConstraintMaker but could be a parent MASConstraint
*/
@property (nonatomic, weak) id<MASConstraintDelegate> delegate;
/**
* First item/view and first attribute of the NSLayoutConstraint
*/
@property (nonatomic, strong, readonly) MASViewAttribute *firstViewAttribute;
/**
* Second item/view and second attribute of the NSLayoutConstraint
*/
@property (nonatomic, strong, readonly) MASViewAttribute *secondViewAttribute;
/**
* The generate MASLayoutConstraint could be nil if -commit has not been called
*/
@property (nonatomic, strong, readonly) MASLayoutConstraint *layoutConstraint;
/**
* initialises the MASViewConstraint with the first part of the equation
*
* @param firstViewAttribute view.mas_left, view.mas_width etc.
*
* @return a new view constraint
*/
- (id)initWithFirstViewAttribute:(MASViewAttribute *)firstViewAttribute;
@end
\ No newline at end of file
... ...
... ... @@ -8,11 +8,13 @@
#import "MASViewConstraint.h"
#import "MASCompositeConstraint.h"
#import "MASLayoutConstraint.h"
#import "NSObject+MASKeyAdditions.h"
@interface MASViewConstraint ()
@property (nonatomic, strong, readwrite) MASViewAttribute *secondViewAttribute;
@property (nonatomic, strong) NSLayoutConstraint *layoutConstraint;
@property (nonatomic, strong, readwrite) MASLayoutConstraint *layoutConstraint;
@property (nonatomic, assign) NSLayoutRelation layoutRelation;
@property (nonatomic, assign) MASLayoutPriority layoutPriority;
@property (nonatomic, assign) CGFloat layoutMultiplier;
... ... @@ -228,6 +230,15 @@
return self;
}
#pragma mark - debug helpers
- (id<MASConstraint> (^)(id))key {
return ^id(id key) {
self.mas_key = key;
return self;
};
}
#pragma mark - MASConstraint
- (void)commit {
... ... @@ -243,15 +254,16 @@
}
self.layoutConstraint = [NSLayoutConstraint constraintWithItem:firstLayoutItem
attribute:firstLayoutAttribute
relatedBy:self.layoutRelation
toItem:secondLayoutItem
attribute:secondLayoutAttribute
multiplier:self.layoutMultiplier
constant:self.layoutConstant];
self.layoutConstraint = [MASLayoutConstraint constraintWithItem:firstLayoutItem
attribute:firstLayoutAttribute
relatedBy:self.layoutRelation
toItem:secondLayoutItem
attribute:secondLayoutAttribute
multiplier:self.layoutMultiplier
constant:self.layoutConstant];
self.layoutConstraint.priority = self.layoutPriority;
self.layoutConstraint.mas_key = self.mas_key;
if (secondLayoutItem) {
UIView *closestCommonSuperview = nil;
... ... @@ -276,8 +288,6 @@
[firstLayoutItem addConstraint:self.layoutConstraint];
}
}
@end
... ...
... ... @@ -12,4 +12,6 @@
#import "MASCompositeConstraint.h"
#import "MASViewAttribute.h"
#import "MASViewConstraint.h"
#import "MASConstraintMaker.h"
\ No newline at end of file
#import "MASConstraintMaker.h"
#import "MASLayoutConstraint.h"
#import "NSLayoutConstraint+MASDebugAdditions.h"
\ No newline at end of file
... ...
//
// NSLayoutConstraint+MASDebugAdditions.h
// Masonry
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "NSObject+MASKeyAdditions.h"
/**
* makes debug and log output of NSLayoutConstraints more readable
*/
@interface NSLayoutConstraint (MASDebugAdditions)
@end
... ...
//
// NSLayoutConstraint+MASDebugAdditions.m
// Masonry
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import "NSLayoutConstraint+MASDebugAdditions.h"
#import "MASConstraint.h"
@implementation NSLayoutConstraint (MASDebugAdditions)
#pragma mark - description maps
+ (NSDictionary *)layoutRelationDescriptionsByValue {
static dispatch_once_t once;
static NSDictionary *descriptionMap;
dispatch_once(&once, ^{
descriptionMap = @{
@(NSLayoutRelationEqual) : @"==",
@(NSLayoutRelationGreaterThanOrEqual) : @">=",
@(NSLayoutRelationLessThanOrEqual) : @"<=",
};
});
return descriptionMap;
}
+ (NSDictionary *)layoutAttributeDescriptionsByValue {
static dispatch_once_t once;
static NSDictionary *descriptionMap;
dispatch_once(&once, ^{
descriptionMap = @{
@(NSLayoutAttributeTop) : @"top",
@(NSLayoutAttributeLeft) : @"left",
@(NSLayoutAttributeBottom) : @"bottom",
@(NSLayoutAttributeRight) : @"right",
@(NSLayoutAttributeLeading) : @"leading",
@(NSLayoutAttributeTrailing) : @"trailing",
@(NSLayoutAttributeWidth) : @"width",
@(NSLayoutAttributeHeight) : @"height",
@(NSLayoutAttributeCenterX) : @"centerX",
@(NSLayoutAttributeCenterY) : @"centerY",
@(NSLayoutAttributeBaseline) : @"baseline",
};
});
return descriptionMap;
}
+ (NSDictionary *)layoutPriorityDescriptionsByValue {
static dispatch_once_t once;
static NSDictionary *descriptionMap;
dispatch_once(&once, ^{
descriptionMap = @{
@(MASLayoutPriorityDefaultHigh) : @"high",
@(MASLayoutPriorityDefaultLow) : @"low",
@(MASLayoutPriorityDefaultMedium) : @"medium",
@(MASLayoutPriorityRequired) : @"required",
@(MASLayoutPriorityFittingSizeLevel) : @"fitting size",
};
});
return descriptionMap;
}
#pragma mark - description override
+ (NSString *)descriptionForObject:(id)obj {
if ([obj mas_key]) {
return [NSString stringWithFormat:@"%@:%@", [obj class], [obj mas_key]];
}
return [NSString stringWithFormat:@"%@:%p", [obj class], obj];
}
- (NSString *)description {
NSMutableString *description = [[NSMutableString alloc] initWithString:@"<"];
[description appendString:[self.class descriptionForObject:self]];
[description appendFormat:@" %@", [self.class descriptionForObject:self.firstItem]];
if (self.firstAttribute != NSLayoutAttributeNotAnAttribute) {
[description appendFormat:@".%@", self.class.layoutAttributeDescriptionsByValue[@(self.firstAttribute)]];
}
[description appendFormat:@" %@", self.class.layoutRelationDescriptionsByValue[@(self.relation)]];
if (self.secondItem) {
[description appendFormat:@" %@", [self.class descriptionForObject:self.secondItem]];
}
if (self.secondAttribute != NSLayoutAttributeNotAnAttribute) {
[description appendFormat:@".%@", self.class.layoutAttributeDescriptionsByValue[@(self.secondAttribute)]];
}
if (self.multiplier != 1) {
[description appendFormat:@" * %g", self.multiplier];
}
if (self.constant) {
if (self.secondAttribute == NSLayoutAttributeNotAnAttribute) {
[description appendFormat:@" %g", self.constant];
} else {
[description appendFormat:@" %@ %g", (self.constant < 0 ? @"-" : @"+"), ABS(self.constant)];
}
}
if (self.priority != UILayoutPriorityRequired) {
[description appendFormat:@" ^%@", self.class.layoutPriorityDescriptionsByValue[@(self.priority)] ?: [NSNumber numberWithDouble:self.priority]];
}
[description appendString:@">"];
return description;
}
@end
... ...
//
// NSObject+MASKeyAdditions.h
// Masonry
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSObject (MASKeyAdditions)
/**
* a key to associate with this object
*/
@property (nonatomic, strong) id mas_key;
@end
/**
* Allows you to attach keys to objects matching the variable names passed.
*
* view1.mas_key = @"view1", view2.mas_key = @"view2";
*
* is equivalent to:
*
* MASAttachKeys(view1, view2);
*/
#define MASAttachKeys(...) \
NSDictionary *keyPairs = NSDictionaryOfVariableBindings(__VA_ARGS__); \
for (id key in keyPairs.allKeys) { \
[keyPairs[key] setMas_key:key]; \
}
\ No newline at end of file
... ...
//
// NSObject+MASKeyAdditions.m
// Masonry
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import "NSObject+MASKeyAdditions.h"
#import <objc/runtime.h>
@implementation NSObject (MASKeyAdditions)
- (id)mas_key {
return objc_getAssociatedObject(self, @selector(mas_key));
}
- (void)setMas_key:(id)key {
objc_setAssociatedObject(self, @selector(mas_key), key, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
... ...
... ... @@ -10,9 +10,15 @@
#import "MASConstraintMaker.h"
#import "MASViewAttribute.h"
/**
* Provides constraint maker block
* and convience methods for creating MASViewAttribute which are view + NSLayoutAttribute pairs
*/
@interface UIView (MASAdditions)
// following properties return a new MASViewAttribute with current view and appropriate NSLayoutAttribute
/**
* following properties return a new MASViewAttribute with current view and appropriate NSLayoutAttribute
*/
@property (nonatomic, strong, readonly) MASViewAttribute *mas_left;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_top;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_right;
... ...
... ... @@ -11,6 +11,10 @@
#ifdef MAS_SHORTHAND
/**
* Shorthand view additions without the 'mas_' prefixes,
* only enabled if MAS_SHORTHAND is defined
*/
@interface UIView (MASShorthandAdditions)
@property (nonatomic, strong, readonly) MASViewAttribute *left;
... ...
... ... @@ -19,6 +19,7 @@
DD52F254179CADC0005CD195 /* MASExampleSidesView.m in Sources */ = {isa = PBXBuildFile; fileRef = DD52F24E179CADC0005CD195 /* MASExampleSidesView.m */; };
DD52F255179CADC0005CD195 /* MASExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DD52F250179CADC0005CD195 /* MASExampleViewController.m */; };
DD52F26E179CBA05005CD195 /* libMasonry.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DD52F26D179CBA05005CD195 /* libMasonry.a */; };
DD7CC17617ACE990007A469E /* MASExampleDebuggingView.m in Sources */ = {isa = PBXBuildFile; fileRef = DD7CC17517ACE990007A469E /* MASExampleDebuggingView.m */; };
DDF3875C179D648D00178773 /* MASExampleAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = DDF3875B179D648D00178773 /* MASExampleAnimatedView.m */; };
/* End PBXBuildFile section */
... ... @@ -44,6 +45,8 @@
DD52F24F179CADC0005CD195 /* MASExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleViewController.h; sourceTree = "<group>"; };
DD52F250179CADC0005CD195 /* MASExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleViewController.m; sourceTree = "<group>"; };
DD52F26D179CBA05005CD195 /* libMasonry.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libMasonry.a; sourceTree = BUILT_PRODUCTS_DIR; };
DD7CC17417ACE990007A469E /* MASExampleDebuggingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleDebuggingView.h; sourceTree = "<group>"; };
DD7CC17517ACE990007A469E /* MASExampleDebuggingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleDebuggingView.m; sourceTree = "<group>"; };
DDF3875A179D648D00178773 /* MASExampleAnimatedView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleAnimatedView.h; sourceTree = "<group>"; };
DDF3875B179D648D00178773 /* MASExampleAnimatedView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleAnimatedView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
... ... @@ -125,6 +128,8 @@
DD52F24E179CADC0005CD195 /* MASExampleSidesView.m */,
DDF3875A179D648D00178773 /* MASExampleAnimatedView.h */,
DDF3875B179D648D00178773 /* MASExampleAnimatedView.m */,
DD7CC17417ACE990007A469E /* MASExampleDebuggingView.h */,
DD7CC17517ACE990007A469E /* MASExampleDebuggingView.m */,
);
name = Views;
sourceTree = "<group>";
... ... @@ -211,6 +216,7 @@
DD52F254179CADC0005CD195 /* MASExampleSidesView.m in Sources */,
DD52F255179CADC0005CD195 /* MASExampleViewController.m in Sources */,
DDF3875C179D648D00178773 /* MASExampleAnimatedView.m in Sources */,
DD7CC17617ACE990007A469E /* MASExampleDebuggingView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ...
... ... @@ -64,7 +64,6 @@
make.left.equalTo(superview.mas_left).offset(padding);
make.bottom.equalTo(superview.mas_bottom).offset(-padding);
make.right.equalTo(superview.mas_right).offset(-padding);
make.height.equalTo(@[view1.mas_height, view2.mas_height]); //can pass array of attributes
}];
... ...
//
// MASExampleDebuggingView.h
// MasonryExamples
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface MASExampleDebuggingView : UIView
@end
... ...
//
// MASExampleDebuggingView.m
// MasonryExamples
//
// Created by Jonas Budelmann on 3/08/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import "MASExampleDebuggingView.h"
@implementation MASExampleDebuggingView
- (id)init {
self = [super init];
if (!self) return nil;
UIView *view1 = UIView.new;
view1.backgroundColor = UIColor.greenColor;
view1.layer.borderColor = UIColor.blackColor.CGColor;
view1.layer.borderWidth = 2;
[self addSubview:view1];
UIView *view2 = UIView.new;
view2.backgroundColor = UIColor.redColor;
view2.layer.borderColor = UIColor.blackColor.CGColor;
view2.layer.borderWidth = 2;
[self addSubview:view2];
UILabel *view3 = UILabel.new;
view3.backgroundColor = UIColor.blueColor;
view3.numberOfLines = 3;
view3.textAlignment = NSTextAlignmentCenter;
view3.font = [UIFont systemFontOfSize:24];
view3.textColor = UIColor.whiteColor;
view3.text = @"this should look broken! check your console!";
view3.layer.borderColor = UIColor.blackColor.CGColor;
view3.layer.borderWidth = 2;
[self addSubview:view3];
UIView *superview = self;
int padding = 10;
//you can attach debug keys to views like so:
// view1.mas_key = @"view1";
// view2.mas_key = @"view2";
// view3.mas_key = @"view3";
// superview.mas_key = @"superview";
//OR you can attach keys automagically like so:
MASAttachKeys(view1, view2, view3, superview);
[view3 mas_makeConstraints:^(MASConstraintMaker *make) {
//you can also attach debug keys to constaints
make.edges.equalTo(@1).key(@"ConflictingConstraint"); //composite constraint keys will be indexed
make.height.greaterThanOrEqualTo(@5000).key(@"ConstantConstraint");
make.top.equalTo(view1.mas_bottom).offset(padding);
make.left.equalTo(superview.mas_left).offset(padding);
make.bottom.equalTo(superview.mas_bottom).offset(-padding).key(@"BottomConstraint");
make.right.equalTo(superview.mas_right).offset(-padding);
make.height.equalTo(view1.mas_height);
make.height.equalTo(view2.mas_height).key(@340954); //anything can be a key
}];
[view1 makeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(superview.top).offset(padding);
make.left.equalTo(superview.left).offset(padding);
make.bottom.equalTo(view3.top).offset(-padding);
make.right.equalTo(view2.left).offset(-padding);
make.width.equalTo(view2.width);
make.height.equalTo(view2.height);
make.height.equalTo(view3.height);
}];
//with is semantic and option
[view2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding);
make.left.equalTo(view1.mas_right).offset(padding);
make.bottom.equalTo(view3.mas_top).offset(-padding);
make.right.equalTo(superview.mas_right).offset(-padding);
make.width.equalTo(view1.mas_width);
make.height.equalTo(@[view1, view3]);
}];
return self;
}
@end
... ...
... ... @@ -12,6 +12,7 @@
#import "MASExampleConstantsView.h"
#import "MASExampleSidesView.h"
#import "MASExampleAnimatedView.h"
#import "MASExampleDebuggingView.h"
static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier";
... ... @@ -30,10 +31,16 @@ static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier";
self.title = @"Examples";
self.exampleControllers = @[
[[MASExampleViewController alloc] initWithTitle:@"Basic" viewClass:MASExampleBasicView.class],
[[MASExampleViewController alloc] initWithTitle:@"Using Constants" viewClass:MASExampleConstantsView.class],
[[MASExampleViewController alloc] initWithTitle:@"Composite sides" viewClass:MASExampleSidesView.class],
[[MASExampleViewController alloc] initWithTitle:@"Basic Animated" viewClass:MASExampleAnimatedView.class],
[[MASExampleViewController alloc] initWithTitle:@"Basic"
viewClass:MASExampleBasicView.class],
[[MASExampleViewController alloc] initWithTitle:@"Using Constants"
viewClass:MASExampleConstantsView.class],
[[MASExampleViewController alloc] initWithTitle:@"Composite sides"
viewClass:MASExampleSidesView.class],
[[MASExampleViewController alloc] initWithTitle:@"Basic Animated"
viewClass:MASExampleAnimatedView.class],
[[MASExampleViewController alloc] initWithTitle:@"Debugging helpers"
viewClass:MASExampleDebuggingView.class],
];
return self;
... ...
... ... @@ -13,7 +13,6 @@
@interface MASViewConstraint ()
@property (nonatomic, strong) NSLayoutConstraint *layoutConstraint;
@property (nonatomic, assign) NSLayoutRelation layoutRelation;
@property (nonatomic, assign) MASLayoutPriority layoutPriority;
@property (nonatomic, assign) CGFloat layoutMultiplier;
... ...
Masonry
=======
Masonary is a light-weight layout framework which wraps AutoLayout with a nicer syntax. Masonary has its own layout DSL which provides a chainable way of describing your NSLayoutConstraints which results in layout code which is more concise and readable.
Masonary is a light-weight layout framework which wraps AutoLayout with a nicer syntax. Masonary has its own layout DSL which provides a chainable way of describing your NSLayoutConstraints which results in layout code that is more concise and readable.
For examples take a look at the **MasonryExamples** project in the Masonry workspace.
... ... @@ -81,7 +81,7 @@ Or ever shorter
}];
```
Also note in the first example we had add the constraints to the superview `[superview addConstraints:...`.
Also note in the first example we had to add the constraints to the superview `[superview addConstraints:...`.
Masonry however will automagically add constraints to the appropriate view.
Masonry will also call `view1.translatesAutoresizingMaskIntoConstraints = NO;` for you.
... ... @@ -201,28 +201,63 @@ make.center.equalTo(button1)
// make centerX = superview.centerX - 5, centerY = superview.centerY + 10
make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))
```
## When the ^&*!@ hits the fan!
Laying out your views doesn't always goto plan. So when things literally go pear shaped, you don't want to be looking at console output like this:
```
Unable to simultaneously satisfy constraints.....blah blah blah....
(
"<NSLayoutConstraint:0x7189ac0 V:[UILabel:0x7186980(>=5000)]>",
"<NSAutoresizingMaskLayoutConstraint:0x839ea20 h=--& v=--& V:[MASExampleDebuggingView:0x7186560(416)]>",
"<NSLayoutConstraint:0x7189c70 UILabel:0x7186980.bottom == MASExampleDebuggingView:0x7186560.bottom - 10>",
"<NSLayoutConstraint:0x7189560 V:|-(1)-[UILabel:0x7186980] (Names: '|':MASExampleDebuggingView:0x7186560 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7189ac0 V:[UILabel:0x7186980(>=5000)]>
```
Masonry adds a category to NSLayoutConstraint which overrides the default implementation of `- (NSString *)description`.
Now you can give meaningful names to views and constraints, and also easily pick out the constraints created by Masonry.
which means your console output can now look like this:
```
Unable to simultaneously satisfy constraints......blah blah blah....
(
"<NSAutoresizingMaskLayoutConstraint:0x8887740 MASExampleDebuggingView:superview.height == 416>",
"<MASLayoutConstraint:ConstantConstraint UILabel:messageLabel.height >= 5000>",
"<MASLayoutConstraint:BottomConstraint UILabel:messageLabel.bottom == MASExampleDebuggingView:superview.bottom - 10>",
"<MASLayoutConstraint:ConflictingConstraint[0] UILabel:messageLabel.top == MASExampleDebuggingView:superview.top + 1>"
)
Will attempt to recover by breaking constraint
<MASLayoutConstraint:ConstantConstraint UILabel:messageLabel.height >= 5000>
```
For an example of how to set this up take a look at the **MasonryExamples** project in the Masonry workspace.
## Installation
Use the [orsome](http://www.youtube.com/watch?v=YaIZF8uUTtk) [CocoaPods](http://github.com/CocoaPods/CocoaPods).
In your Podfile
```ruby
pod 'Masonry'
```
>`pod 'Masonry'`
If you want to use masonry without all those pesky 'mas_' prefixes. Add #define MAS_SHORTHAND to your prefix.pch before importing Masonry
```obj-c
#define MAS_SHORTHAND
```
>`#define MAS_SHORTHAND`
Get busy Masoning
```obj-c
#import "Masonry.h"
```
>`#import "Masonry.h"`
## Features
* No macro magic. Masonry won't pollute the global namespace with macros.
* Not limited to subset of Auto Layout. Anything NSLayoutConstraint can do, Masonry can do to!
* Great debug support, give your views and constraints meaningful names.
* Constraints read like sentences.
* No crazy macro magic. Masonry won't pollute the global namespace with macros.
* Not string or dictionary based and hence you get compile time checking.
## TODO
* Eye candy
* Better debugging help for complicated layouts
* Header comments/Documentation
* Mac support
* More tests and examples
... ...