Masonry 中的坑
1. 在使用Masonry添加约束之前,需要在addSubview之后才能使用,否则会导致崩溃。
2. 在添加约束时初学者经常会出现一些错误,约束出现问题的原因一般就是两种:约束冲突和缺少约束。对于这两种问题,可以通过调试和log排查。
3. 之前使用Interface Builder添加约束,如果约束有错误直接就可以看出来,并且会以红色或者黄色警告体现出来。而Masonry则不会直观的体现出来,而是以运行过程中崩溃或者打印异常log体现,所以这也是手写代码进行AutoLayout的一个缺点。
一、Masonry 基础 API
mas_makeConstraints() 添加约束
mas_remakeConstraints() 移除之前的约束,重新添加新的约束
mas_updateConstraints() 更新约束
equalTo() 参数是对象类型,一般是视图对象或者 mas_width 这样的坐标系对象
mas_equalTo() 和上面功能相同,参数可以传递基础数据类型对象,可以理解为比上面的 API 更强大
width() 用来表示宽度,例如代表 view 的宽度
mas_width() 用来获取宽度的值。和上面的区别在于,一个代表某个坐标系对象,一个用来获取坐标系对象的值
二、equalTo或者width这样的,有时候需要涉及到使用mas_前缀,这在开发中需要注意作区分。
如果在当前类引入#import “Masonry.h”之前,用下面两种宏定义声明一下,就不需要区分mas_前缀。
// 定义这个常量,就可以不用在开发过程中使用"mas_"前缀。
define MAS_SHORTHAND
// 定义这个常量,就可以让 Masonry 帮我们自动把基础数据类型的数据,自动装箱为对象类型。
define MAS_SHORTHAND_GLOBALS
三、添加了and和with两个方法。这两个方法内部实际上什么都没干,只是在内部将self直接返回,功能就是为了更加方便阅读,对代码执行没有实际作用
make.top.and.bottom.equalTo(self.containerView).with.offset(padding);
内部代码实现,实际上就是直接将self返回
- (MASConstraint *)with {
return self;
}
四、更新约束(4个)和布局(3个)
- (void)updateConstraintsIfNeeded 调用此方法,如果有标记为需要重新布局的约束,则立即进行重新布局,内部会调用 updateConstraints 方法
- (void)updateConstraints 重写此方法,内部实现自定义布局过程
- (BOOL)needsUpdateConstraints 当前是否需要重新布局,内部会判断当前有没有被标记的约束
- (void)setNeedsUpdateConstraints 标记需要进行重新布局
- (void)setNeedsLayout 标记为需要重新布局
- (void)layoutIfNeeded 查看当前视图是否被标记需要重新布局,有则在内部调用 layoutSubviews 方法进行重新布局
- (void)layoutSubviews 重写当前方法,在内部完成重新布局操作
五、Masonry 本质上就是对系统 AutoLayout 进行的封装,包括里面很多的 API,都是对系统 API 进行了一次二次包装
typedef NS_OPTIONS(NSInteger, MASAttribute) {
MASAttributeLeft = 1 << NSLayoutAttributeLeft,
MASAttributeRight = 1 << NSLayoutAttributeRight,
MASAttributeTop = 1 << NSLayoutAttributeTop,
MASAttributeBottom = 1 << NSLayoutAttributeBottom,
MASAttributeLeading = 1 << NSLayoutAttributeLeading,
MASAttributeTrailing = 1 << NSLayoutAttributeTrailing,
MASAttributeWidth = 1 << NSLayoutAttributeWidth,
MASAttributeHeight = 1 << NSLayoutAttributeHeight,
MASAttributeCenterX = 1 << NSLayoutAttributeCenterX,
MASAttributeCenterY = 1 << NSLayoutAttributeCenterY,
MASAttributeBaseline = 1 << NSLayoutAttributeBaseline,
};
一、设置内边距
/**
设置 yellow 视图和 self.view 等大,并且有 10 的内边距。
注意根据 UIView 的坐标系,下面 right 和 bottom 进行了取反。所以不能写成下面这样,否则 right、bottom 这两个方向会出现问题。
make.edges.equalTo(self.view).with.offset(10);
除了下面例子中的 offset()方法,还有针对不同坐标系的 centerOffset()、sizeOffset()、valueOffset()之类的方法。
*/
[self.yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view).with.offset(10);
make.top.equalTo(self.view).with.offset(10);
make.right.equalTo(self.view).with.offset(-10);
make.bottom.equalTo(self.view).with.offset(-10);
}];
二、通过 insets 简化设置内边距的方式
//下面的方法和上面例子等价,区别在于使用 insets()方法。
[self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
// 下、右不需要写负号,insets 方法中已经为我们做了取反的操作了。
make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
}];
三、更新约束
// 设置 greenView 的 center 和 size,这样就可以达到简单进行约束的目的
[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
// 这里通过 mas_equalTo 给 size 设置了基础数据类型的参数,参数为 CGSize 的结构体
make.size.mas_equalTo(CGSizeMake(300, 300));
}];
// 为了更清楚的看出约束变化的效果,在显示两秒后更新约束。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.greenView mas_updateConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view).offset(100);
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
});