1、前言git
关于苹果的布局一直是我比较纠结的问题,是写代码来控制布局,仍是使用storyboard来控制布局呢?之前我我的开发的时候不多使用代码去写约束,由于太麻烦了。因此最终选择的都是AutoLayout进行布局,而后拖线设置约束。不过好多公司进行iOS开发的时候都会去动态的修改约束,并且有的会使用约束去建立一些动画,因此不太去用storyboard进行开发(还有就是使用storyboard几我的合做的时候比较麻烦)。反倒更多的是写代码开发看起来更加的高效。因此好多开发者都开始去使用Masonry。它是一个封装的第三方类库,做用就是来简化开发者写布局约束。github
2、“安装”Masonryapp
由于它是一个第三方的类库,咱们能够从这里下载,而后解压将Masonry那个文件夹拖入本身的项目文件夹下便可。less
3、开始使用Masonryide
咱们在使用它的时候,最好在AppDelegate.m的布局
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
方法中去自定义加载本身的控制器。例如我写的时候就是这样:动画
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window.backgroundColor = [UIColor whiteColor]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]]; self.window.rootViewController = nav; [self.window makeKeyAndVisible]; return YES; }
直接加载的我本身写的ViewController。(建议把系统自带的Main.stoaryboard删除掉,若是运行报错本身修改,问题不大)。ui
先来一个不用Masonry写的最简单的布局:(目的是在视图中添加一个视图)this
- (void)viewDidLoad { [super viewDidLoad]; self.title = @"Basic View"; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1]; UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10); [superview addConstraints:@[ //view1 constraints [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:padding.top], [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeft multiplier:1.0 constant:padding.left], [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-padding.bottom], [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeRight multiplier:1 constant:-padding.right], ]]; }
运行效果以下:atom
这就是咱们用系统的NSLayoutConstraint写的一个view,而后将这个view加载到根view中。如今咱们用Masonry来实现和上边同样的效果:
第一步、导入类库
#import "Masonry.h"
而后修改代码以下:
- (void)viewDidLoad { [super viewDidLoad]; self.title = @"Basic View"; UIView *superview = self.view; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1]; UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).offset(padding.top); make.left.equalTo(superview.mas_left).offset(padding.left); make.bottom.equalTo(superview.mas_bottom).offset(-padding.bottom); make.right.equalTo(superview.mas_right).offset(-padding.right); }]; }
上面的效果和原来用NSLayoutConstraint实现的效果是同样的,因此就再也不贴图。
咱们能够看到,咱们使用的一个mas_makConstrints块来进行约束设置。view1指代的就是要添加约束的view(也能够是button,label等等)。而后make的top,left,bottom,right就至关于view1的上下左右,而后equalTo()括号内的就是相对的view,而后offset是偏移量。
还能够更简单的实现:
- (void)viewDidLoad { [super viewDidLoad]; self.title = @"Basic View"; UIView *superview = self.view; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1]; UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(superview).with.insets(padding); }]; // [view1 mas_makeConstraints:^(MASConstraintMaker *make) { // make.top.equalTo(superview.mas_top).offset(padding.top); // make.left.equalTo(superview.mas_left).offset(padding.left); // make.bottom.equalTo(superview.mas_bottom).offset(-padding.bottom); // make.right.equalTo(superview.mas_right).offset(-padding.right); // }]; }
以上的三种方式都是实现上边图种的效果。
MASViewAttribute | NSLayoutAttribute |
---|---|
view.mas_left | NSLayoutAttributeLeft |
view.mas_right | NSLayoutAttributeRight |
view.mas_top | NSLayoutAttributeTop |
view.mas_bottom | NSLayoutAttributeBottom |
view.mas_leading | NSLayoutAttributeLeading |
view.mas_trailing | NSLayoutAttributeTrailing |
view.mas_width | NSLayoutAttributeWidth |
view.mas_height | NSLayoutAttributeHeight |
view.mas_centerX | NSLayoutAttributeCenterX |
view.mas_centerY | NSLayoutAttributeCenterY |
view.mas_baseline | NSLayoutAttributeBaseline |
以上的属性对应相应的NSLayoutAttribute。
下面就来看它的使用吧。(先上效果图,而后再上代码)
使用1、简单的三个视图的布局
这个时我直接自定义了一个ZGBasicView视图,而后添加到了ViewController中。
关键代码以下:
// // ZGBasicView.m // MasonryDemo // // Created by zhanggui on 15/10/26. // Copyright © 2015年 zhanggui. All rights reserved. // #import "ZGBasicView.h" #import "View+MASShorthandAdditions.h" @implementation ZGBasicView /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (id)init { self = [super init]; if (!self) { return nil; } // self.translatesAutoresizingMaskIntoConstraints = YES; //红色视图 UIView *redView = [UIView new]; redView.backgroundColor = [UIColor redColor]; redView.layer.borderColor = [UIColor blackColor].CGColor; redView.layer.borderWidth = 2; [self addSubview:redView]; //绿色视图 UIView *greenView = [[UIView alloc] init]; greenView.backgroundColor = [UIColor greenColor]; greenView.layer.borderColor = [UIColor blackColor].CGColor; greenView.layer.borderWidth = 2; [self addSubview:greenView]; //蓝色视图 UIView *blueView = [[UIView alloc] init]; blueView.backgroundColor = [UIColor blueColor]; blueView.layer.borderWidth = 2; blueView.layer.borderColor = [UIColor blackColor].CGColor; [self addSubview:blueView]; int padding = 10; UIView *superview = self; //with is semantic and option [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).offset(padding); //with with make.left.equalTo(greenView.mas_right).offset(padding); //without with make.bottom.equalTo(blueView.mas_top).offset(-padding); make.right.equalTo(superview.mas_right).offset(-padding); make.width.equalTo(greenView.mas_width); make.height.equalTo(@[greenView, blueView]); //can pass array of views }]; [greenView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).offset(padding); make.left.equalTo(superview.mas_left).offset(padding); make.bottom.equalTo(blueView.mas_top).offset(-padding); make.right.equalTo(redView.mas_left).offset(-padding); make.width.equalTo(redView.mas_width); make.height.equalTo(redView.mas_height); // make.height.equalTo(blueView.mas_height); }]; [blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(greenView.mas_bottom).offset(padding); 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(greenView.mas_height); //can pass array of attributes }]; return self; } @end
三个视图之间的关系。
场景2、更新视图
效果图以下:
实现代码以下:(这里也是自定义了一个View,而后将这个view加入到了根视图中)
// // UpdateConstraintsView.m // MasonryDemo // // Created by zhanggui on 15/10/26. // Copyright © 2015年 zhanggui. All rights reserved. // #import "UpdateConstraintsView.h" #import "Masonry.h" @interface UpdateConstraintsView () @property (nonatomic,strong)UIButton *myButton; @property (nonatomic,assign)CGSize buttonSize; @end @implementation UpdateConstraintsView - (id)init { self = [super init]; if (self) { self.myButton = [UIButton buttonWithType:UIButtonTypeSystem]; [self.myButton setTitle:@"更新约束" forState:UIControlStateNormal]; self.myButton.layer.borderColor = [UIColor blackColor].CGColor; self.myButton.layer.borderWidth = 2; [self.myButton addTarget:self action:@selector(changeAction:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:self.myButton]; self.buttonSize = CGSizeMake(100, 100); } return self; } /** Returns whether the receiver depends on the constraint-based layout system. YES if the view must be in a window using constraint-based layout to function properly, NO otherwise. */ + (BOOL)requiresConstraintBasedLayout { return YES; } /** Updates constraints for the view. Custom views that set up constraints themselves should do so by overriding this method. When your custom view notes that a change has been made to the view that invalidates one of its constraints, it should immediately remove that constraint, and then call setNeedsUpdateConstraints to note that constraints need to be updated. Before layout is performed, your implementation of updateConstraints will be invoked, allowing you to verify that all necessary constraints for your content are in place at a time when your custom view’s properties are not changing. You must not invalidate any constraints as part of your constraint update phase. You also must not invoke a layout or drawing phase as part of constraint updating. Important:Important Call [super updateConstraints] as the final step in your implementation. 苹果推荐在这个方法里面添加或者更新约束 */ - (void)updateConstraints { [self.myButton mas_updateConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self); make.width.equalTo(@(self.buttonSize.width)).priorityLow(); //设置优先级以及width make.height.equalTo(@(self.buttonSize.height)).priorityLow(); //设置myButton的大小小于等于自身view的大小 make.width.lessThanOrEqualTo(self); make.height.lessThanOrEqualTo(self); }]; [super updateConstraints]; } - (void)changeAction:(UIButton *)button { self.buttonSize = CGSizeMake(self.buttonSize.width*1.2, self.buttonSize.height*1.2); //告诉约束他们须要更新 [self setNeedsUpdateConstraints]; //update constraints now [self updateConstraintsIfNeeded]; //设置更新大小动画 [UIView animateWithDuration:0.5 animations:^{ /** Lays out the subviews immediately. Use this method to force the layout of subviews before drawing. Using the view that receives the message as the root view, this method lays out the view subtree starting at the root. */ [self layoutIfNeeded]; }]; } @end
这里主要使用了mas_updateConstraints:方法
场景3、让约束复原
实现代码以下:
// // ReBackConstraintsView.m // MasonryDemo //能够恢复原来的约束 // Created by zhanggui on 15/10/26. // Copyright © 2015年 zhanggui. All rights reserved. // #import "ReBackConstraintsView.h" #import "Masonry.h" @interface ReBackConstraintsView () @property (nonatomic,strong)UIButton *myButton; @property (nonatomic,assign)BOOL isAtTop; @end @implementation ReBackConstraintsView - (id)init { self = [super init]; if (self) { self.myButton = [UIButton buttonWithType:UIButtonTypeSystem];; [self.myButton setTitle:@"Move Me!" forState:UIControlStateNormal]; self.myButton.layer.borderColor = UIColor.greenColor.CGColor; self.myButton.layer.borderWidth = 3; [self.myButton addTarget:self action:@selector(moveAction:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:self.myButton]; self.isAtTop = YES; } return self; } + (BOOL)requiresConstraintBasedLayout { return YES; } - (void)updateConstraints { [self.myButton mas_remakeConstraints:^(MASConstraintMaker *make) { make.width.equalTo(@(100)); make.height.equalTo(@(100)); if (self.isAtTop) { make.left.equalTo(self.mas_left).offset(10); make.top.equalTo(self.mas_top).offset(10); }else { make.bottom.equalTo(self.mas_bottom).offset(-10); make.right.equalTo(self.mas_right).offset(-10); } }]; [super updateConstraints]; } - (void)moveAction:(UIButton *)myButton { self.isAtTop = !self.isAtTop; //告诉约束他们须要更新 [self setNeedsUpdateConstraints]; //马上更新视图约束 [self updateConstraintsIfNeeded]; [UIView animateWithDuration:0.3 animations:^{ [self layoutIfNeeded]; }]; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end
这里主要使用了mas_remakeConstraints:方法。
场景4、两个视图的嵌套
实现代码:
// // NestConstraintsView.m // MasonryDemo // // Created by zhanggui on 15/10/26. // Copyright © 2015年 zhanggui. All rights reserved. // #import "NestConstraintsView.h" #import "Masonry.h" @implementation NestConstraintsView - (id)init { self = [super init]; if (self) { UIView *bigView = [[UIView alloc] init]; bigView.backgroundColor = [UIColor blackColor]; [self addSubview:bigView]; UIView *smallView = [[UIView alloc] init]; smallView.backgroundColor = [UIColor redColor]; [self addSubview:smallView]; [bigView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self).offset(20); make.left.equalTo(self).offset(20); make.bottom.equalTo(self).offset(-20); make.right.equalTo(self).offset(-20); }]; [smallView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(bigView.mas_top).offset(40); make.left.equalTo(bigView.mas_left).offset(40); make.bottom.equalTo(bigView.mas_bottom).offset(-40); make.right.equalTo(bigView.mas_right).offset(-40); }]; } return self; } @end
这里和第一个场景同样,都是最基本的实现约束的添加,只不过相对参照物不一样。
场景5、多个view一块儿布局(以组为单位布局)
效果:
实现代码:
// // GroupButtonView.m // MasonryDemo // // Created by zhanggui on 15/10/26. // Copyright © 2015年 zhanggui. All rights reserved. // #import "GroupButtonView.h" #import "Masonry.h" @implementation GroupButtonView - (instancetype)init { self = [super init]; if (self) { NSArray *strArr = @[@"10",@"20",@"50",@"100",@"200",@"300"]; NSMutableArray *mutableArr = [[NSMutableArray alloc] initWithCapacity:6]; for (int i=0; i<3; i++) { UIButton *button = [[UIButton alloc] init]; [button setTitle:strArr[i] forState:UIControlStateNormal]; [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; button.layer.borderColor = [UIColor blackColor].CGColor; [button addTarget:self action:@selector(show:) forControlEvents:UIControlEventTouchUpInside]; button.layer.borderWidth = 2; [self addSubview:button]; [mutableArr addObject:button]; } [mutableArr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:20 tailSpacing:20]; [mutableArr mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(@120); make.height.equalTo(@75); }]; /** * ----------------------- */ NSMutableArray *marr = [NSMutableArray new]; for (int i=3; i<6; i++) { UIButton *button = [[UIButton alloc] init]; [button setTitle:strArr[i] forState:UIControlStateNormal]; [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; button.layer.borderColor = [UIColor blackColor].CGColor; [button addTarget:self action:@selector(show:) forControlEvents:UIControlEventTouchUpInside]; button.layer.borderWidth = 2; [self addSubview:button]; [marr addObject:button]; } [marr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:20 tailSpacing:20]; [marr mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(@200); make.height.equalTo(@75); }]; } return self; } - (void)show:(UIButton *)button { NSLog(@"%@",button.titleLabel.text); } @end
在这里,咱们主要就是用到了mas_distributeViewsAlongAxis:...这个方法,来万曾一组视图的布局。
场景6、本身写的一个简单的登陆界面
效果以下:
代码以下:
// // ViewController.m // MasonryDemo // // Created by zhanggui on 15/10/8. // Copyright © 2015年 zhanggui. All rights reserved. // #import "ViewController.h" #import "Masonry.h" #import "ZGBasicView.h" #import "UpdateConstraintsView.h" #import "ReBackConstraintsView.h" #import "NestConstraintsView.h" #import "GroupButtonView.h" #import "LoginView.h" #import "ArrayView.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"登陆"; [self loginView]; // [self addArrayView]; } - (void)loginView { LoginView *loginView = [[LoginView alloc] init]; self.view = loginView; // loginView.frame = self.view.frame; // [self.view addSubview:loginView]; } - (void)addArrayView { ArrayView *arrView = [[ArrayView alloc] init]; self.view = arrView; } - (void)groupButtonView { GroupButtonView *nestView = [[GroupButtonView alloc] init]; nestView.frame = self.view.frame; // self.view = nestView; [self.view addSubview:nestView]; } - (void)nestConstraintsView { NestConstraintsView *nestView = [[NestConstraintsView alloc] init]; self.view = nestView; } - (void)reBackConstraints { ReBackConstraintsView *rebackView = [[ReBackConstraintsView alloc] init]; self.view = rebackView; } - (void)updateConstraintsView { UpdateConstraintsView *updateView = [[UpdateConstraintsView alloc] init]; self.view = updateView; } - (void)simpleView { ZGBasicView *basicView = [[ZGBasicView alloc] init]; // [self.view addSubview:basicView]; self.view = basicView; } - (void)firstSimpleView { UIView *superview = self.view; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1]; UIEdgeInsets padding = UIEdgeInsetsMake(74, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(superview).with.insets(padding); }]; // [view1 mas_makeConstraints:^(MASConstraintMaker *make) { // make.top.equalTo(superview.mas_top).offset(padding.top); // make.left.equalTo(superview.mas_left).offset(padding.left); // make.bottom.equalTo(superview.mas_bottom).offset(-padding.bottom); // make.right.equalTo(superview.mas_right).offset(-padding.right); // }]; } @end
你们能够简单的看一下,写的比较简单,应该很容易理解的。(横屏的距离上边的高度没有处理太好,将就着看吧)
简单就介绍这么多了。
附:
一、源码下载地址:http://pan.baidu.com/s/1o6083G2
二、Masonry Git地址:https://github.com/SnapKit/Masonry