了解 UIView.animate 以及完成闭包的工作原理
Understanding UIView.animate and how completion closures work
有没有一种方法可以中断动画,而不是"cancel"(倒带)它们,而是"fast-forwards"它们强制完成关闭到 运行原计划?
背景:
在 IOS 中,可以 "animate a view with duration" 并包含一个完成闭包...像这样使用 UIView 的静态方法 animate() :
class func animate(withDuration: TimeInterval, animations: () -> Void, completion: ((Bool) -> Void)? = nil)
现实生活中的示例可能看起来像 EXHIBIT-A 此处:
// assume we have a UILabel named 'bigLabel'
func animationWeNeedToDo() {
UIView.animate(withDuration: 1, animations: {
self.bigLabel.alpha = 0
}, completion: {
if [=12=] {
UIView.animate(withDuration: 1, animations: {
self.bigLabel.center.x -= 20
}, completion: {
if [=12=] {
self.updateMainDisplay()
}
}) }
})
}
所以我们有一个 UILabel,bigLabel,我们首先对 "fade," 进行动画处理,然后我们链接到第一个完成后的另一个动画,然后再次完成第二个,我们 运行 最重要的函数,updateMainDisplay()。
但是这个简单的示例可能会复杂得多,涉及更多的视图。执行 updateMainDisplay() 可能是必要的。 ;)
updateMainDisplay() 函数很重要,因为它 "resets" 所有视图,将应用程序返回到类似于应用程序最初启动时的中性状态......有点 "re-calibrates" 一切。
Anyhoo,问题是,如果用户在动画播放时做了一些事情,比如尽早按下主页按钮或切换到新的 activity(模态,比如设置......然后回来)发生,它永远不会完成... 所以 updateMainDisplay() 不会被执行! ...事情变得复杂和讨厌。
那么,如何处理这个问题呢?
似乎需要在 "onPause()" 中完成一些事情(我知道这不是 Android)...例如确保取消动画并执行 updateMainDisplay()。
但是为了做到这一点,您必须在 "onPause()" 方法中检查各种布尔状态。如果有一种方法可以保证动画完成,我会更愿意。
所以,再一次,我认为如果有一种方法可以不取消动画,而是取消所有动画"force immediate completion",那就太棒了.
这是伪代码...但是有没有办法做这样的事情:
var myAnimation = (animation) { // EXHIBIT-A from above }
myAnimation.execute()
// if needed:
myAnimation.forceCompletionNow()
有人知道这是否可行吗?
谢谢。
您的代码存在问题,您正在检查完成闭包的第一个参数。这表明动画是否完成。如果那是真的,你只有 运行 updateMainDisplay()
。
所以事实上,即使动画没有完成,完成处理程序也会被调用。是你告诉它如果动画没有结束什么都不做。
要解决此问题,只需删除 if [=12=]
语句即可。
现在 Xcode 将显示警告,因为您没有使用闭包的第一个参数。要消除此警告,只需将 _ in
放在闭包的开头:
{ _ in
// some code
}
您可以尝试的另一件事是 CABasicAnimation
,它 实际上 不会更改视图的属性。它使 CALayer
动画化。如果您以某种方式再次更新视图,视图将回到动画之前的原始状态。您似乎想在动画结束后重置所有内容,所以这可能适合您。
有没有一种方法可以中断动画,而不是"cancel"(倒带)它们,而是"fast-forwards"它们强制完成关闭到 运行原计划?
背景:
在 IOS 中,可以 "animate a view with duration" 并包含一个完成闭包...像这样使用 UIView 的静态方法 animate() :
class func animate(withDuration: TimeInterval, animations: () -> Void, completion: ((Bool) -> Void)? = nil)
现实生活中的示例可能看起来像 EXHIBIT-A 此处:
// assume we have a UILabel named 'bigLabel'
func animationWeNeedToDo() {
UIView.animate(withDuration: 1, animations: {
self.bigLabel.alpha = 0
}, completion: {
if [=12=] {
UIView.animate(withDuration: 1, animations: {
self.bigLabel.center.x -= 20
}, completion: {
if [=12=] {
self.updateMainDisplay()
}
}) }
})
}
所以我们有一个 UILabel,bigLabel,我们首先对 "fade," 进行动画处理,然后我们链接到第一个完成后的另一个动画,然后再次完成第二个,我们 运行 最重要的函数,updateMainDisplay()。
但是这个简单的示例可能会复杂得多,涉及更多的视图。执行 updateMainDisplay() 可能是必要的。 ;)
updateMainDisplay() 函数很重要,因为它 "resets" 所有视图,将应用程序返回到类似于应用程序最初启动时的中性状态......有点 "re-calibrates" 一切。
Anyhoo,问题是,如果用户在动画播放时做了一些事情,比如尽早按下主页按钮或切换到新的 activity(模态,比如设置......然后回来)发生,它永远不会完成... 所以 updateMainDisplay() 不会被执行! ...事情变得复杂和讨厌。
那么,如何处理这个问题呢?
似乎需要在 "onPause()" 中完成一些事情(我知道这不是 Android)...例如确保取消动画并执行 updateMainDisplay()。
但是为了做到这一点,您必须在 "onPause()" 方法中检查各种布尔状态。如果有一种方法可以保证动画完成,我会更愿意。
所以,再一次,我认为如果有一种方法可以不取消动画,而是取消所有动画"force immediate completion",那就太棒了.
这是伪代码...但是有没有办法做这样的事情:
var myAnimation = (animation) { // EXHIBIT-A from above }
myAnimation.execute()
// if needed:
myAnimation.forceCompletionNow()
有人知道这是否可行吗?
谢谢。
您的代码存在问题,您正在检查完成闭包的第一个参数。这表明动画是否完成。如果那是真的,你只有 运行 updateMainDisplay()
。
所以事实上,即使动画没有完成,完成处理程序也会被调用。是你告诉它如果动画没有结束什么都不做。
要解决此问题,只需删除 if [=12=]
语句即可。
现在 Xcode 将显示警告,因为您没有使用闭包的第一个参数。要消除此警告,只需将 _ in
放在闭包的开头:
{ _ in
// some code
}
您可以尝试的另一件事是 CABasicAnimation
,它 实际上 不会更改视图的属性。它使 CALayer
动画化。如果您以某种方式再次更新视图,视图将回到动画之前的原始状态。您似乎想在动画结束后重置所有内容,所以这可能适合您。