从这个答案:
这是被接受的答案建议为您的视图变化设置动画:
_addBannerDistanceFromBottomConstraint.constant = 0
UIView.animate(withDuration: 5) {
self.view.layoutIfNeeded()
}
不
更改框架layoutIfNeeded
时为什么要打电话。我们正在更改约束,所以(根据[另一个答案]我们不应该打电话吗? setNeedsUpdateConstraints
如果以后发生的更改使您的约束之一无效,则应立即删除约束并调用setNeedsUpdateConstraints
我实际上确实尝试过同时使用它们。使用setNeedsLayout
我的视图 可以向右正确设置动画
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func animate(_ sender: UIButton) {
UIView.animate(withDuration: 1.8, animations: {
self.centerXConstraint.isActive = !self.centerXConstraint.isActive
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
})
}
@IBOutlet weak var centerYConstraint: NSLayoutConstraint!
@IBOutlet var centerXConstraint: NSLayoutConstraint!
}
但是,使用setNeedsUpdateConstraints
不会 设置动画,它只是将视图 快速向左 移动。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func animate(_ sender: UIButton) {
UIView.animate(withDuration: 1.8, animations: {
self.centerXConstraint.isActive = !self.centerXConstraint.isActive
self.view.setNeedsUpdateConstraints()
self.view.updateConstraintsIfNeeded()
})
}
@IBOutlet weak var centerYConstraint: NSLayoutConstraint!
@IBOutlet var centerXConstraint: NSLayoutConstraint!
}
如果我不想动画,请使用其中之一view.setNeedsLayout
或view.setNeedsUpdateConstraints
将其向左移动。然而:
view.setNeedsLayout
,点击我的按钮后,viewDidLayoutSubviews
到达断点。但是updateViewConstraints
从未达到断点。这使我对约束的更新方式感到困惑。view.setNeedsUpdateConstraints
,在点击按钮后updateViewConstraints
到达我的 断点, 然后 到达viewDidLayoutSubviews
断点。这确实是有道理的,更新约束,然后调用layoutSubviews。根据我的读物:如果您更改约束条件,然后使其生效,则必须致电setNeedsUpdateConstraints
,但是根据我的观察,这是错误的。拥有以下代码足以制作动画:
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
为什么?
然后我想也许是在幕后通过其他方式更新了约束。所以,我把一个断点override func updateViewConstraints
和overridefuncviewDidLayoutSubviews
,但只viewDidLayoutSubviews
达到了断点。
那么,自动版式引擎如何管理呢?
这是iOS开发人员中常见的误解。
这是我的“自动版式”的“黄金法则”之一:
你 永远 需要调用任何这些方法:
setNeedsUpdateConstraints()
updateConstraintsIfNeeded()
updateConstraints()
updateViewConstraints()
除了 极少数情况下,您的布局非常复杂会减慢您的应用程序运行速度(或者您故意选择以非典型方式实施布局更改)。
通常,当您想更改布局时,您可以在点击按钮或发生任何事件触发更改后立即激活/停用或更改布局约束,例如,在按钮的操作方法中:
@IBAction func toggleLayoutButtonTapped(_ button: UIButton) {
toggleLayout()
}
func toggleLayout() {
isCenteredLayout = !isCenteredLayout
if isCenteredLayout {
centerXConstraint.isActive = true
} else {
centerXConstraint.isActive = false
}
}
正如Apple在其《自动布局指南》中所说:
发生影响性更改之后,几乎总是更干净,更轻松地立即更新约束。将这些更改推迟到以后的方法中会使代码更加复杂且难以理解。
当然,您也可以在动画中包装此约束更改:首先执行约束更改,然后通过调用layoutIfNeeded()
动画闭包为更改设置动画:
@IBAction func toggleLayoutButtonTapped(_ button: UIButton) {
// 1. Perform constraint changes:
toggleLayout()
// 2. Animate the changes:
UIView.animate(withDuration: 1.8, animations: {
view.layoutIfNeeded()
}
}
每当您更改约束时,系统都会 自动
安排延迟的布局遍历,这意味着系统将在不久的将来重新计算布局。无需致电,setNeedsUpdateConstraints()
因为您只是 自己
更新(更改)约束!需要更新的是布局,即所有视图的框架, 而不是 其他任何约束。
如前所述,iOS布局系统通常不会立即对约束更改做出反应,而只会安排延迟的布局通过。这是出于性能原因。这样想:
当您去购物时,您将商品放入购物车,但没有立即付款。取而代之的是,您将其他物品放到购物车中,直到感觉得到所需的一切为止。只有这样,您才能前往收银员并立即支付所有杂货。这样更有效。
由于这种延迟的布局传递,需要一种特殊的机制来处理布局更改。我称之为 无效原则 。这是一个两步机制:
就布局引擎而言,它对应于:
setNeedsLayout()
layoutIfNeeded()
和
setNeedsUpdateConstraints()
updateConstraintsIfNeeded()
第一对方法 将导致 立即 (而不是延迟)布局通过:首先使布局无效,然后在布局无效时立即重新计算布局(当然是这样)。
通常您不介意现在或几毫秒后进行布局传递,因此通常只调用setNeedsLayout()
使布局无效,然后等待推迟的布局传递。这使您有机会对约束进行其他更改,然后稍晚但一次全部更新布局(→购物车)。
你只需要调用layoutIfNeeded()
,当你需要的布局被重新计算 现在 。当您需要根据新布局的结果框架执行其他一些计算时,可能就是这种情况。
第二对方法
将导致立即调用updateConstraints()
(在视图上或updateViewConstraints()
在视图控制器上)。但这是您通常不应该执行的操作。
仅当布局 真的很
慢并且UI因布局更改而感到迟钝时,您才可以选择与上述方法不同的方法:您不必对按钮的点击直接更新约束,而只是在“注释”一下什么您要更改,另一个“说明”是您的约束需要更新。
@IBAction func toggleLayoutButtonTapped(_ button: UIButton) {
// 1. Make a note how you want your layout to change:
isCenteredLayout = !isCenteredLayout
// 2. Make a note that your constraints need to be updated (invalidate constraints):
setNeedsUpdateConstraints()
}
这将安排一个延迟的布局过程,并确保在布局过程中将调用updateConstraints()
/
updateViewConstraints()
。因此,您现在甚至可以执行其他更改并调用setNeedsUpdateConstraints()
一千次-
您的约束在下一次布局遍历中仍只会更新 一次 。
现在,您覆盖updateConstraints()
/updateViewConstraints()
并根据您当前的布局状态(即您在上面的“1”中“注意到”的内容)执行必要的约束更改:
override func updateConstraints() {
if isCenteredLayout {
centerXConstraint.isActive = true
} else {
centerXConstraint.isActive = false
}
super.updateConstraints()
}
同样,如果布局真的很慢并且您要处理数百或数千个约束,那么这只是您的最后选择。我 从未updateConstraints()
在任何项目中使用过。
我希望这可以使事情变得更清晰。
从这个答案中: 以下是公认的答案建议的动画视图更改: 当我们不更改帧时,为什么要调用。我们正在更改约束,所以(根据另一个答案)我们不应该调用? 同样,这个备受好评的答案说: 如果以后发生的某些更改使某个约束无效,则应立即删除该约束并调用setNeedsUpdateConstraints 我确实试过两种方法。使用my view可正确向左设置动画 但是,使用不会设置动画,它只是将视图快速向左移动。 如
问题内容: 我正在使用来更新旧的应用,并且当没有广告时,它会滑出屏幕。出现广告时,它会在屏幕上滑动。基本的东西。 旧样式,我将帧设置在动画块中。新样式,我对自动布局约束有一个确定Y位置,在这种情况下,它是距父视图底部的距离,并修改常量: 横幅完全按预期移动,但没有动画。 更新:我重新观看了WWDC 12讲的“掌握自动布局的最佳实践” ,其中涵盖了动画。它讨论了如何使用CoreAnimation更新
我正在用更新一个旧的应用程序,当没有广告时,它就会滑出屏幕。当有广告时,它会在屏幕上滑动。基本的东西。 老风格,我设置了一个动画块的框架。新样式中,我有一个到auto-layout约束,它确定位置,在本例中是距离超级视图底部的距离,并修改常数: 和预期的一样,但没有动画。 更新:我重新观看了WWDC12讨论的最佳实践,以掌握自动布局,其中包括动画。它讨论了如何使用CoreAnimation更新约束
我在学习教程中的动画自动布局 http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was 一切都很顺利。 当我尝试在我的应用程序中使用这个概念,尝试从下到上设置设置屏幕(UIView)的动画时,当设置屏幕只是一个空的UIView时,效果非常好, 但如果我将UILabel
所以我正在学习如何使视图从屏幕外变成动画,用作滑块菜单。 我改编了这段代码,从如何在Swift中使用约束对UIView进行动画制作? 什么是自我。看法layoutIfNeeded()部分代码如何? 2.为什么在动画之前和期间编码为2x? 注:如果我注释掉第一个自我。看法layoutIfNeeded()没有任何变化,但如果我注释掉第二个self。看法layoutIfNeeded()移动不再设置动画,
我知道自动布局链基本上由3个不同的过程组成。 更新约束 布局视图(这里是我们计算框架的地方) 显示 我并不完全清楚的是 和 之间的内在区别。来自苹果文档: 设置需要布局 当您想要调整视图子视图的布局时,请在应用程序的主线程上调用此方法。此方法记下请求并立即返回。由于此方法不会强制立即更新,而是等待下一个更新周期,因此您可以使用它来使多个视图的布局失效,然后再更新这些视图中的任何一个。此行为允许您将