如何在执行 segue 之前执行按钮动画
How to perform button animation before performing segue
在我的主屏幕上,我有一个开始游戏按钮,按下该按钮时会触发动画 (sender.pulsate()),然后还会更改 viewController:
@IBAction func newGamePressed(_ sender: UIButton) {
currentScore = 0
timeRemaining = 60
visualTime = "01:00"
sender.pulsate()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "firstLevel")
self.present(viewController, animated: false, completion: nil)
}
但是,新的 viewController 会立即出现,而不是等待脉动动画发生(脉动动画确实有效)。
我知道这与代码没有被自上而下阅读有关,但我可以添加什么来告诉 xcode 到 运行 一个接一个?
谢谢!
ps。这是脉动代码,如果它相关:
func pulsate() {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = 0.6
pulse.fromValue = 0.95
pulse.toValue = 1.0
pulse.autoreverses = true
pulse.repeatCount = 2
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
}
您的动画持续时间 0.6
秒。在那个时间
之后现在 ViewController
异步之后
您可以为动画结束后执行的 pulsate
方法创建完成
func pulsate(duration: CFTimeInterval, _ completion: @escaping ()->()) {
...
pulse.duration = duration
...
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
completion()
}
}
CATransaction 的完成块
您可以为 pulsate
方法创建 completion
,该方法在 CAAnimation
结束后执行。为此,您可以使用 CATransaction
的完成块
func pulsate(duration: CFTimeInterval, _ completion: @escaping ()->()) {
CATransaction.begin()
...
pulse.duration = duration
...
CATransaction.setCompletionBlock {
completion()
}
CATransaction.commit()
}
sender.pulsate(duration: 0.6) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "firstLevel")
self.present(viewController, animated: false, completion: nil)
}
只需为我们的动画使用完成方法,没有计时器延迟。
func pulsate() {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = 0.6
pulse.fromValue = 0.95
pulse.toValue = 1.0
pulse.autoreverses = true
pulse.repeatCount = 2
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
CATransaction.setCompletionBlock {
print("animation done")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "firstLevel")
self.present(viewController, animated: false, completion: nil)
}
}
也可以使用performSelector
实现
@IBAction func didTapButton(_ sender: UIButton) {
let animationDuration = 0.6
sender.pulsate(duration:animationDuration)
//Invoke method after particular delay on current thread
self.perform(#selector(navigateToViewController), with: nil, afterDelay: animationDuration)
}
@objc func navigateToViewController() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "NewViewControllerID") as! NewViewController
self.present(viewController, animated: false, completion: nil)
}
脉动码
func pulsate(duration: Double) {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = duration
pulse.fromValue = 0.95
pulse.toValue = 1.0
pulse.autoreverses = true
pulse.repeatCount = 2
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
}
使用 asyncAfter
和 [weak self]
的替代方法来删除保留循环,
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak self] in
self?.present(viewController, animated: false, completion: nil)
}
在我的主屏幕上,我有一个开始游戏按钮,按下该按钮时会触发动画 (sender.pulsate()),然后还会更改 viewController:
@IBAction func newGamePressed(_ sender: UIButton) {
currentScore = 0
timeRemaining = 60
visualTime = "01:00"
sender.pulsate()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "firstLevel")
self.present(viewController, animated: false, completion: nil)
}
但是,新的 viewController 会立即出现,而不是等待脉动动画发生(脉动动画确实有效)。
我知道这与代码没有被自上而下阅读有关,但我可以添加什么来告诉 xcode 到 运行 一个接一个?
谢谢!
ps。这是脉动代码,如果它相关:
func pulsate() {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = 0.6
pulse.fromValue = 0.95
pulse.toValue = 1.0
pulse.autoreverses = true
pulse.repeatCount = 2
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
}
您的动画持续时间 0.6
秒。在那个时间
异步之后
您可以为动画结束后执行的 pulsate
方法创建完成
func pulsate(duration: CFTimeInterval, _ completion: @escaping ()->()) {
...
pulse.duration = duration
...
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
completion()
}
}
CATransaction 的完成块
您可以为 pulsate
方法创建 completion
,该方法在 CAAnimation
结束后执行。为此,您可以使用 CATransaction
的完成块
func pulsate(duration: CFTimeInterval, _ completion: @escaping ()->()) {
CATransaction.begin()
...
pulse.duration = duration
...
CATransaction.setCompletionBlock {
completion()
}
CATransaction.commit()
}
sender.pulsate(duration: 0.6) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "firstLevel")
self.present(viewController, animated: false, completion: nil)
}
只需为我们的动画使用完成方法,没有计时器延迟。
func pulsate() {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = 0.6
pulse.fromValue = 0.95
pulse.toValue = 1.0
pulse.autoreverses = true
pulse.repeatCount = 2
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
CATransaction.setCompletionBlock {
print("animation done")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "firstLevel")
self.present(viewController, animated: false, completion: nil)
}
}
也可以使用performSelector
实现
@IBAction func didTapButton(_ sender: UIButton) {
let animationDuration = 0.6
sender.pulsate(duration:animationDuration)
//Invoke method after particular delay on current thread
self.perform(#selector(navigateToViewController), with: nil, afterDelay: animationDuration)
}
@objc func navigateToViewController() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "NewViewControllerID") as! NewViewController
self.present(viewController, animated: false, completion: nil)
}
脉动码
func pulsate(duration: Double) {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = duration
pulse.fromValue = 0.95
pulse.toValue = 1.0
pulse.autoreverses = true
pulse.repeatCount = 2
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
}
使用 asyncAfter
和 [weak self]
的替代方法来删除保留循环,
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak self] in
self?.present(viewController, animated: false, completion: nil)
}