什么是 masonry
这是官方的一个说明:
Masonry is a light-weight layout framework which wraps AutoLayout with a nicer syntax. Masonry 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. Masonry supports iOS and Mac OS X.
它为 iOS 以及 Mac 的开发提供了一个轻量级的布局框架,用更好的代码语法封装了 AutoLayout。 用更简短代码来设置自己的 NSLaytouConstranits。
可以做什么
在以前的开发过程中,view 要显示在屏幕的哪个位置是用 NSLayoutConstraints 来约束的,用现在的眼光来看待 NSLayoutConstraints,它好处是可以让我们更详细的了解约束的方式以及各种参数的作用。随之带来的是代码兀余、开发效率低下的结果。
一个简单的例子:让一个子视图 view1 大小填满它的父视图 superview ,并且上下左右空出 10pt。用 NSLayoutConstraints 来描述这个需求的代码类似是这样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
UIView *superview = self.view; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1]; UIEdgeInsets padding = UIEdgeInsetsMake(10, 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], ]]; |
实现这样的需求,需要以上代码,而这例子仅仅是要包含一个子视图 view1 ,那如果在这时候插入两个以及更多的时候呢?代码量自然不言而喻。
来看看 masonry 是怎么描述的:
1 2 3 4 5 6 7 8 9 |
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler make.left.equalTo(superview.mas_left).with.offset(padding.left); make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom); make.right.equalTo(superview.mas_right).with.offset(-padding.right); }]; |
甚至还能有更短的:
1 2 3 4 |
[view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(superview).with.insets(padding); }]; |
类似这样:
是不是简单了很多?
使用方法
介绍了 masonry 以及它的作用之后,下面我们根据例子来试用一下,看看效果。
首先使用前: 用 CocoaPods 来安装,Podfile 中 增加 pod ‘Masonry’ ,然后在项目当前的文件下 #import “Masonry.h”,
如果之前有定义了 pch 文件可以直接在里面 #define MAS_SHORTHAND。这些是官方提供的安装方式。
开始使用,先看这么个需求(其实也是上面例子中的引申):让一个子视图 view1 的大小填满它的父视图 superview ,并且上下左右空出 10pt。在 view1 里面增加一个 view2 跟两个按钮,这两个按钮分别来控制 view2 的显示位置以及使用 masonry 的一些方法特性。
必须按照以下步骤来做,否则会抛出异常导致崩溃:
- 子 View 初始化;
- 子 View 包含在父 View 上addSubViews:;
- 然后再做约束。
!
贴出代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
// // ViewController.m // MasonryDemo // // Created by jele lam on 24/10/2017. // Copyright © 2017年 jele lam. All rights reserved. // #import "ViewController.h" #import "Masonry.h" @interface ViewController () @property (nonatomic, strong) UIView *view1; @property (nonatomic, strong) UIView *view2; @property (nonatomic, strong) UIButton *updateButton; @property (nonatomic, strong) UIButton *remakeButton; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 首先要加載並初始化控件 [self setupViews]; // 然後才使用 masonry 框架來約束各個控件 [self setupFrame]; } - (void)setupViews { [self.view1 addSubview:self.view2]; [self.view1 addSubview:self.updateButton]; [self.view1 addSubview:self.remakeButton]; [self.view addSubview:self.view1]; } - (void)setupFrame { [self.view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(20, 10, 10, 10)); }]; [self.view2 mas_makeConstraints:^(MASConstraintMaker *make) { // 讓黃色 view2 貼近黑色 view1 的頂部 make.top.equalTo(self.view1); // 讓黃色 view2 的水平中心點與黑色 view1 對齊 make.centerX.equalTo(self.view1); // 設定黃色 view2 的寬高 make.width.equalTo(@(50)); make.height.equalTo(@(50)); }]; [self.updateButton mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.view1); make.width.equalTo(@(100)); make.height.equalTo(@(60)); }]; [self.remakeButton mas_makeConstraints:^(MASConstraintMaker *make) { // 讓 remakeButton 的頂部與 updateButton 的底部對齊 // 換句話說,把 remakeButton 放在 updateButton 下面 make.top.equalTo(self.updateButton.mas_bottom); make.centerX.equalTo(self.updateButton); make.width.equalTo(@(100)); make.height.equalTo(@(60)); }]; [self.view updateConstraintsIfNeeded]; [self.view setNeedsUpdateConstraints]; } /* * mas_updateConstraints 修改或增加約束。 */ - (void)updateButtonPress { NSLog(@"你點擊了"); self.updateButton.selected = !self.updateButton.selected; if (self.updateButton.selected) { [self.view2 mas_updateConstraints:^(MASConstraintMaker *make) { make.width.equalTo(@(self.view1.frame.size.width)); }]; } else { [self.view2 mas_updateConstraints:^(MASConstraintMaker *make) { make.width.equalTo(@(50)); }]; } //加入以下代码可以让约束动起来~~ [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ [self.view layoutIfNeeded]; } completion:nil]; } /* * mas_remakeConstraints 丟棄之前設定的約束,以設置新的約束。 */ - (void)remakeButtonPress { self.remakeButton.selected = !self.remakeButton.selected; if (self.remakeButton.selected) { [self.view2 mas_remakeConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(self.view1); make.width.equalTo(@(50)); make.height.equalTo(@(50)); // 讓黃色 view2 貼近黑色 view1 右側 make.right.mas_equalTo(self.view1); }]; } else { [self.view2 mas_remakeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.view1); make.width.equalTo(@(50)); make.height.equalTo(@(50)); // 讓黃色 view2 貼近黑色 view1 左側 make.left.mas_equalTo(self.view1); }]; } self.updateButton.selected = NO; } #pragma mark lazyLoad - (UIView *)view1 { if (!_view1) { _view1 = [[UIView alloc] init]; _view1.backgroundColor = [UIColor blackColor]; } return _view1; } - (UIView *)view2 { if (!_view2) { _view2 = [[UIView alloc] init]; _view2.backgroundColor = [UIColor yellowColor]; } return _view2; } - (UIButton *)updateButton { if (!_updateButton) { _updateButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_updateButton setTitle:@"更新約束" forState:UIControlStateNormal]; [_updateButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [_updateButton setTitleColor:[UIColor orangeColor] forState:UIControlStateHighlighted]; [_updateButton.layer setMasksToBounds:YES]; [_updateButton.layer setBorderWidth:1.f]; [_updateButton.layer setBorderColor:[UIColor orangeColor].CGColor]; [_updateButton addTarget:self action:@selector(updateButtonPress) forControlEvents:UIControlEventTouchUpInside]; } return _updateButton; } - (UIButton *)remakeButton { if (!_remakeButton) { _remakeButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_remakeButton setTitle:@"重建約束" forState:UIControlStateNormal]; [_remakeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [_remakeButton setTitleColor:[UIColor orangeColor] forState:UIControlStateHighlighted]; [_remakeButton.layer setMasksToBounds:YES]; [_remakeButton.layer setBorderWidth:1.f]; [_remakeButton.layer setBorderColor:[UIColor orangeColor].CGColor]; [_remakeButton addTarget:self action:@selector(remakeButtonPress) forControlEvents:UIControlEventTouchUpInside]; } return _remakeButton; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end |
最后
谢谢大家
参考阅读: