使用 UIViewPropertyAnimator 依次为 UIView 的 alpha 设置动画

Posted

技术标签:

【中文标题】使用 UIViewPropertyAnimator 依次为 UIView 的 alpha 设置动画【英文标题】:Animating a UIView's alpha in sequence with UIViewPropertyAnimator 【发布时间】:2017-03-23 09:03:37 【问题描述】:

我有一个 UIView,我想在 0.5 秒后显示,并在 0.5 秒后再次隐藏,创建一个简单的动画。我的代码如下:

    let animation = UIViewPropertyAnimator.init(duration: 0.5, curve: .linear) 
        self.timerBackground.alpha = 1
        let transition = UIViewPropertyAnimator.init(duration: 0.5, curve: .linear) 
            self.timerBackground.alpha = 0
        
        transition.startAnimation(afterDelay: 0.5)
    
    animation.startAnimation()

当我测试它时,什么都没有发生。我认为这是因为它们同时运行,这意味着它们相互抵消,但这不是“afterDelay”部分应该防止的吗?

如果我单独运行它们,即从隐藏到可见或从可见到​​隐藏,它可以工作,但是当我尝试按顺序运行它们时,它不起作用。

我的 UIView 不是不透明或隐藏的。

【问题讨论】:

"但这不是 "afterDelay" 部分应该防止的吗?"不。如果你想在动画之后做一些事情,添加一个completion handler到属性动画器。 developer.apple.com/reference/uikit/uiviewpropertyanimator/… 【参考方案1】:

您可以使用Timer,并为您的UIViewPropertyAnimatorobject 添加出现/隐藏动画块在每个计时器滴答声中。

这是一个代码库:

@IBOutlet weak var timerBackground: UIImageView!

private var timer: Timer?
private var isShown = false
private var viewAnimator = UIViewPropertyAnimator.init(duration: 0.5, curve: .linear)

override func viewDidLoad() 
    super.viewDidLoad()
    viewAnimator.addAnimations 
        self.timerBackground.alpha = 1
    
    viewAnimator.startAnimation()
    isShown = true

    self.timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(self.startReversedAction), userInfo: nil, repeats: true)


func startReversedAction() 
    // stop the previous animations block if it did not have time to finish its movement
    viewAnimator.stopAnimation(true)
    viewAnimator.addAnimations (
        self.timerBackground.alpha = self.isShown ? 0 : 1
    )
    viewAnimator.startAnimation()
    isShown  =  !isShown

我已经为 dots jumping 和 ios 10 Animations demo project 实现了非常相似的行为。

请随时查看以获取更多详细信息。

【讨论】:

【参考方案2】:

如果你有复杂的动画,使用UIView.animateKeyframes 你会很好地构建你的代码。如果您将使用嵌套在其他完成块中的 UIView 动画,它可能会导致荒谬的缩进级别和零可读性。

这是一个例子:

/* Target frames to move our object to (and animate)
   or it could be alpha property in your case... */

let newFrameOne = CGRect(x: 200, y: 50, width: button.bounds.size.width, height: button.bounds.size.height)
let newFrameTwo = CGRect(x: 300, y: 200, width: button.bounds.size.width, height: button.bounds.size.height)

UIView.animateKeyframes(withDuration: 2.0,
                               delay: 0.0,
                             options: .repeat,
                          animations:  _ in
    /* First animation */                                    
    UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5, animations:  [weak self] in
        self?.button.frame = newFrameOne
    )

    /* Second animation */                                    
    UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations:  [weak self] in
        self?.button.frame = newFrameTwo
    )

    /* . . . */  

    , completion: nil)

【讨论】:

我同意动画关键帧很棒,但在 Apple 的 UIView 文档页面上他们说 Use of these [UIView.animate] methods is discouraged. Use the UIViewPropertyAnimator class to perform animations instead. 在 WWDC 2017 (developer.apple.com/videos/play/wwdc2017-230) 的高级动画会议中,他们介绍了 UIViewPropertyAnimator,他们还展示了如何通过嵌套调用来使用关键帧动画,以在其中创建关键帧动画UIViewPropertyAnimator 的初始化(参见该视频中的 26:47)。【参考方案3】:

对我有用的是使用 UIViewPropertyAnimators 序列。这是我的代码示例:

let animator1 = UIViewPropertyAnimator(duration:1, curve: .easeIn)
        animator1.addAnimations 
            smallCoin.transform = CGAffineTransform(scaleX: 4, y: 4)
            smallCoin.center = center
        
        let animator2 = UIViewPropertyAnimator(duration:1, curve: .easeIn)
        animator2.addAnimations 
            center.y -= 20
            smallCoin.center = center
        
        let animator3 = UIViewPropertyAnimator(duration:10, curve: .easeIn)
        animator3.addAnimations 
            smallCoin.alpha = 0
        
        animator1.addCompletion  _ in
            animator2.startAnimation()
          
        animator2.addCompletion  _ in
            animator3.startAnimation()
          
        animator3.addCompletion ( _ in
            print("finished")
        )
        animator1.startAnimation()

您甚至可以添加 afterdelay 属性来管理动画的速度。

animator3.startAnimation(afterDelay: 10)

【讨论】:

以上是关于使用 UIViewPropertyAnimator 依次为 UIView 的 alpha 设置动画的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 UIViewPropertyAnimator.fractionComplete 驱动 UIView.transition

使用 UIViewPropertyAnimator 同步动画 CALayer 属性和 UIView

UIViewPropertyAnimator 自动布局完成问题

使用 UIViewPropertyAnimator 为 UILabel textColor 属性设置动画

使用 UIViewPropertyAnimator 依次为 UIView 的 alpha 设置动画

使用 UIViewPropertyAnimator 通过触摸中断动画