您的位置:首页 > 移动开发 > IOS开发

Masonry教程--IOS自适配,丢掉Autolayout吧

2016-04-14 11:32 1306 查看
文章来自http://www.brighttj.com/ios/ios-masonry-demo.html#comment-353

如果说自动布局解救了多屏幕适配,那众多三方库的出现就解救了系统自动布局的写法。Masonry就是其中一个。

在Github上,Masonry已经得到6000+个star,用法上也比较简单灵活,很大程度上替代了传统的NSLayoutConstraint布局方式。本文将利用几个案例来讲解Masonry的使用。

Masonry下载地址:


https://github.com/SnapKit/Masonry

本文Demo下载地址:


https://github.com/saitjr/MasonryDemo.git

环境信息:

Mac OS X 10.10.3

Xcode 6.3

iOS 8.3

正文:

前期准备:
1. 下载Masonry并导入到工程中;
2. 将Masonry.h导入当前控制器。

案例一:

要求:

无论在什么尺寸的设备上(包括横竖屏切换),红色view都居中显示。

案例一

实现:

#import "ViewController.h"
#import "Masonry.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];

// 防止block中的循环引用
__weak typeof(self) weakSelf = self;

// 初始化view并设置背景
UIView *view = [UIView new];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view];

// 一定要在 需要设置约束的视图添加到父视图上后再使用设置约束的方法
// 使用mas_makeConstraints添加约束
[view mas_makeConstraints:^(MASConstraintMaker *make) {
// 添加大小约束(make就是要添加约束的控件view)
make.size.mas_equalTo(CGSizeMake(100, 100));
// 添加居中约束(居中方式与self相同)
make.center.equalTo(weakSelf.view); }];
}
@end

案例二:

要求:

无论在什么尺寸的设备上(包括横竖屏切换),黑色view的左、上边距、大小都不变;
灰色view的右边距不变
宽、高、上边距黑色view相等

案例二

实现:

#import "ViewController2.h"
#import "Masonry.h"
@interface ViewController2 ()
@end
@implementation ViewController2
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *blackView = [UIView new];
blackView.backgroundColor = [UIColor blackColor];
[self.view addSubview:blackView];

// 给黑色view添加约束
[blackView mas_makeConstraints:^(MASConstraintMaker *make) {
// 添加大小约束

make.size.mas_equalTo(CGSizeMake(100, 100));

// 添加左、上边距约束(左、上约束都是20)
make.left.and.top.mas_equalTo(20); // 使用 mas_equalTo可以直接写数值,不需要用@()封装
}];
// 初始化灰色view UIView *grayView = [UIView new];
grayView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:grayView];

// 给灰色view添加约束
[grayView mas_makeConstraints:^(MASConstraintMaker *make) {
// 大小、上边距约束与黑色view相同
make.size.and.top.equalTo(blackView);
// 添加右边距约束
(这里的间距是有方向性的,左、上边距约束为正数,右、下边距约束为负数)
make.right.mas_equalTo(-20);
}];
}
@end

在上面的案例中,涉及以下内容:

在Masonry中,and,with都没有具体操作,仅仅是为了提高程序的可读性

make.left.and.top.mas_equalTo(20);

等价于

make.left.top.mas_equalTo(20);

equalTo与mas_equalTo

如果约束条件是数值或者结构体等类型,可以使用mas_equalTo进行包装。

关于这个问题,我也不是很清楚,可以看看官方的解释:

Instead of using NSNumber, you can use primitives and structs to build your constraints.By default,
macros which support autoboxing are prefixed with mas_.
Unprefixed versions are available by defining MAS_SHORTHAND_GLOBALS
before importing Masonry.

我一般将数值类型的约束用mas_equalTo,而相对于某个控件,或者某个控件的某个约束,我会使用equalTo,如:

make.size.mas_equalTo(CGSizeMake(100, 100));make.center.equalTo(weakSelf.view);

案例三:

要求:

有两个view,黑色与灰色;
黑色view的左、上、右边距均为20,下边距灰色view 20,宽度自适应,高度与灰色view平分整个界面;
灰色view宽度为黑色view的一半(即左边以中线起始),右、下边距与黑色view相同,高度与黑色view相同。

案例三

实现:

#import "ViewController3.h"
#import "Masonry.h"
@interface ViewController3 ()
@end
@implementation ViewController3
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *blackView = [UIView new];
blackView.backgroundColor = [UIColor blackColor];
[self.view addSubview:blackView];

// 给黑色view添加约束
[blackView mas_makeConstraints:^(MASConstraintMaker *make) {
// 添加左、上边距约束

make.left.and.top.mas_equalTo(20);
// 添加右边距约束
make.right.mas_equalTo(-20); }];

view UIView *grayView = [UIView new];
grayView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:grayView];

// 给灰色view添加约束
[grayView mas_makeConstraints:^(MASConstraintMaker *make) {
// 添加右、下边距约束

make.bottom.and.right.mas_equalTo(-20);
// 添加高度约束,让高度等于blackview
make.height.equalTo(blackView);
// 添加上边距约束(上边距 = 黑色view的下边框 + 偏移量20)
make.top.equalTo(blackView.mas_bottom).offset(20);
// 添加左边距(左边距 = 父容器纵轴中心 + 偏移量0)
make.left.equalTo(weakSelf.view.mas_centerX).offset(0); }];
}
@end

案例四:

要求


当键盘挡住输入框时,输入框自动向上弹到键盘上方。

实现


这里需要使用到Masonry的另外一个方法
mas_updateConstraints
。这个方法用于更新控件约束。

具体的实现方式可以下载Demo来看,这里只贴出键盘弹出时的处理代码:

- (void)keyboardWillChangeFrameNotification:(NSNotification *)notification

{
// 获取键盘基本信息(动画时长与键盘高度)
NSDictionary *userInfo = [notification userInfo];
CGRect rect =
[userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];

CGFloat keyboardHeight = CGRectGetHeight(rect);
CGFloat keyboardDuration =
[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];

// 修改下边距约束
[_textField mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(-keyboardHeight); }];

// 更新约束

[UIView animateWithDuration:keyboardDuration animations:^{
[self.view layoutIfNeeded]; }];
}

总结:

可以给控件添加left/right/top/bottom/size/height/width/insert约束;
库提供了三个方法,mas_makeConstraints添加约束,mas_updateConstraints修改约束,mas_remakeConstraints清除以前约束并添加新约束;
可以通过view.mas_bottom获得view的某个约束;
在约束的block中,使用make来给当前控件添加约束。


Masonry介绍与使用实践(快速上手Autolayout)
— 前言1MagicNumber -> autoresizingMask -> autolayout以上是纯手写代码所经历的关于页面布局的三个时期在iphone1-iphone3gs时代 window的size固定为(320,480) 我们只需要简单计算一下相对位置就好了在iphone4-iphone4s时代 苹果推出了retina屏 但是给了码农们非常大的福利:window的s
HYYadad184.com →


有趣的Autolayout示例-Masonry实现
— 前言好久没有写Blog了,这段时间有点忙啊=。=本文举了3个比较有“特点”的Autolayout例子,源于微博上好友的提问,感觉比较有意思,也比较有代表性,就写了出来,分享给大家~至于为什么用Masonry,那是因为它好用啊!(被问到过有关Masonry的问题,就索性用它来实现吧=。=)。效果图Github地址https://github.com/zekunyan/AutolayoutExam
HYYtutuge.me →

文/HYY(简书作者)

原文链接:http://www.jianshu.com/p/598225bb7ddc

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

文章地址: http://www.tuicool.com/articles/I73M3iQ


iOS常用第三方库之Masonry

另一篇截取:

场景二、更新视图

效果图如下:



实现代码如下:(这里也是自定义了一个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:方法

场景三、让约束复原



实现代码如下:
//
//  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:方法。

场景四、两个视图的嵌套



实现代码:
//
//  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


这里和第一个场景一样,都是最基本的实现约束的添加,只不过相对参照物不同。

场景五、多个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:...这个方法,来万曾一组视图的布局。

简单就介绍这么多了。

附:

1、源码下载地址: http://pan.baidu.com/s/1mgALZmC

2、Masonry Git地址: https://github.com/SnapKit/Masonry
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: