Masonry——简化自动布局代码框架

注:以下内容来源于官方源码、 README 文档、测试 Demo或个人使用总结 !

Masonry 是一个轻量级的布局框架,拥有自己的描述语法,采用优雅的链式语法来封装自动布局,简洁明了并具有高可读性。

Masonry 利用简化、可链接和表达式的语法发挥 Auto LayoutNSLayoutConstraints 的力量。支持 iOS 和 Mac OS 系统的自动布局 。

总的来说,就是当你在 Interface Bulider 上使用 Auto Layout 的时候是非常方便的。但是,当我们的视图通过手写代码生成时,或是UI界面需要随用户交互而更改,这时候使用原生的 NSLayoutConstraints 类实现自动布局及其繁琐,Masonry 用简洁的语法对 Auto Layout 进行了封装,使用相对更方便。

NSLayoutConstraints 的问题

添加一个子视图,跟随父视图的大小变化,但是与父视图边距有10个点的距离:


使用 NSLayoutConstraints

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIView *superview = self.view;
    UIView *view1 = [[UIView alloc] init];
    // 设置为NO,表示通过添加自己的约束以使用 Auto Layout 定位视图
    view1.translatesAutoresizingMaskIntoConstraints = NO;
    view1.backgroundColor = [UIColor greenColor];
    [superview addSubview:view1];
    
    // 指定每个边缘的插入量(正),值可以是负的到“起点”
    UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
    
    [superview addConstraints:@[
                                
        // view1 constraints
        // view1.attribute1 = multiplier × superview.attribute2 + constant
        // view1的顶部距离父视图的顶部10px
        [NSLayoutConstraint constraintWithItem:view1
                                     attribute:NSLayoutAttributeTop
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:superview
                                     attribute:NSLayoutAttributeTop
                                    multiplier:1.0
                                      constant:padding.top],
        // 左边距离10px
        [NSLayoutConstraint constraintWithItem:view1
                                     attribute:NSLayoutAttributeLeft
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:superview
                                     attribute:NSLayoutAttributeLeft
                                    multiplier:1.0
                                      constant:padding.left],
        // 底部距离10px
        [NSLayoutConstraint constraintWithItem:view1
                                     attribute:NSLayoutAttributeBottom
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:superview
                                     attribute:NSLayoutAttributeBottom
                                    multiplier:1.0
                                      constant:-padding.bottom],
        // 右边距离10px
        [NSLayoutConstraint constraintWithItem:view1
                                     attribute:NSLayoutAttributeRight
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:superview
                                     attribute:NSLayoutAttributeRight
                                    multiplier:1
                                      constant:-padding.right],
        ]];
}

使用 Masonry

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(superview.mas_top).with.offset(padding.top);
    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);
}];

更短的写法

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(padding);
}];

Masonry 实践

下面参考Masonry介绍与使用实践(快速上手Autolayout) @里脊串的开发随笔,练习使用Masonry。

1. 居中显示一个 300*300 的 superview

UIView *superview = [UIView new];
[superview showPlaceHolder];    // 需要导入MMPlaceHolder框架
superview.backgroundColor = [UIColor blackColor];
[self.view addSubview:superview];

[superview mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    make.size.mas_equalTo(CGSizeMake(300, 300));
}];

2. 让 superview1 略小于其 superview (边距为20)

UIView *superview1 =[UIView new];
superview1.backgroundColor = [UIColor redColor];
[superview addSubview:superview1];
[superview1 mas_makeConstraints:^(MASConstraintMaker *make) {
    // 写法一
   make.edges.equalTo(superview).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));

    /** 写法二
    make.top.equalTo(superview).with.offset(20);
    make.left.equalTo(superview).with.offset(20);
    make.bottom.equalTo(superview).with.offset(-20);
    make.right.equalTo(superview).with.offset(-20);
    **/

    /** 写法三
     make.top.left.bottom.and.right.equalTo(superview).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
    **/
}];

3. 让两个高度为 150 的视图垂直居中、等宽、等间隔排列 (间隔为10 ),自动计算其宽度

UIView *superview2 =[UIView new];
superview2.backgroundColor = [UIColor orangeColor];
[superview addSubview:superview2];

UIView *superview3 =[UIView new];
superview3.backgroundColor = [UIColor orangeColor];
[superview addSubview:superview3];

int padding1 = 10;
[superview2 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerY.mas_equalTo(superview.mas_centerY);
    make.left.equalTo(superview.mas_left).with.offset(padding1);
    make.right.equalTo(superview3.mas_left).with.offset(-padding1);
    make.height.mas_equalTo(@150);
    make.width.equalTo(superview3);
}];

[superview3 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerY.mas_equalTo(superview.mas_centerY);
    make.left.equalTo(superview2.mas_right).with.offset(padding1);
    make.right.equalTo(superview.mas_right).with.offset(-padding1);
    make.height.mas_equalTo(@150);
    make.width.equalTo(superview2);
}];

4. 在UIScrollView 上顺序排列一些view并自动计算contentSize

UIScrollView *scrollView = [UIScrollView new];
scrollView.backgroundColor = [UIColor whiteColor];
[superview addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(UIEdgeInsetsMake(5, 5, 5, 5));
}];

UIView *container = [UIView new];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    make.width.equalTo(scrollView);
}];

int count = 10;
UIView *lastView = nil;

for (int i = 1;  i <= count; i++) {
    UIView *subView = [UIView new];
    [container addSubview:subView];
    subView.backgroundColor = [UIColor colorWithHue:(arc4random() % 256 / 256.0)
                                         saturation:(arc4random() % 128 / 256.0) + 0.5
                                         brightness:(arc4random() % 128 / 256.0) + 0.5
                                              alpha:1];

    [subView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(container);
        make.height.mas_equalTo(@(20 * i)); // 每个子视图的高度是20的倍数

        if (lastView) {
            // 下一个子视图的顶部 = 上一个子视图的底部
            make.top.mas_equalTo(lastView.mas_bottom);
        }else {
            // 第一次执行,lastView = nil,因此第一个子视图的顶部是容器的顶部
            make.top.mas_equalTo(container.mas_top);
        }
    }];
    lastView = subView;
}
[container mas_makeConstraints:^(MASConstraintMaker *make) {
    // 容器的底部是最后一个视图的底部
    make.bottom.equalTo(lastView.mas_bottom);
}];

5. 横向或者纵向等间隙的排列一组view

11/15 添加
均匀分布一组view推荐使用 NSArray+MASAdditions.h 类中的两个方法:

/**
 *  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;

需要使用封装的 category 类:

  • UIView+LJC.h
#import <UIKit/UIKit.h>

/**
 横向或者纵向等间隙的排列一组view
 */
@interface UIView (LJC)

- (void) distributeSpacingHorizontallyWith:(NSArray*)views;

- (void) distributeSpacingVerticallyWith:(NSArray*)views;

@end
  • UIView+LJC.m
#import "UIView+LJC.h"
#import <Masonry/Masonry.h>


@implementation UIView (LJC)


/**
 横向排列一组view

 @param views view数组
 */
- (void) distributeSpacingHorizontallyWith:(NSArray*)views
{
    NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
    
    for ( int i = 0 ; i < views.count+1 ; ++i )
    {
        UIView *v = [UIView new];
        [spaces addObject:v];
        [self addSubview:v];
        
        [v mas_makeConstraints:^(MASConstraintMaker *make) {
            make.width.equalTo(v.mas_height);
        }];
    }
    
    UIView *v0 = spaces[0];
    
    [v0 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mas_left);
        make.centerY.equalTo(((UIView*)views[0]).mas_centerY);
    }];
    
    UIView *lastSpace = v0;
    for ( int i = 0 ; i < views.count; ++i )
    {
        UIView *obj = views[i];
        UIView *space = spaces[i+1];
        
        [obj mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(lastSpace.mas_right);
        }];
        
        [space mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(obj.mas_right);
            make.centerY.equalTo(obj.mas_centerY);
            make.width.equalTo(v0);
        }];
        
        lastSpace = space;
    }
    
    [lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.equalTo(self.mas_right);
    }];
    
}


/**
 垂直排列一组view

 @param views view数组
 */
- (void) distributeSpacingVerticallyWith:(NSArray*)views
{
    NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
    
    for ( int i = 0 ; i < views.count+1 ; ++i )
    {
        UIView *v = [UIView new];
        [spaces addObject:v];
        [self addSubview:v];
        
        [v mas_makeConstraints:^(MASConstraintMaker *make) {
            make.width.equalTo(v.mas_height);
        }];
    }
    
    
    UIView *v0 = spaces[0];
    
    [v0 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.mas_top);
        make.centerX.equalTo(((UIView*)views[0]).mas_centerX);
    }];
    
    UIView *lastSpace = v0;
    for ( int i = 0 ; i < views.count; ++i )
    {
        UIView *obj = views[i];
        UIView *space = spaces[i+1];
        
        [obj mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(lastSpace.mas_bottom);
        }];
        
        [space mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(obj.mas_bottom);
            make.centerX.equalTo(obj.mas_centerX);
            make.height.equalTo(v0);
        }];
        
        lastSpace = space;
    }
    
    [lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.mas_bottom);
    }];
    
}

@end
  • 实例测试:
UIView *subView11 = [UIView new];
UIView *subView12 = [UIView new];
UIView *subView13 = [UIView new];
UIView *subView21 = [UIView new];
UIView *subView31 = [UIView new];

subView11.backgroundColor = [UIColor redColor];
subView12.backgroundColor = [UIColor redColor];
subView13.backgroundColor = [UIColor redColor];
subView21.backgroundColor = [UIColor redColor];
subView31.backgroundColor = [UIColor redColor];

[superview addSubview:subView11];
[superview addSubview:subView12];
[superview addSubview:subView13];
[superview addSubview:subView21];
[superview addSubview:subView31];

//给予不同的大小,测试结果

[subView11 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerY.equalTo(@[subView12,subView13]); // 11、12、13 Y方向对齐
    make.centerX.equalTo(@[subView21,subView31]); // 11、21、31 X方向对齐
    make.size.mas_equalTo(CGSizeMake(40, 40));
}];

[subView12 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(30, 30));
}];

[subView13 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(20, 20));
}];

[subView21 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(50, 50));
}];

[subView31 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(60, 60));
}];

[superview distributeSpacingHorizontallyWith:@[subView11,subView12,subView13]];
[superview distributeSpacingVerticallyWith:@[subView11,subView21,subView31]];

[superview showPlaceHolderWithAllSubviews];
[superview hidePlaceHolder];

使用空白的占位view填充目标view的旁边

继续参考:Masonry使用总结,学习使用 Masonry;

6. Masonry 中的比例 multipliedBy

使用 multipliedBy 属性必须是对同一个控件本身,如果修改成相对于其它控件会导致 Crash。

UIView *topView = [UIView new];
[topView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:topView];

UIView *topInnerView = [UIView new];
[topInnerView setBackgroundColor:[UIColor greenColor]];
[topInnerView showPlaceHolder];
[self.view addSubview:topInnerView];

UIView *bottomView =[UIView new];
[bottomView setBackgroundColor:[UIColor blueColor]];
[self.view addSubview:bottomView];

UIView *bottomInnerView =[UIView new];
[bottomInnerView setBackgroundColor:[UIColor blackColor]];
[bottomInnerView showPlaceHolder];
[self.view addSubview:bottomInnerView];

[topView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.left.and.right.mas_equalTo(0);
    make.height.mas_equalTo(bottomView);
}];

[topInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.and.right.mas_equalTo(0);
    make.width.mas_equalTo(topInnerView.mas_height).multipliedBy(3);
    make.center.mas_equalTo(topView);
}];

[bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.bottom.and.right.mas_equalTo(0);
    make.height.mas_equalTo(topView);
    make.top.mas_equalTo(topView.mas_bottom);
}];

[bottomInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.and.bottom.mas_equalTo(bottomView);
    make.height.mas_equalTo(bottomInnerView.mas_width).multipliedBy(3);
    make.center.mas_equalTo(bottomView);
}];

7. 使用 priority 优先级属性来做简单的动画

.priority allows you to specify an exact priority

.priorityHigh equivalent to UILayoutPriorityDefaultHigh

.priorityMedium is half way between high and low

.priorityLow equivalent to UILayoutPriorityDefaultLow

  1. 先为blueView设置属性:
@interface ViewController ()

@property (nonatomic,strong) UIView *blueView;

@end

2.创建视图并设置约束:

// 红色视图
UIView *redView = [UIView new];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];

// 蓝色视图
self.blueView = [UIView new];
self.blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:self.blueView];

// 黄色视图
UIView *yellowView = [UIView new];
yellowView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:yellowView];

// ————红色视图约束————
[redView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.mas_equalTo(self.view.mas_left).with.offset(20);
    make.bottom.mas_equalTo(self.view.mas_bottom).with.offset(-80);
    make.height.mas_equalTo(50);
}];

// ————蓝色视图约束————
[self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.mas_equalTo(redView.mas_right).with.offset(40);
    make.bottom.width.and.height.with.height.mas_equalTo(redView);
}];

// ————黄色视图约束————
[yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
    // 默认满足高优先级约束
    make.left.mas_equalTo(self.blueView.mas_right).with.offset(40);
    make.right.mas_equalTo(self.view.mas_right).with.offset(-20);
    make.bottom.width.and.height.mas_equalTo(redView);

    //** priority设置为250,最高1000(默认)**
    make.left.mas_equalTo(redView.mas_right).with.offset(20).priority(250);
}];

3.点击屏幕移除蓝色视图方法:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.blueView removeFromSuperview];
    [UIView animateWithDuration:1.0 animations:^{
        [self.view layoutIfNeeded];
    }];
}

注释:黄色视图的left属性分别设置了两个约束,一个相对于蓝色视图的高优先级约束:make.left.mas_equalTo(self.blueView.mas_right).with.offset(40);

另一个相对于红色视图的低优先级约束:make.left.mas_equalTo(redView.mas_right).with.offset(20).priority(250);

当蓝色视图存在时,两个约束同时存在,为避免约束冲突,系统默认满足高优先级的约束;

当点击屏幕,蓝色视图被移除后,低优先级的约束就会生效。

8.Masonry更新约束方法:mas_updateConstraints

如果你只想更新约束的常量值,则可以使用更方便的方法:mas_updateConstraints而不是mas_makeConstraints

  1. 创建一个 Button 属性、scale 属性用于记录放大比例:

    @interface ViewController ()
    @property (nonatomic,strong) UIButton *growingButton;
    @property (nonatomic,assign) CGFloat scale;
    @end
    
  1. 创建 Button 实例:

    self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.growingButton setTitle:@"点我放大" forState:UIControlStateNormal];
    self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;
    self.growingButton.layer.borderWidth = 3;
    [self.growingButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.growingButton];
    self.scale = 1.0;
    
    [self.growingButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(self.view);
        // 初始宽、高为100,优先级最低
        make.width.height.mas_equalTo(100 * self.scale);
        // 最大放大到整个view
        make.width.and.height.lessThanOrEqualTo(self.view);
    }]
    
  2. 点击 Button 方法:

    - (void)onGrowButtonTaped:(UIButton *)sender {
        self.scale += 1.0;
        
        //告诉self.view约束需要更新
        [self.view setNeedsUpdateConstraints];
        
        //调用此方法告诉self.view检测是否需要更新约束,若需要则更新。下面添加的动画效果才起作用
        [self.view updateConstraintsIfNeeded];
        
        [UIView animateWithDuration:0.3 animations:^{
            [self.view layoutIfNeeded];
        }];
    }
    
  3. 更新约束:

    // 这是Apple推荐的添加/更新约束的地方
    // 此方法可以被多次调用,以响应 setNeedsUpdateConstraints
    // 如果您需要触发对约束的更新,可以在UIKit内部或你的代码中调用该方法
    - (void)updateViewConstraints {
        [self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
            //这里写需要更新的约束,不用更新的约束将继续存在,并不会被取代
            make.width.and.height.mas_equalTo(100*self.scale);
        }];
         // //根据Apple要求,super方法应该在方法结束时调用
        [super updateViewConstraints];
    }
    

代码执行顺序:

-[ViewController viewDidLoad]

-[ViewController createGrowingButton]

mas_makeConstraints

-[ViewController updateViewConstraints]

mas_updateConstraints

点击按钮

-[ViewController onGrowButtonTaped:]

-[ViewController updateViewConstraints]

mas_updateConstraints

点击按钮

-[ViewController onGrowButtonTaped:]

-[ViewController updateViewConstraints]

mas_updateConstraints

更新约束和布局的相关方法
  • 关于 UIView 重新布局相关的 API,主要有以下三个:
// 标记为需要在下一个周期重新布局
- (void)setNeedsLayout;

// 查看当前视图是否被标记需要重新布局,有则在内部调用layoutSubviews方法立即进行重新布局
- (void)layoutIfNeeded;

// 重写当前方法,在内部完成重新布局操作,不要直接调用,如果需要强制更新布局,调用 setNeedsLayout()
- (void)layoutSubviews;
  • 关于更新约束布局相关的 API,主要有以下四个:
// 标记需要进行重新布局,系统会调用 updateConstraints()方法,修改多个约束后调用该方法批量更新有助于提升性能
- (void)setNeedsUpdateConstraints;

// 当前是否需要重新布局,内部会判断当前有没有被标记的约束
- (BOOL)needsUpdateConstraints;

// 调用此方法,如果有标记为需要重新布局的约束,则立即进行重新布局,内部会调用  updateConstraints方法
- (void)updateConstraintsIfNeeded;

// 重写此方法,内部实现自定义布局过程
- (void)updateConstraints;

9.Masonry的重写约束:mas_remakeConstraints

mas_updateConstraints is useful for updating a set of constraints, but doing anything beyond updating constant values can get exhausting. That's where mas_remakeConstraints comes in.

mas_remakeConstraints is similar to mas_updateConstraints, but instead of updating constant values, it will remove all of its constraints before installing them again. This lets you provide different constraints without having to keep around references to ones which you want to remove.

  1. 创建一个Button属性、isExpanded属性用于记录按钮状态:
@property (nonatomic,strong) UIButton *growingButton;
@property (nonatomic,assign) BOOL isExpanded;
  1. 创建Button实例:
self.isExpanded = NO;
self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.growingButton setTitle:@"点我展开" forState:UIControlStateNormal];
self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;
self.growingButton.layer.borderWidth = 3;
self.growingButton.backgroundColor = [UIColor redColor];
[self.growingButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_growingButton];

[self.growingButton mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.and.left.mas_equalTo(100);
    make.bottom.mas_equalTo(-350);
    make.right.mas_equalTo(-100);
}];
  1. 点击Button方法:
- (void)onGrowButtonTaped:(UIButton *)sender {
    self.isExpanded = !self.isExpanded;
    if (!self.isExpanded) {
        [self.growingButton setTitle:@"点我展开" forState:UIControlStateNormal];
    }else {
        [self.growingButton setTitle:@"点我收起" forState:UIControlStateNormal];
    }
    
    [self.view setNeedsUpdateConstraints];
    [self.view updateConstraintsIfNeeded];
    [UIView animateWithDuration:0.3 animations:^{
        [self.view layoutIfNeeded];
    }];
}
  1. 更新约束:
- (void)updateViewConstraints {
    NSLog(@"%s",__func__);
    // 这里使用update也能实现效果,而remark会将之前的约束全部移除,然后重新添加
    __weak typeof (self)weakself = self;
    [self.growingButton mas_remakeConstraints:^(MASConstraintMaker *make) {
        // 重写全部约束
        if (weakself.isExpanded) {
            make.top.and.left.mas_equalTo(0);
            make.bottom.mas_equalTo(10);
            make.right.mas_equalTo(0);
        }else {
            make.top.and.left.mas_equalTo(100);
            make.bottom.mas_equalTo(-350);
            make.right.mas_equalTo(-100);
        }
    }];
    [super updateViewConstraints];
}

实现结果:

其他

By default, macros which support autoboxing are prefixed with mas_. Unprefixed versions are available by defining MAS_SHORTHAND_GLOBALS before importing Masonry.

​ ——摘自Masonary:README.md

  • 为了增加代码的可读性这里有两个简化代码的宏:#define MAS_SHORTHAND#define MAS_SHORTHAND_GLOBALS
  • MAS_SHORTHAND:只要在导入Masonry主头文件之前定义这个宏, 那么以后在使用Masonry框架中的属性和方法的时候, 就可以省略mas_前缀

  • MAS_SHORTHAND_GLOBALS:只要在导入Masonry主头文件之前定义这个宏,那么就可以让equalTo函数接收基本数据类型, 内部会对基本数据类型进行包装

  • 注意:这两个宏如果想有效使用,必须要在添加Masonry头文件之前导入进去。在没有增加宏MAS_SHORTHAND_GLOBALS时,下面这句是会报错的。

  • make.top.equalTo(42); --> make.top.equalTo([NSNumber numberWithInt:42]);

    ​ ——摘自Masonry使用总结

注意:有时候写约束语法的时候 with 经常会不小心写成 width,就像这样:

make.bottom.mas_equalTo(self.view.mas_bottom).width.offset(-80);

于是会报这样的错误:

Attributes should be chained before defining the constraint relation.

属性应该在定义约束关系之前链接.

记得仔细查找这种错误并改正。

参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容