序
上一篇做完了masonry 的基础用法笔记,现在想要更深入一些了解 masonry 对动画框架的支持,再进一步了解 masonry 的实现原理
masonry 动画
准备知识
在开始演示动画之前得先搞懂几个知识点,要不然就算你能写代码出来实现动画,但是也不会清楚为什么代码要这样写,原理是什么。
- UIView 中的 setNeedsLayout 方法,想更深入了解请看官文 setNeedsLayout
如果要调整视图子视图的布局,请在应用程序的主线程上调用此方法。 此方法记录请求并立即返回。 由于此方法不强制立即更新,而是等待下一个更新周期,因此可以在更新任何视图之前使用它来使多个视图的布局无效。 此行为允许您将所有布局更新合并到一个更新周期,这通常会提高性能。
// Allows you to perform layout before the drawing cycle happens. -layoutIfNeeded forces layout early
- (void)setNeedsLayout;
- UIView 中的 layoutIfNeeded 方法,同样想深入了解可以去看官文 layoutIfNeeded
使用此方法强制视图立即更新其布局。 使用“自动布局”时,布局引擎会根据需要更新视图的位置,以满足约束的更改。 使用以根视图接收消息的视图,此方法从根开始布局视图子树。 如果没有待处理的布局更新,则此方法退出而不修改布局或调用任何与布局相关的回调。
- (void)layoutIfNeeded;
- UIView 中的 layoutSubviews 方法, 官文的描述
layoutSubviews,有兴趣可以去看看。
此方法的默认实现在iOS 5.1及更早版本中不执行任何操作。 否则,默认实现使用您设置的任何约束来确定任何子视图的大小和位置。
子类可以根据需要覆盖此方法,以执行其子视图的更精确布局。 仅当子视图的自动调整大小和基于约束的行为不提供所需的行为时,才应覆盖此方法。 您可以使用实现直接设置子视图的框架矩形。另外,您不应该直接调用此方法。 如果要强制进行布局更新,请在下次绘图更新之前调用setNeedsLayout方法。 如果要立即更新视图的布局,请调用layoutIfNeeded方法。
- (void)layoutSubviews; // override point. called by layoutIfNeeded automatically. As of iOS 6.0, when constraints-based layout is used the base implementation applies the constraints-based layout, otherwise it does nothing.
如果相对上面有更加几个方法有更加深入的认识,就得去了解runloop了,可以拜读一下这篇博客:深入理解runloop 堪称神作
动画效果如下
Jan-26-2019 21-48-36.gif实现代码
- 第一步,创建一个 View 来展示动画;创建一个 Button 来触发动画;
- (void)createDemo {
self.animationView = [[UIView alloc] init];
self.animationView.backgroundColor = UIColor.greenColor;
//1
[self.view addSubview:self.animationView];
[self.animationView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.view.mas_centerX);
make.centerY.mas_equalTo(self.view.mas_centerY);
make.width.height.mas_equalTo(100);
}];
UIButton *button = [[UIButton alloc]init];
button.backgroundColor = UIColor.redColor;
[button setTitle:@"放大" forState:UIControlStateNormal];
[button setTitle:@"缩小" forState:UIControlStateSelected];
[button addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(-100);
make.centerX.mas_equalTo(self.view.mas_centerX);
make.height.width.mas_equalTo(100);
}];
}
- 第二步,实现 Button 的点击事件
- (void)clicked:(UIButton *)btn {
btn.selected = !btn.selected;
//2
[self.animationView setNeedsLayout];
if (btn.selected) {
[UIView animateWithDuration:0.25 animations:^{
[self.animationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(300);
}];
//3
[self.animationView layoutIfNeeded];
}];
} else {
[UIView animateWithDuration:0.25 animations:^{
[self.animationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(100);
}];
//3
[self.animationView layoutIfNeeded];
}];
}
}
当 masonry 执行布局代码是并不会立马进行布局,在 setNeedsLayout 时不会立即更新布局,同时还会使后面执行的视图布局无效,而调用 layoutIfNeeded 会强制立即更新布局。这里有点难理解,但是我找不出更合适的解释,表示很对不住语文老师。
网友评论