简体   繁体   中英

Animating a UIView's alpha in sequence with UIViewPropertyAnimator

I have a UIView that I want to reveal after 0.5 seconds, and hide again after 0.5 seconds, creating a simple animation. My code is as follows:

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

When I test it out, nothing happens. I assume it's because they're both running at the same time, which would mean they cancel each other out, but isn't that what the "afterDelay" part should prevent?

If I run them separately, ie either fading from hidden to visible, or visible to hidden, it works, but when I try to run them in a sequence, it doesn't work.

My UIView is not opaque or hidden.

You can use Timer , and add appearing / hiding animations blocks on every timer tick to your UIViewPropertyAnimator object.

Here's a codebase:

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

I've implemented the very similar behavior for dots jumping of iOS 10 Animations demo project .

Please, feel free to look at it to get more details.

Use UIView.animateKeyframes you'll structure your code nicely if you have complicated animations. If you'll use UIView animations nested within the completion blocks of others, it will probably result in ridiculous indentation levels and zero readability.

Here's an example:

/* 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM