Masonry 与 frame 混用可能出现子控件大小跟预期不一致的情况,具体是什么样呢?
例如,自定义一个 UIView 的子类SmallView,SmallView 中含有一个 UIImageView,在控制器创建SmallView,在SmallView创建UIImageView时都使用 init 方法,都没有给定 frame,但是在使用 masonry 约束时,用到了 frame,那么这就很可能会出现问题,导致大小跟预期不一致。
一.
在 SmallView 中创建 UIImageView
_imageView = [[UIImageView alloc] init];
_imageView.image = [UIImage imageNamed:@"一无所有"];
[self addSubview:_imageView];
//1.
//这种写法容易出问题,如果 SmallView 创建时没有设置 frame 或者重新约束,那么_imageView并不能达到预期的效果
//SmallView init 会先执行这里,然后在约束SmallView,但是 imageview 的大小已经在这里定型了
[_imageView mas_makeConstraints:^(MASConstraintMaker *make) {
//问题就在self.bounds.size.width,self.bounds.size.height,如果外面创建SmallView时,没有 frame, 这里就是0了
make.size.mas_equalTo(CGSizeMake(self.bounds.size.width, self.bounds.size.height));
make.center.mas_equalTo(self);
}];
在控制器中创建 SmallView
//1.没有给定 frame,此时 SmallView的imageView 已经大小为0了
SmallView *small = [[SmallView alloc] init];
[self.view addSubview:small];
//约束和 frame 不一致,SmallView的imageView 已经大小为0了,只对SmallView起效果了
[small mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(100, 100));
make.top.mas_equalTo(self.view).mas_offset(30);
make.leading.mas_equalTo(self.view).mas_offset(30);
}];
结果是这样,没有大小,不是与 SmallView 一样大
那就给一个 frame
SmallView *small = [[SmallView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
图片大小为 init 时的50,50
那么正确的姿势来了。
二.
在 SmallView 中创建 UIImageView
//2.
//这种写法无论 SmallView在创建时有没有给定 frame 或者给了 frame 但是约束跟 frame 不一致也不会出问题.
[_imageView mas_makeConstraints:^(MASConstraintMaker *make) {
//这里是约束,并不是 frame
//make.size.mas_equalTo(self);
make.width.mas_equalTo(self.mas_width);
make.height.mas_equalTo(self.mas_height);
make.center.mas_equalTo(self);
}];
在控制器中创建 SmallView
//2.frame 和约束不一致,使用的是约束,无所谓啦
//SmallView *small = [[SmallView alloc] init];
SmallView *small = [[SmallView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[self.view addSubview:small];
//约束和 frame 不一致,使用的是约束,无所谓啦
[small mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(100, 100));
make.top.mas_equalTo(self.view).mas_offset(30);
make.leading.mas_equalTo(self.view).mas_offset(30);
}];
那么,结论就是在自定义控件时,内部约束尽量使用mas_width这种属性,谨慎使用具体数值,如固定的 width 等等。如果你使用了 UIView 的快速改变 frame 的分类一定要注意,很多属性名类似,如 centerX 与mas_centerX可是不一样的,后果你遇到就知道啦~
代码https://github.com/lxszl/UIViewTest