微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Swift 中向 UIViewPropertyAnimator 添加完成处理程序

如何解决在 Swift 中向 UIViewPropertyAnimator 添加完成处理程序

我试图让一个属性动画师在一个视图控制器出现时开始动画。 现在动画正在播放,但是 UIViewPropertyAnimator 没有响应添加到它的完成处理程序。

  • UIVisualEffectView 子类。
import UIKit

final class BlurEffectView: UIVisualEffectView {
    
    deinit {
    animator?.stopAnimation(true)
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        effect = nil
        animator = UIViewPropertyAnimator(duration: 1,curve: .linear) { [uNowned self] in
          self.effect = theEffect
        }
        animator?.pausesOnCompletion = true
   }

    private let theEffect: UIVisualEffect = UIBlurEffect(style: .regular)
    var animator: UIViewPropertyAnimator?

}

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func doSomething(_ sender: UIButton) {
        let vc = storyboard?.instantiateViewController(identifier: "second") as! SecondVC
        vc.modalPresentationStyle = .overFullScreen

        present(vc,animated: false) { //vc presentation completion handler
            
            //adding a completion handler to the UIViewPropertyAnimator
            vc.blurView.animator?.addCompletion({ (pos) in
                print("animation complete") //the problem is that this line isn't executed 
            })
            vc.blurView.animator?.startAnimation()
        }
    }
    
}
  • 第二个视图控制器
import UIKit

class SecondVC: UIViewController {

    @IBOutlet weak var blurView: BlurEffectView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

这里 UIViewPropertyAnimator 完成处理程序是在第二个视图控制器(具有视觉效果视图的控制器)呈现之后添加的。我曾尝试将完成处理程序移动到不同的位置,例如 viewDidLoadviewDidAppear,但似乎没有任何效果

解决方法

整个事情似乎设计不正确。

draw(_ rect:) 不是初始化您的动画师*的地方,我对发生的事情的最佳猜测是当您尝试启动它时 vc.blurView.animator?nil(您确认它不是不是吗?)。

相反,您的视图类可能如下所示**:

final class BlurEffectView: UIVisualEffectView {
    func fadeInEffect(_ completion: @escaping () -> Void) {
        UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.5,delay: 0,options: []) {
            self.effect = UIBlurEffect(style: .regular)
        } completion: { _ in
            completion()
        }
    }
}

你会像这样执行你的动画:

present(vc,animated: false) { //vc presentation completion handler
    vc.blurView.fadeInEffect {
        // Completion here
    }
}

*draw(_ rect:) 每次让系统知道您需要重绘视图时都会被调用,并且在内部您应该使用 CoreGraphics 来绘制视图的内容,这不是您想要的在这里做。

**由于您没有使用属性动画器的任何更高级的功能,因此似乎没有必要将其存储在 ivar 中。

,

问题在于您将 pausesOnCompletion 设置为 true。这会导致不调用完成处理程序。

如果您确实需要将其设置为 true,则需要使用 KVO 来观察 isRunning 属性:

// property of your VC
var ob: NSKeyValueObservation?

...

self.ob?.invalidate()
self.ob = vc.blurView.animator?.observe(\.isRunning,options: [.new],changeHandler: { (animator,change) in
    if !(change.newValue!) {
        print("completed")
    }
})
vc.blurView.animator?.startAnimation()

正如 EmilioPelaez 所说,您不应该在 animator 中初始化您的 draw。同样,如果您确实有使用 pausesOnCompletion = true 的理由,请将其设置为惰性属性:

lazy var animator: UIViewPropertyAnimator? = {
    let anim = UIViewPropertyAnimator(duration: 1,curve: .linear) { [unowned self] in
        self.effect = self.theEffect
    }
    anim.pausesOnCompletion = true
    return anim
}()

self.effect = nil 可以在初始化程序中设置。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。