怎么安装Masonry
和怎么makeConstraints
不多说, 我们假设你会...
cell的高度自适应
开发中常常需要UITableViewCell
高度自适应, 最最常见的, 就是UILabel
的多行文字显示, 我们都是让内部view
自适应来撑起父视图. 一般的view
自适应我们也是这么做的
子view撑起父view
比如, 我们在界面中间需要放一个contentView
, 居中, view
的内部呢, 我们假设有一个子view
-innerView
, 上下左右距离父视图均为20, 我们一般配合Masonry
, 可以这么写:
UIView *contentView = [[UIView alloc] init];
contentView.backgroundColor = [UIColor blueColor];
[self.view addSubview:contentView];
UIView *innerView = [[UIView alloc] init];
innerView.backgroundColor = [UIColor redColor];
[contentView addSubview:innerView];
[innerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsMake(20, 20, 20, 20));
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.centerY.mas_equalTo(0);
}];
通常写法
这里有一个注意点是我们把这个contentView
加到self.view
上去了, 最终我们其实并不需要知道他的frame
是多少.
需要结果的自适应
开发中还有一种是我们需要知道frame
的情况, 给tableView
设置tableHeaderView
, 或者其他什么框架, 需要我们提供一个有已知frame
的view
, 这时候怎么办呢, 我们试试, 把contentView
不设置父视图, 打印一下他的frame
UIView *contentView = [[UIView alloc] init];
contentView.backgroundColor = [UIColor blueColor];
UIView *innerView = [[UIView alloc] init];
innerView.backgroundColor = [UIColor redColor];
[contentView addSubview:innerView];
[innerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsMake(20, 20, 20, 20));
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
[contentView layoutIfNeeded];
NSLog(@"%@", NSStringFromCGRect(innerView.frame)); // {{20, 20}, {0, 0}}
NSLog(@"%@", NSStringFromCGRect(contentView.frame)); // {{0, 0}, {0, 0}}
都是0, 这时候我们设置view
肯定不成功啊, 都是0, 咋整呢?
我们创建view
, 内部那么多子view
, 让我通过高低来计算出frame
, 不是不可以, 很麻烦, 也很chǔn
, 那我们能不能, 还是让他自适应, 我约束子视图, 最后在不添加到父视图的情况下, 直接获取到contentView的size
呢?
优雅的自适应
很简单, 直接在[contentView layoutIfNeeded];前面加一句话
...
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
// 可以什么都不写, 或者你写上其他的约束
}];
[contentView layoutIfNeeded];
NSLog(@"%@", NSStringFromCGRect(innerView.frame)); // {{20, 20}, {100, 100}}
NSLog(@"%@", NSStringFromCGRect(contentView.frame)); // {{-70, -70}, {140, 140}}
contentView
并不需要添加到父视图, 由于其内部视图已经做好了约束, 确实把它撑起来了.
最后我们得到innerView
是100*100
, contentView
是140*140
, 因为frame.origin
我们没有设置, 显示的是-70, 这个不重要, 当他被添加到其他视图上时, origin
会自动更改的.
到这一步, 我们得到一个view
, 我只要把内部的view
约束好, 就能拿到他的frame
, 这样我设置header
或者其他需要的地方的时候, 我可以直接给出正确的size
, 就不需要自己去计算, 是不是很优雅.
实战
headerView
这是我们常见的用户信息, 我现在要求你只传给我一个有已知size
的headerView
那我们的方法就如下
- (UIView *)getHeaderView {
UIView *headerView = [[UIView alloc] init];
UIView *iconView = [[UIView alloc] init];
[headerView addSubview:iconView];
[iconView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(20);
make.height.mas_equalTo(40);
make.width.mas_equalTo(40);
make.left.mas_equalTo(20);
}];
UIView *nameView = [[UIView alloc] init];
[headerView addSubview:nameView];
// 写法1
// [nameView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.top.equalTo(iconView.mas_bottom).with.offset(20);
// make.left.mas_equalTo(20);
// make.right.mas_equalTo(-20);
// make.height.mas_equalTo(40);
// make.bottom.mas_equalTo(-40);
// }];
//
// [headerView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.width.mas_equalTo(320);
// }];
// 写法2
[nameView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(iconView.mas_bottom).with.offset(20);
make.left.mas_equalTo(20);
make.right.mas_equalTo(-20);
make.width.mas_equalTo(280);
make.height.mas_equalTo(40);
make.bottom.mas_equalTo(-40);
}];
[headerView mas_makeConstraints:^(MASConstraintMaker *make) {
}];
[headerView layoutIfNeeded];
NSLog(@"%@", NSStringFromCGRect(headerView.frame)); // {{-160, -80}, {320, 160}}
NSLog(@"%@", NSStringFromCGRect(iconView.frame)); // {{20, 20}, {40, 40}}
NSLog(@"%@", NSStringFromCGRect(nameView.frame)); // {{20, 80}, {280, 40}}
return headerView;
}
其中写法1就是headerView
限制了宽度320, 里面的nameView
左右距离20, 那么nameView
就是280
写法2就是nameView
限制了宽度280, 左右各20, 那headerView
宽就是320
至此, 我们在还没有加到父视图上, 还没有对headerView
有任何人为计算的情况下, 获得了一个已知size
的headerView
, 拿去干别的事岂不是很方便?