美文网首页
由使用Masonry布局不能立即获取到frame想到的一些问题

由使用Masonry布局不能立即获取到frame想到的一些问题

作者: 困惑困惑困惑 | 来源:发表于2018-09-27 11:24 被阅读105次

    前言

    我相信很多同学曾经都遇到过这样的问题:明明用masonry布好局了,怎么获取到的frame就是0呢?

    解决问题不难,百度一下就能找到答案,但如果只是单纯的解决问题而不去想为什么或许会制约我们的成长。

    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
          make.edges.mas_equalTo(UIEdgeInsetsMake(0, 0, 0, 0));
    }];
    // 0.1秒后获取      
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{  
     NSLog(@"%@", self.scrollView);
    });
    

    问:为什么要调用superView的layoutIfNeeded或者延迟0.1秒后才能获取到frame?

    [iOS高端妓术裙的裙主:锤神] 告诉我:

    首先你要知道autolayout和frame的关系,autolayout最终也是转成frame,masonry是建立在autolayout之上的。你没获取到正确的值,那是因为约束还没布局完成。相当于就是我们给一定的约束,系统内部自己去根据约束条件转成对应的frame,而这需要一个过程。想要拿到正确的frame最好的就是让autolayout完成之后,什么时候完成呢?那就是在layoutsubviews for view or didlayoutsubviews for controller 里获取,当然在控制器的viewdidappear里也拿得到,但是正确做法和最佳做法还是在控制器里的viewdidlayout里获取最好~因为autolayout会根据约束,不停的去改变frame,这方法里最后拿到的frame就是最终姿势.

    锤神最后补充了一句:

    可能有些需要纠正,但这基本是我一个大概的理解~~

    看,多么谦虚~

    我来总结一下锤神的回答:

    约束转frame需要时间。

    探求原因

    先不管锤神的回答,自己一步一步思考下。

    猜想:Masonry的block的回调不是立即的

    NSLog(@"a");[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {    NSLog(@"b");
        make.edges.mas_equalTo(UIEdgeInsetsMake(90, 90, 90, 90);
    }];
    NSLog(@"c");
    

    按照猜想,打印结果应该是“acb”

    但实际上却是“abc”。

    为什么?

    看看Masonry的源码就知道了:

    - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {    self.translatesAutoresizingMaskIntoConstraints = NO;    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];   block(constraintMaker);   return [constraintMaker install];}
    

    我们调用mas_makeConstraints这个方法的时候block就立即调用了。

    那这就更奇怪了,既然获取frame的时候已经设置好约束了,怎么获取到的frame却是0呢?

    因为你设置好了约束不代表它就转化成了frame,正如锤神所说,这需要一个过程。

    0.1秒后能获取到正确的frame是因为这个时候布局已经完成。

    那么我们怎么知道布局完成的这个点?

    锤神说的是didlayoutsubviews这个方法,虽然锤神很牛逼,但我们也应该保持怀疑态度,看下官方文档验证一下锤神的说法:

    masonry block里的代码是最先执行的,接着是直接获取frame,然后是viewDidLayoutSubviews,最后才是0.1秒后block。

    layoutIfNeeded做了什么事?

    弄清了延迟0.1加载可以获取到正确frame的原因,再来研究下为什么调用了[xx.superView layoutIfNeeded]也能获取到正确frame的原因。

    先看一下官方文档对这个方法的描述:

    可以发现,调用[self.scrollView.superview layoutIfNeeded];时回调了viewDidLayoutSubviews方法。这就是调用[xx.superView layoutIfNeeded]后能获取到正确frame的原因。

    原文链接:http://www.cocoachina.com/ios/20170928/20671.html

    相关文章

      网友评论

          本文标题:由使用Masonry布局不能立即获取到frame想到的一些问题

          本文链接:https://www.haomeiwen.com/subject/enfeoftx.html