UIView如何优雅的自适应布局(Masonry)
怎么安装Masonry和怎么makeConstraints不多说, 我们假设你会...
cell的高度自适应 - 子view撑起父view
如果你经常使用这方法, 可以跳过这节.
开发中常常需要UITableViewCell高度自适应, 最最常见的, 就是UILabel的多行文字显示, 我们都是给内部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, 这时候怎么办呢?
用layoutIfNeeded? 让UI更新, 拿到frame? 我们试试, 把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是没有父视图的, 它是不可以设置相对约束的
}];
[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, 就不需要自己去计算, 是不是很优雅.

浙公网安备 33010602011771号