最近在学习Masonry在更新约束动画过程中产生了一些疑问:setNeedsLayout、layoutIfNeeded和setNeedsUpdateConstraints、updateConstraintsIfNeeded的区别和联系。
通过查看前辈的文章和实践个人理解如下:
-setNeedsLayout方法: 标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定会被调用
-layoutIfNeeded方法:如果,有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)
-setNeedsUpdateConstraints方法: 标记为需要更新约束,异步调用updateViewConstraints刷新布局,不立即刷新,但updateViewConstraints一定会被调用
-updateConstraintsIfNeeded方法:如果,有需要刷新的约束,立即调用updateViewConstraints进行布局(如果没有标记,不一定会调用layoutSubviews)
举个栗子:
//
// ViewController.m
// PodDome
//
// Created by ZX on 2017/2/13.
// Copyright © 2017年 ZX. All rights reserved.
//
#import "ViewController.h"
// 只要添加了这个宏,就不用带mas_前缀
#define MAS_SHORTHAND
// 只要添加了这个宏,equalTo就等价于mas_equalTo
#define MAS_SHORTHAND_GLOBALS
// 这个头文件一定要放在上面两个宏的后面
#import "Masonry.h"
@interface ViewController ()
@property (nonatomic, strong) UIButton *growingButton;
@property (nonatomic, assign) CGFloat scacle;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.growingButton setTitle:@"点我放大" forState:UIControlStateNormal];
self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;
self.growingButton.layer.borderWidth = 3;
[self.growingButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.growingButton];
self.scacle = 1.0;
[self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.view);
// 初始宽、高为100,优先级最低
make.width.height.mas_equalTo(100 * self.scacle).priorityLow();
// 最大放大到整个view
make.width.height.lessThanOrEqualTo(self.view);
}];
}
#pragma mark - updateViewConstraints
- (void)updateViewConstraints {
[self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.view);
// 初始宽、高为100,优先级最低
make.width.height.mas_equalTo(100 * self.scacle).priorityLow();
// 最大放大到整个view
make.width.height.lessThanOrEqualTo(self.view);
}];
[super updateViewConstraints];
}
- (void)onGrowButtonTaped:(UIButton *)sender {
self.scacle += 0.5;
// 告诉self.view约束需要更新
// [self.view setNeedsUpdateConstraints];
// 调用此方法告诉self.view检测是否需要更新约束,若需要则更新,下面添加动画效果才起作用
// [self.view updateConstraintsIfNeeded];
// 告诉self.view布局需要更新
[self.view setNeedsLayout];
// 调用此方法告诉self.view检测是否需要更新布局,若需要则更新,下面添加动画效果才起作用
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)viewDidLayoutSubviews {
[self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.view);
// 初始宽、高为100,优先级最低
make.width.height.mas_equalTo(100 * self.scacle).priorityLow();
// 最大放大到整个view
make.width.height.lessThanOrEqualTo(self.view);
}];
[super viewDidLayoutSubviews];
}
@end
不管约束更新的代码是放在layoutIfNeeded 还是 updateViewConstraints 都能完成约束更新的动画效果。
补充一点:在控制器中viewDidLayoutSubviews 等价于 layoutSubviews。