Berro
Berro

Reputation: 15

swift 3 uiview animate only showing last two animations

Trying to get the background colours of my popup UIView to change between 4 colours and then loop back and repeat. For the code below, only the last two colours are appearing, the first two are skipping, I've tried everything I can think of, any idea what I'm missing?

     UIView.animateWithDuration(2, delay: 0.0, options:[UIViewAnimationOptions.Repeat, UIViewAnimationOptions.Autoreverse], animations: {
        self.view.backgroundColor = UIColor.blackColor()
        self.view.backgroundColor = UIColor.greenColor()
        self.view.backgroundColor = UIColor.grayColor()
        self.view.backgroundColor = UIColor.redColor()
    }, completion: nil)

Updated code:

     UIView.animate(withDuration: 12, delay: 1, options:
                [UIViewAnimationOptions.allowUserInteraction,
                 UIViewAnimationOptions.repeat,
                 UIViewAnimationOptions.autoreverse],
                                       animations: {
                                        self.popupView.backgroundColor = UIColor.black
                                        self.popupView.backgroundColor = UIColor.green
                                        self.popupView.backgroundColor = UIColor.gray
                                        self.popupView.backgroundColor = UIColor.red
            }, completion:nil )

Update 2: Individual animation block:

     UIView.animate(withDuration: 3, delay: 0.0, options:
       [UIViewAnimationOptions.repeat, 
        UIViewAnimationOptions.autoreverse, 
       .allowUserInteraction], 
       animations: { (BOOL) -> Void in

                self.popupView.backgroundColor = UIColor.black
            }) { (Bool) -> Void in
                UIView.animate(withDuration: 3.0, animations: { () -> Void in
                    self.popupView.backgroundColor = UIColor.green
                }, completion: { (Bool) -> Void in
                    UIView.animate(withDuration: 3.0, animations: { () -> Void in
                        self.popupView.backgroundColor = UIColor.gray
                    }, completion: { (Bool) -> Void in
                        UIView.animate(withDuration: 3.0, animations: { () -> Void in
                            self.popupView.backgroundColor = UIColor.white
                        }, completion:nil)
                    })
                })
            }

Upvotes: 0

Views: 610

Answers (2)

Ryan
Ryan

Reputation: 4884

First of all, color change in animation block will not animate color change. However if you want to just change color, it might be okay to use animation block.

To get a result you want with animation block the code should look like below.

UIView.animate(withDuration: 12, delay: 1, options:
            [.allowUserInteraction, .repeat, .autoreverse],
                                   animations: {
                                    self.popupView.backgroundColor = UIColor.black
        }, completion:{ competed in
            UIView.animate(withDuration: 12, delay: 1, options:
            [.allowUserInteraction, .repeat, .autoreverse],
                                   animations: {
                                    self.popupView.backgroundColor = UIColor.green
            }, completion: .... )

If you want to just change background color every N seconds, you better use timer.

UDATE

Here's an example of using timer.

class MyViewController : UIViewController {
    var timer: Timer?
    let colors: [UIColor] = [.white, .black, .red, .magenta]
    var idx: Int = 0

    deinit {
        timer?.invalidate()
        timer = nil
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        timer = Timer(timeInterval: 5,
                      target: self,
                      selector: #selector(changeColor),
                      userInfo: nil,
                      repeats: true)
    }

    @objc
    func changeColor() {
        view.backgroundColor = colors[idx]
        idx = (idx + 1) % colors.count
    }
}

Using timer will make your code simpler.

Upvotes: 0

creeperspeak
creeperspeak

Reputation: 5521

First off, backgroundColor is not animatable. But if it was, or if you wanted to animate something that is animatable, the better way to cycle through multiple animations would be to use key frame animation, like so:

UIView.animateKeyframes(withDuration: 12, delay: 0, options: [.allowUserInteraction, .repeat, .autoreverse], animations: {
    UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.25, animations: {
        self.popupView.backgroundColor = .black
    })
    UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25, animations: {
        self.popupView.backgroundColor = .green
    })
    UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25, animations: {
        self.popupView.backgroundColor = .gray
    })
    UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25, animations: {
        self.popupView.backgroundColor = .red
    })
}, completion: nil)

In this case I set the relativeDuration for each keyFrame to be 0.25 (1/4) of the total animation time, and set the relativeStartTime to be beginning, 1/4, 1/2, and 3/4 of the way through the total duration.

Again, to reiterate, that is not an animatable property, but this is an effective way to chain animations together.

It also is possible to animate color change by using transition instead of animate, though you can't do keyFrame transition. You could chain these together by using the completions, and when you get to the end you'd have to start the animation over again by calling some wrapper function or something similar:

UIView.transition(with: self.popupView, duration: 3, options: .allowUserInteraction, animations: {
    self.popupView.backgroundColor = .black
}, completion: { (finished) in
    UIView.transition(with: self.popupView, duration: 3, options: .allowUserInteraction, animations: {
        self.popupView.backgroundColor = .green
    }, completion: { (finished) in
        UIView.transition(with: self.popupView, duration: 3, options: .allowUserInteraction, animations: {
            self.popupView.backgroundColor = .gray
        }, completion: { (finished) in
            UIView.transition(with: self.popupView, duration: 3, options: .allowUserInteraction, animations: {
                self.popupView.backgroundColor = .red
            }, completion: { (finished) in
                //Start the chain over again
            })
        })
    })
})

Upvotes: 1

Related Questions