我正在尝试将受约束的视图(iconVerticalConstraint
)设置为超视图的中心Y(+100
)的动画,特别是在到达其右侧(0
)后的位置动画。
这是我的代码:
self.view.layoutIfNeeded()
UIView.animateKeyframes(withDuration: 2, delay: 0, animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25, animations:{
self.iconVerticalConstraint.constant -= 20
})
UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.75, animations:{
self.iconVerticalConstraint.constant -= 80
})
})
我尝试关注this question's answer,但这没有帮助,因为在我的情况下,我的视图包含更多子视图,内在链接,并且在我的动画块中放置layoutIfNeeded()
会为整个<设置动画/ strong>查看,而不仅仅是那个约束。否则这种方法根本就没有动画。
答案 0 :(得分:2)
更改
等约束self.iconVerticalConstraint.constant -= 20
应该在动画块外面,你只需要调用
self.view.layoutIfNeeded()
我认为因为你试图做2,并且打电话
self.view.layoutIfNeeded()
它们都发生一次,考虑改为:
self.iconVerticalConstraint.constant -= 20
UIView.animate(withDuration: 0.25, animations: {
self.view.layoutIfNeeded()
}) { (finished) in
self.iconVerticalConstraint.constant -= 80
UIView.animate(withDuration: 0.75, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
编辑:说明
当您遇到约束时,视图将不会更新,直到下一个布局周期,通常是退出当前范围时。因此,当您想要为约束设置动画时,可以在动画块之前更改常量,然后在动画块内调用layoutIfNeeded()
这将告诉它为当前强制布局周期设置动画。
现在在你的例子中,你在那里调用layoutIfNeeded()
,在那里什么也不做,然后改变2个常量,而不告诉布局动画,所以当范围退出时,UI将布局而没有动画。 / p>
在你的情况下,你想链接2个常量的变化,但你没有办法在第一个动画完成后改变第二个常量(80)
,如果你设置两个,两个常量都将被调整FIRST layoutIfNeeded()
因此,动画的链接仍将与您省略的其他动画一起使用,只需在第一个动画块中添加它们,如果它们在第一个关键帧中,则第二个动画块在第二个动画块中,如果它们在第二个动画块中
最终编辑:
此外,您可以将当前应用于self.view的layoutIfNeeded()
实际更改为其影响的视图,在本例中为iconVerticalConstraint
,如果它是附加到另一个视图的视图,则表示附加了顶部在视图底部,如果你想要制作动画,你必须在它影响的每个视图上调用layoutIfNeeded()
答案 1 :(得分:2)
花了几个小时的时间来理解基本机制,我可以为所有发现自己处境的人提供我自己的答案。
layoutIfNeeded()
告诉视图调整所有子视图的位置。
animate
或animateKeyframes
或您正在使用的所有其他替代方案,会告诉视图以您指定的方式执行动画块中的任何指令在animate
函数中(默认情况下,使用options: .easeInOut
)
回到问题:问题在于animate
和layoutIfNeeded
被称为 异步 ,所以事实上,每一个动画块内的指令在layoutIfNeeded
指令之前执行,使其无效。根据SeanLintern88的建议,解决方案不是将layoutIfNeeded
指令放在动画块中,因为这样我们就会根据动画告诉视图 调整其子视图的位置选项 即可。这是关键点。
答案有点简单。将动画部分移动到子视图本身,特别是在您知道超级视图已经过&#34; autolayouted&#34; (例如viewDidAppear
),以便已经定义并执行约束,现在可以更改它。在这一点上,代码应如下所示:
UIView.animateKeyframes(withDuration: 2, delay: 0, animations: {
self.view.layoutIfNeeded()
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25, animations:{
self.iconVerticalConstraint.constant -= 20
})
UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.75, animations:{
self.iconVerticalConstraint.constant -= 80
})
})
因为想要为自动布局设置动画。
另一个选项(例如,如果您没有想要为子视图创建课程)是要更改 界限/中心 viewDidAppear函数中。这是因为,如果您在父视图中,您知道此时自动布局已经已注册但未执行,更准确地说,边界和中心已根据已更改自动布局。
如果您随后更改了它们,您将获得所需的动画(但记住:自动布局仍处于启用状态,因此您必须以反映最终位置的方式更改约束你的动画;如果你愿意,你可以在completion
函数的animate
部分那样做。