masonry 使用笔记--续

上一篇做完了masonry 的基础用法笔记,现在想要更深入一些了解 masonry 对动画框架的支持,再进一步了解 masonry 的实现原理

masonry 动画

准备知识

在开始演示动画之前得先搞懂几个知识点,要不然就算你能写代码出来实现动画,但是也不会清楚为什么代码要这样写,原理是什么。

  1. UIView 中的 setNeedsLayout 方法,想更深入了解请看官文 setNeedsLayout

如果要调整视图子视图的布局,请在应用程序的主线程上调用此方法。 此方法记录请求并立即返回。 由于此方法不强制立即更新,而是等待下一个更新周期,因此可以在更新任何视图之前使用它来使多个视图的布局无效。 此行为允许您将所有布局更新合并到一个更新周期,这通常会提高性能。

// Allows you to perform layout before the drawing cycle happens. -layoutIfNeeded forces layout early
- (void)setNeedsLayout;
  1. UIView 中的 layoutIfNeeded 方法,同样想深入了解可以去看官文 layoutIfNeeded

使用此方法强制视图立即更新其布局。 使用“自动布局”时,布局引擎会根据需要更新视图的位置,以满足约束的更改。 使用以根视图接收消息的视图,此方法从根开始布局视图子树。 如果没有待处理的布局更新,则此方法退出而不修改布局或调用任何与布局相关的回调。

- (void)layoutIfNeeded;
  1. 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 堪称神作

动画效果如下

4639197-995322369c97c2e1.gif
Jan-26-2019 21-48-36.gif

实现代码

  1. 第一步,创建一个 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);
    }];
}
  1. 第二步,实现 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 会强制立即更新布局。这里有点难理解,但是我找不出更合适的解释,表示很对不住语文老师。

masonry 源码解读博客再配合源码测试,深入理解 masonry 杠杠的

猜你喜欢

转载自blog.csdn.net/weixin_34082854/article/details/86877289