调用 layoutIfNeeded 后视图未立即显示

Posted

技术标签:

【中文标题】调用 layoutIfNeeded 后视图未立即显示【英文标题】:View not displayed immediately after layoutIfNeeded is called 【发布时间】:2017-03-19 21:26:53 【问题描述】:

我正在尝试使用自动布局制作一个简单的从顶部向下滑动的动画(在 SnapKit 的帮助下)。

下面是我用来生成视图、设置其约束并强制重新加载(从而显示)所述视图的代码。在同一代码中,我将顶部约束更改为不同的值并在动画块中调用layoutIfNeeded

然而,发生的事情是视图显示在预期位置,没有任何动画。

这是在短暂延迟后(用于其他目的)在方法中调用的代码:

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: 
    self.view.addSubview(view)
    view.backgroundColor = .black

    view.snp.makeConstraints  (make) -> Void in
        make.left.right.equalToSuperview()
        make.height.equalTo(200)
        make.bottom.equalTo(self.view.snp.top) // Pin view to top to prepare slide-down animation
    

    view.setNeedsLayout()
    view.layoutIfNeeded()

    view.snp.updateConstraints  (make) -> Void in
        make.bottom.equalTo(self.view.snp.top).offset(200)
    

    view.setNeedsLayout()

    UIView.animate(withDuration: 5, animations: 
        view.layoutIfNeeded()
    )
)

【问题讨论】:

我看到了几个潜在的原因。 (1) 看起来您正试图在单独的线程中进行 UI 更新。我很惊讶它甚至可以工作。如果您以这种方式编码,那将是一个主要的禁忌。 (2) 为什么在 UIView.animate 中调用 setNeedsLayout()layoutIfNeeded() outside?这可能是罪魁祸首。 (3) 约束变化。也许这与 SnapKit 相关,但调用 updateContraints() 不是我在尝试更改约束然后为约束设置动画时所做的事情。我更改其中的常量/乘数。 (1) 之后就没想过。谢谢。任何提示我应该如何在一定延迟后调用方法来进行 UI 更新? Sleep() 显然也是一种不好的方式,因为它会阻塞。 (2) 我需要先设置视图,然后才能对其进行动画处理。 (3) SnapKit 的UpdateConstraint 就是这样做的。如果你有一个给定的约束,我会比较你是否只更新常量/乘数。 @dfd DispatchQueue.main 确实在使用main thread,所以不用担心(来源:hackingwithswift.com/read/9/4/…)。 这个问题的标题具有误导性。似乎更多的是关于约束和动画。 layoutIfNeeded() 与视图是否在屏幕上的关系为零。如果渲染系统不忙于长时间运行的进程,它将把它放在屏幕上,但它再次保证不被渲染。 【参考方案1】:

感谢In Swift, how do I animate a UIView with auto-layout like a page sliding in?我找到了罪魁祸首。

虽然我不是 100% 明白为什么会这样,但 layoutIfNeeded 需要从超级视图调用,而不是视图本身。

所以调用self.view.layoutIfNeeded() 是正确的方法。请注意,view 是当前正在添加的 UIView,而 self.view 是超级视图,其中正在添加 view

【讨论】:

在同一段代码中同时使用self.viewview,而这些名称指的是两个不同的对象,这听起来很令人困惑。回答后一切都开始工作了吗?如果是这样,您可以接受您的答案,以便获得积分。 :) 是的,命名不是很聪明 :-) 它确实解决了这个问题。不过只能在 2 天内接受我自己的答案。 啊,好的。很高兴你知道了!

以上是关于调用 layoutIfNeeded 后视图未立即显示的主要内容,如果未能解决你的问题,请参考以下文章

为啥在子视图中添加图层蒙版时需要调用 layoutIfNeeded()?

如果 layoutIfNeeded() 被调用,UIView 约束不会动画

swift 3 layoutIfneeded 无法正常工作

layoutIfNeeded 是如何使用的?

在 UITableView 上为 layoutIfNeeded 设置动画而不为 UITableViewCells 设置动画

Swift/iOS 子视图在主线程上未立即显示