Authored by Robert Payne

Merge pull request #225 from pingyourid/master

add distribute function
... ... @@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
00FC4A321B7359D700DCA999 /* MASExampleDistributeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 00FC4A311B7359D700DCA999 /* MASExampleDistributeView.m */; };
114413091924B6EE008E702E /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 114413081924B6EE008E702E /* Default-568h@2x.png */; };
27A27D461A6CF0C400D34F52 /* MASExampleAspectFitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A27D451A6CF0C400D34F52 /* MASExampleAspectFitView.m */; };
3C02224919D0C4EC00507321 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3C02224819D0C4EC00507321 /* Images.xcassets */; };
... ... @@ -35,6 +36,8 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
00FC4A301B7359D700DCA999 /* MASExampleDistributeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleDistributeView.h; sourceTree = "<group>"; };
00FC4A311B7359D700DCA999 /* MASExampleDistributeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleDistributeView.m; sourceTree = "<group>"; };
114413081924B6EE008E702E /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
27A27D441A6CF0C400D34F52 /* MASExampleAspectFitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleAspectFitView.h; sourceTree = "<group>"; };
27A27D451A6CF0C400D34F52 /* MASExampleAspectFitView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleAspectFitView.m; sourceTree = "<group>"; };
... ... @@ -182,6 +185,8 @@
DD32C3FC18E8BFF6001F6AD2 /* MASExampleAttributeChainingView.m */,
44C0E6AD1A9B9C55003C70CF /* MASExampleMarginView.h */,
44C0E6AE1A9B9C55003C70CF /* MASExampleMarginView.m */,
00FC4A301B7359D700DCA999 /* MASExampleDistributeView.h */,
00FC4A311B7359D700DCA999 /* MASExampleDistributeView.m */,
);
name = Views;
sourceTree = "<group>";
... ... @@ -308,6 +313,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00FC4A321B7359D700DCA999 /* MASExampleDistributeView.m in Sources */,
DD175E6A182639FB0099129A /* MASExampleUpdateView.m in Sources */,
DD52F237179CAD57005CD195 /* main.m in Sources */,
3DB1CAD5184538E200E91FC5 /* MASExampleArrayView.m in Sources */,
... ...
//
// MASExampleDistributeView.h
// Masonry iOS Examples
//
// Created by bibibi on 15/8/6.
// Copyright (c) 2015年 Jonas Budelmann. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface MASExampleDistributeView : UIView
@end
... ...
//
// MASExampleDistributeView.m
// Masonry iOS Examples
//
// Created by bibibi on 15/8/6.
// Copyright (c) 2015年 Jonas Budelmann. All rights reserved.
//
#import "MASExampleDistributeView.h"
@implementation MASExampleDistributeView
- (id)init {
self = [super init];
if (!self) return nil;
NSMutableArray *arr = @[].mutableCopy;
for (int i = 0; i < 4; i++) {
UIView *view = UIView.new;
view.backgroundColor = [self randomColor];
view.layer.borderColor = UIColor.blackColor.CGColor;
view.layer.borderWidth = 2;
[self addSubview:view];
[arr addObject:view];
}
unsigned int type = arc4random()%4;
switch (type) {
case 0:
[arr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:5 tailSpacing:5];
[arr makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@60);
make.height.equalTo(@60);
}];
break;
case 1:
[arr mas_distributeViewsAlongAxis:MASAxisTypeVertical withFixedSpacing:20 leadSpacing:5 tailSpacing:5];
[arr makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(@0);
make.width.equalTo(@60);
}];
break;
case 2:
[arr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:30 leadSpacing:200 tailSpacing:30];
[arr makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@60);
make.height.equalTo(@60);
}];
break;
case 3:
[arr mas_distributeViewsAlongAxis:MASAxisTypeVertical withFixedItemLength:30 leadSpacing:30 tailSpacing:200];
[arr makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(@0);
make.width.equalTo(@60);
}];
break;
default:
break;
}
return self;
}
- (UIColor *)randomColor {
CGFloat hue = ( arc4random() % 256 / 256.0 ); // 0.0 to 1.0
CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from white
CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from black
return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1];
}
@end
... ...
... ... @@ -22,6 +22,7 @@
#import "MASExampleAttributeChainingView.h"
#import "MASExampleAspectFitView.h"
#import "MASExampleMarginView.h"
#import "MASExampleDistributeView.h"
static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier";
... ... @@ -66,6 +67,8 @@ static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier";
viewClass:MASExampleAttributeChainingView.class],
[[MASExampleViewController alloc] initWithTitle:@"Margins"
viewClass:MASExampleMarginView.class],
[[MASExampleViewController alloc] initWithTitle:@"Views Distribute"
viewClass:MASExampleDistributeView.class],
];
... ...
... ... @@ -10,6 +10,11 @@
#import "MASConstraintMaker.h"
#import "MASViewAttribute.h"
typedef NS_ENUM(NSUInteger, MASAxisType) {
MASAxisTypeHorizontal,
MASAxisTypeVertical
};
@interface NSArray (MASAdditions)
/**
... ... @@ -20,7 +25,7 @@
*
* @return Array of created MASConstraints
*/
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block;
- (NSArray *)mas_makeConstraints:(void (^)(MASConstraintMaker *make))block;
/**
* Creates a MASConstraintMaker with each view in the callee.
... ... @@ -31,7 +36,7 @@
*
* @return Array of created/updated MASConstraints
*/
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block;
- (NSArray *)mas_updateConstraints:(void (^)(MASConstraintMaker *make))block;
/**
* Creates a MASConstraintMaker with each view in the callee.
... ... @@ -42,6 +47,26 @@
*
* @return Array of created/updated MASConstraints
*/
- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block;
- (NSArray *)mas_remakeConstraints:(void (^)(MASConstraintMaker *make))block;
/**
* distribute with fixed spacing
*
* @param axisType which axis to distribute items along
* @param fixedSpacing the spacing between each item
* @param leadSpacing the spacing before the first item and the container
* @param tailSpacing the spacing after the last item and the container
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
/**
* distribute with fixed item size
*
* @param axisType which axis to distribute items along
* @param fixedItemLength the fixed length of each item
* @param leadSpacing the spacing before the first item and the container
* @param tailSpacing the spacing after the last item and the container
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
@end
... ...
... ... @@ -38,4 +38,127 @@
return constraints;
}
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing {
if (self.count < 2) {
NSAssert(self.count>1,@"views to distribute need to bigger than one");
return;
}
MAS_VIEW *tempSuperView = [self mas_commonSuperviewOfViews];
if (axisType == MASAxisTypeHorizontal) {
MAS_VIEW *prev;
for (int i = 0; i < self.count; i++) {
MAS_VIEW *v = [self objectAtIndex:i];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
if (prev) {
make.width.equalTo(prev);
make.left.equalTo(prev.mas_right).offset(fixedSpacing);
if (i == (CGFloat)self.count - 1) {//last one
make.right.equalTo(tempSuperView).offset(-tailSpacing);
}
}
else {//first one
make.left.equalTo(tempSuperView).offset(leadSpacing);
}
}];
prev = v;
}
}
else {
MAS_VIEW *prev;
for (int i = 0; i < self.count; i++) {
MAS_VIEW *v = [self objectAtIndex:i];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
if (prev) {
make.height.equalTo(prev);
make.top.equalTo(prev.mas_bottom).offset(fixedSpacing);
if (i == (CGFloat)self.count - 1) {//last one
make.bottom.equalTo(tempSuperView).offset(-tailSpacing);
}
}
else {//first one
make.top.equalTo(tempSuperView).offset(leadSpacing);
}
}];
prev = v;
}
}
}
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing {
if (self.count < 2) {
NSAssert(self.count>1,@"views to distribute need to bigger than one");
return;
}
MAS_VIEW *tempSuperView = [self mas_commonSuperviewOfViews];
if (axisType == MASAxisTypeHorizontal) {
MAS_VIEW *prev;
for (int i = 0; i < self.count; i++) {
MAS_VIEW *v = [self objectAtIndex:i];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
if (prev) {
CGFloat offset = (1-(i/((CGFloat)self.count-1)))*(fixedItemLength+leadSpacing)-i*tailSpacing/(((CGFloat)self.count-1));
make.width.equalTo(@(fixedItemLength));
if (i == (CGFloat)self.count - 1) {//last one
make.right.equalTo(tempSuperView).offset(-tailSpacing);
}
else {
make.right.equalTo(tempSuperView).multipliedBy(i/((CGFloat)self.count-1)).with.offset(offset);
}
}
else {//first one
make.left.equalTo(tempSuperView).offset(leadSpacing);
make.width.equalTo(@(fixedItemLength));
}
}];
prev = v;
}
}
else {
MAS_VIEW *prev;
for (int i = 0; i < self.count; i++) {
MAS_VIEW *v = [self objectAtIndex:i];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
if (prev) {
CGFloat offset = (1-(i/((CGFloat)self.count-1)))*(fixedItemLength+leadSpacing)-i*tailSpacing/(((CGFloat)self.count-1));
make.height.equalTo(@(fixedItemLength));
if (i == (CGFloat)self.count - 1) {//last one
make.bottom.equalTo(tempSuperView).offset(-tailSpacing);
}
else {
make.bottom.equalTo(tempSuperView).multipliedBy(i/((CGFloat)self.count-1)).with.offset(offset);
}
}
else {//first one
make.top.equalTo(tempSuperView).offset(leadSpacing);
make.height.equalTo(@(fixedItemLength));
}
}];
prev = v;
}
}
}
- (MAS_VIEW *)mas_commonSuperviewOfViews
{
MAS_VIEW *commonSuperview = nil;
MAS_VIEW *previousView = nil;
for (id object in self) {
if ([object isKindOfClass:[MAS_VIEW class]]) {
MAS_VIEW *view = (MAS_VIEW *)object;
if (previousView) {
commonSuperview = [view mas_closestCommonSuperview:commonSuperview];
} else {
commonSuperview = view;
}
previousView = view;
}
}
NSAssert(commonSuperview, @"Can't constrain views that do not share a common superview. Make sure that all the views in this array have been added into the same view hierarchy.");
return commonSuperview;
}
@end
... ...
... ... @@ -59,4 +59,93 @@ SpecBegin(NSArray_MASAdditions)
}];
}
- (void)testDistributeViewsWithFixedSpacingShouldFailWhenArrayContainsLessTwoViews {
MAS_VIEW *superView = MAS_VIEW.new;
MAS_VIEW *subject1 = MAS_VIEW.new;
[superView addSubview:subject1];
MAS_VIEW *subject2 = MAS_VIEW.new;
[superView addSubview:subject2];
NSArray *views = @[ subject1];
expect(^{
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:10.0 leadSpacing:5.0 tailSpacing:5.0];
}).to.raiseAny();
}
- (void)testDistributeViewsWithFixedItemLengthShouldFailWhenArrayContainsLessTwoViews {
MAS_VIEW *superView = MAS_VIEW.new;
MAS_VIEW *subject1 = MAS_VIEW.new;
[superView addSubview:subject1];
MAS_VIEW *subject2 = MAS_VIEW.new;
[superView addSubview:subject2];
NSArray *views = @[ subject1];
expect(^{
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:10.0 leadSpacing:5.0 tailSpacing:5.0];
}).to.raiseAny();
}
- (void)testDistributeViewsWithFixedSpacingShouldHaveCorrectNumberOfConstraints {
MAS_VIEW *superView = MAS_VIEW.new;
MAS_VIEW *subject1 = MAS_VIEW.new;
[superView addSubview:subject1];
MAS_VIEW *subject2 = MAS_VIEW.new;
[superView addSubview:subject2];
MAS_VIEW *subject3 = MAS_VIEW.new;
[superView addSubview:subject3];
NSArray *views = @[ subject1,subject2,subject3 ];
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:10.0 leadSpacing:5.0 tailSpacing:5.0];
//left view
NSArray *arr1 = [MASViewConstraint installedConstraintsForView:subject1];
expect(arr1).to.haveCountOf(1);
//middle view
NSArray *arr2 = [MASViewConstraint installedConstraintsForView:subject2];
expect(arr2).to.haveCountOf(2);
//right view
NSArray *arr3 = [MASViewConstraint installedConstraintsForView:subject3];
expect(arr3).to.haveCountOf(3);
}
- (void)testDistributeViewsWithFixedItemLengthShouldHaveCorrectNumberOfConstraints {
MAS_VIEW *superView = MAS_VIEW.new;
MAS_VIEW *subject1 = MAS_VIEW.new;
[superView addSubview:subject1];
MAS_VIEW *subject2 = MAS_VIEW.new;
[superView addSubview:subject2];
MAS_VIEW *subject3 = MAS_VIEW.new;
[superView addSubview:subject3];
NSArray *views = @[ subject1,subject2,subject3 ];
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:30.0 leadSpacing:5.0 tailSpacing:5.0];
//left view
NSArray *arr1 = [MASViewConstraint installedConstraintsForView:subject1];
expect(arr1).to.haveCountOf(2);
//middle view
NSArray *arr2 = [MASViewConstraint installedConstraintsForView:subject2];
expect(arr2).to.haveCountOf(2);
//right view
NSArray *arr3 = [MASViewConstraint installedConstraintsForView:subject3];
expect(arr3).to.haveCountOf(2);
}
SpecEnd
... ...