首页 Masonry
文章
取消

Masonry

用过Autolayout都知道,用代码实现约束是多么麻烦的一件事,虽然有VFL可视化语言在一定程度上减少了代码量,但是代码看起来有点别扭。后来发现这货:Masonry

Masonry有很多简便的写法,比如

设置高度

1
2
3
4
5
	[self.indicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
       make.height.equalTo(self.view);
       //全写
       make.height.equalTo(self.view.mas_height);
    }];

左对其

1
2
3
4
5
	[self.indicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
       make.leading.equalTo(self.view);
       //全写
       make.height.equalTo(self.view.mas_leading);
    }];

向上的约束

1
2
3
4
5
	[self.indicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
       make.top.equalTo(self.view);
       //全写
       make.height.equalTo(self.view.mas_top);
    }];

x轴中心对其

1
2
3
4
5
	[self.indicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
       make.top.equalTo(self.view);
       //全写
       make.height.equalTo(self.mas_centerX);
    }];

具体例子

例子中用的都是简写的方式

倍数约束multipliedBy

1
2
3
4
5
6
    [self.indicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view);
        make.height.equalTo(self.view);
        make.top.equalTo(self.view);
        make.width.equalTo(self.view).multipliedBy(0.5);
    }];

self.indicatorView宽度是self.view的0.5倍

对齐

1
2
3
4
5
6
7
8
    [self.passwordView mas_updateConstraints:^(MASConstraintMaker *make) {
    	//左对齐
        make.leading.equalTo(self.passwordField);
        //右对齐
        make.trailing.equalTo(self.passwordField);
        make.top.equalTo(self.passwordField.mas_bottom).offset(10);
        make.height.equalTo(@10);
    }];

passwordViewpasswordField左右对其

适配iOS 6和iOS 7

1
2
3
4
5
6
7
8
9
10
11
12
	[self.passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.equalTo(@20);
        make.trailing.equalTo(@-20);
        if (IOS7) {
            UIView *topLayoutGuide = (id)self.topLayoutGuide;
            make.top.equalTo(topLayoutGuide.mas_bottom).with.offset(20);
        }
        else{
            make.top.equalTo(self.view.mas_top).with.offset(20);
        }
        make.height.equalTo(@36.0f);
    }];

self.topLayoutGuideUIView子类,所以可以和这个子类进行相对布局

x轴中心对其

1
2
3
4
5
6
7
8
9
10
11
	self.nextButton = [[UIButton alloc] init];
    self.nextButton.backgroundColor = [UIColor blackColor];
    [self.view addSubview:_nextButton];

    [self.nextButton mas_makeConstraints:^(MASConstraintMaker *make) {
        //x轴中心对其
        make.centerX.equalTo(self.view);

        make.top.equalTo(self.mas_bottom).with.offset(200);
        make.width.equalTo(@100);
    }];

self.nextButton和其父视图x轴对其

和父视图一样大小

1
2
3
4
	UIEdgeInsets ed = UIEdgeInsetsMake(0, 0, 0, 0);
    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view).with.insets(ed);
    }];

甚至可以这么用

1
2
3
 [self.scrollView makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];

UIScrollView布局

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
- (void)viewDidLoad
{
 		self.scrollView = UIScrollView.new;
    self.scrollView.backgroundColor = [UIColor yellowColor];
    self.scrollView.pagingEnabled = YES;
    [self.view addSubview:_scrollView];
    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];

    UIView *view1 = [[UIView alloc] init];
    view1.backgroundColor = [UIColor grayColor];
    [self.scrollView addSubview:view1];

    [view1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(@0);
        make.bottom.equalTo(@0);
        make.width.equalTo(@(self.view.frame.size.width));
        make.top.equalTo(@0);
    }];

    UIView *view2 = [[UIView alloc] init];
    view2.backgroundColor = [UIColor cyanColor];
    [self.scrollView addSubview:view2];

    [view2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(view1.mas_right);
        make.bottom.equalTo(@0);
        make.width.equalTo(@(self.view.frame.size.width));
        make.top.equalTo(@0);
        make.right.equalTo(@0);
    }];
}

顺便说一下对于UIScrollView应该怎么布局:上面的代码中相比view1的布局,view2多了一个对视图右侧的约束,对于一般的布局来说,这个约束其实是多余,因为前四个约束已经明确了view2frame。但是在UIScrollView中必须考虑contentSize,也就是说内部的子视图的加入必须确定UIScrollView的滚动范围,想象一下如果没有这个约束,把这两个视图加入中UIScrollView中,对于UIScrollView其实可以随意把contentSize调到self.view.frame.size.width * 2以上的任意宽度,这样也可以容纳这两个视图,所以说这样还不至于约束整个UIScrollView

那么在约束UIScrollView的时候,如果希望横向滚动,就必须在UIScrollView的左右侧有约束。同样的,对于竖向滚动就必须在UIScrollView的上下侧有约束。

跟踪约束

1
@property (nonatomic, strong) MASConstraint *top;
1
2
3
4
5
6
[self.button mas_makeConstraints:^(MASConstraintMaker *make) {
		make.leading.equalTo(@0);
		make.trailing.equalTo(@0);
		self.top = make.top.equalTo(@80);
		make.height.equalTo(@50);
}];

修改约束,执行动画

1
2
3
4
self.top.mas_equalTo(@100);
[UIView animateWithDuration:0.3 delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{
		[self.view.superview layoutIfNeeded];
}completion:NULL];

取消跟踪

1
[self.top uninstall];

快速设置宽高

1
2
3
[self.topView mas_makeConstraints:^(MASConstraintMaker *make) {
		 make.size.mas_equalTo(self.view.frame.size);
}];

甚至可以

1
2
3
[self.topView mas_makeConstraints:^(MASConstraintMaker *make) {
       make.size.mas_equalTo(self.view);
}];

混合

1
2
3
4
5
[self.view.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *obj, NSUInteger idx, BOOL *stop) {
			if (obj.firstItem == _otherView && obj.secondItem == _IDNumberFiled && obj.constant == 29.0f) {
					[self.view removeConstraint:obj];
			}
}];

删除IB中的约束,添加MASConstraint约束

1
2
3
[self.otherView mas_updateConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(_IDNumberFiled.mas_bottom).offset(60.0f);
}];

这样就比较容易更新约束并实现动画

1
2
3
4
5
6
[self.otherView mas_updateConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(_IDNumberFiled.mas_bottom).offset(100.0f);
}];
[UIView animateWithDuration:0.3 delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{
    [self.view layoutIfNeeded];
}completion:NULL];

最后

关于NSLayoutAttributeLeading NSLayoutAttributeTrailingNSLayoutAttributeLeft NSLayoutAttributeRight的区别:leading/trailing在某些从右至左习惯的地区(希伯来语等)会变成, leading是右边,trailing是左边,而left/right永远代表的是左右侧。还有,看下面两种写法

1
2
3
4
5
6
7
[self.otherView mas_updateConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(self.view.contentView);
}];
// 或
[self.otherView mas_updateConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(@0.0f);
}];

个人建议使用第二种,因为第一种写法很容易写错父视图,比如otherView是self.view.contentView的子视图,但是可有可能就写成self.view,这时候 Masonry 又是不会给出任何警告。

本文由作者按照 CC BY 4.0 进行授权

为类关联对象

UIStatusBarStyle