在执行segue之前如何执行按钮动画

时间:2018-12-27 17:05:02

标签: ios swift xcode viewcontroller

在我的主屏幕中,我有一个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)

    }

4 个答案:

答案 0 :(得分:2)

您的动画的时长为0.6秒。在那之后出现ViewController


之后异步

您可以为您的pulsate方法创建完成方式,该完成方式在动画结束后执行

func pulsate(duration: CFTimeInterval, _ completion: @escaping ()->()) {
    ...
    pulse.duration = duration
    ...
    DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
        completion()
    }
}

CATransaction的完成块

您可以为completion方法创建pulsate,该方法在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)
}

答案 1 :(得分:1)

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

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)
    }
}

答案 2 :(得分:1)

也可以使用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 :(得分:0)

使用asyncAfter[weak self]来删除保留周期的另一种方法,

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