【问题标题】:How to perform button animation before performing segue [duplicate]如何在执行segue之前执行按钮动画[重复]
【发布时间】: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)

    }

【问题讨论】:

    标签: ios swift xcode viewcontroller


    【解决方案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)
      }
      

      【讨论】:

      • 什么是保留周期?
      • 保持对对方对象的强引用,会导致内存泄漏
      猜你喜欢
      • 2018-11-08
      • 1970-01-01
      • 2012-08-10
      • 2018-08-11
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多