如何在执行segue之前执行按钮动画[重复]

Posted

技术标签:

【中文标题】如何在执行segue之前执行按钮动画[重复]【英文标题】:How to perform button animation before performing segue [duplicate] 【发布时间】:2018-12-27 17:05:01 【问题描述】:

在我的主屏幕中,我有一个 startGame 按钮,按下该按钮时会触发动画 (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)

    

【问题讨论】:

【参考方案1】:

您的动画持续时间为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)

【讨论】:

感谢这个成功!【参考方案2】:

也可以使用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)   

【讨论】:

【参考方案3】:

只需对我们的动画使用完成方法,没有计时器延迟。

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)
    

【讨论】:

请注意,这不起作用,因为他的pulsate 方法在UIButton 上被调用并且按钮不能present ViewController【参考方案4】:

使用asyncAfter[weak self] 的替代方法来删除保留周期,

DispatchQueue.main.asyncAfter(deadline: .now() + 0.6)  [weak self] in
    self?.present(viewController, animated: false, completion: nil)

【讨论】:

什么是保留周期? 保持对对方对象的强引用,会导致内存泄漏

以上是关于如何在执行segue之前执行按钮动画[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有动画的情况下执行 unwind segue?

如何执行条件转场

动画后执行 Segue,但动画项目回到之前的位置

如何创建 Segue 的动画执行和展开 Segue?

在执行 segue 之前如何显示加载指示器?

如何实现自定义segue动画?