前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >setNeedsLayout和layoutIfNeeded看我就懂!

setNeedsLayout和layoutIfNeeded看我就懂!

作者头像
Dwyane
发布2018-05-22 17:41:38
2.6K0
发布2018-05-22 17:41:38
举报
文章被收录于专栏:技术总结技术总结
前言:

开发得跟view打交道,我们也经常看到苹果官方代码有layout方法的相关调用,但是大家可知道什么时候调用,什么时候需要吗?针对网上大部分资料讲得不够清晰,我决定用Demo来讲解

一、layoutSubviews

不能直接调用这个方法。强制刷新布局,调用 setNeedsLayout,如果想马上刷新界面,调用layoutIfNeeded

二、setNeedsLayout跟layoutIfNeded

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

首先我们在Main.storyboard拖取出一个adjust Height按钮以及带有约束的一个viewRed 如图:

viewRedConstraints拖到ViewController.swift,并作为属性

下面我用一段代码验证下

代码语言:javascript
复制
    @IBAction func adjustedBtnClick(_ sender: Any) {
        view.layoutIfNeeded()
        if self.redViewHeight.constant == 30.0 {
            self.redViewHeight.constant = self.view.frame.height - 90
        }else {
            self.redViewHeight.constant = 30.0
        }
        UIView.animate(withDuration: 2.0) { 
            self.view.layoutIfNeeded()
        }
    }

当按下按钮时,您看到的第一件事是调用view.layoutIfNeeded()。请记住,此方法强制立即布局并显示更新。您可能会想知道为什么在我们进行约束更改之前呢。苹果认为这是一个最佳做法,以确保任何以前的更新等待更新周期的完成,所以我已经添加了它。

当这样的约束被更新时,它会自动执行相当于setNeedsLayout的操作,因此在下一个更新周期内不需要更新视图。我们可以没有更多的代码,你会看到更新,但它不会有动画效果。但在我们的例子中,添加了2秒的动画块UIView.animate,在该块内,我们通过layoutIfNeeded方法强制立即布局。由于此布局同步发生,因此在动画块中捕获来自约束更改的帧移动,因此如果您现在运行应用程序,则可以看到红色视图在2秒钟内如何变大变小。 效果如下:

当我们把动画块代码替换成

代码语言:javascript
复制
   UIView.animate(withDuration: 2.0) { 
       self.view.setNeedsLayout()
   }

现在我们在动画块中正在做的是将视图标记为需要布局更新,但不会立即强制执行。相反,setNeedsLayout方法返回,视图只是在列表中,以在下一个更新周期中进行更新。净效果是在动画块中不会发生动画,因为该块中的视图没有更改。 效果如下:

在这种情况下单击按钮将立即根据更新的约束更新视图大小,而不是动画更新。等一下,如果我们没有使用layoutIfNeeded,为什么会立即? 对我们而言,红色视图的大小变化立即发生。起初它似乎是反直觉的,因为我们没有使用layoutIfNeeded强制立即更新。但是,我们没有在动画块的上下文中进行视图更新,也就是说刚好是一个周期,所以它似乎是立即的,跟没有UIView.animate这段代码效果是一样的。因为我们标记为更新,更新周期的发生的地方也是动画开始的地方。 ** 因此,由于我们的代码已经标记该视图需要通过setNeedsLayout进行布局更新,所以是在更新周期中立即启动视图更新,而不是从更新周期开始约束更改和帧移动的动画。 **

刷新子对象布局:

-layoutSubviews方法:这个方法,默认没有做任何事情,需要子类进行重写

-setNeedsLayout方法: 标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定会被调用

-layoutIfNeeded方法:如果,有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)

如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局

在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用[view layoutIfNeeded]

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.05.06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、layoutSubviews
  • 二、setNeedsLayout跟layoutIfNeded
    • 刷新子对象布局:
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档