Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-Animate Gradient Background with different color in swift in ios

Tags:

ios

swift

I want to re-animate gradient background with different color when animating. I can successfully animate gradient color with this code.

let dayTopColor = CommonUtils.colorWithHexString("955EAC")
let dayBottomColor = CommonUtils.colorWithHexString("9F3050")
let dayToTopColor = CommonUtils.colorWithHexString("D15B52")
let dayToBottomColor = CommonUtils.colorWithHexString("CC4645")
let nightTopColor = CommonUtils.colorWithHexString("2D5E7C")
let nightBottomColor = CommonUtils.colorWithHexString("19337D")
let nightToTopColor = CommonUtils.colorWithHexString("21334E")
let nightToBottomColor = CommonUtils.colorWithHexString("101A55")
var isInSaudiArabia = false
var gradient : CAGradientLayer?
var toColors : AnyObject?
var fromColors : AnyObject?

func animateBackground(){
        var layerToRemove: CAGradientLayer?
        for layer in self.view.layer.sublayers!{
            if layer.isKindOfClass(CAGradientLayer) {
                layerToRemove = layer as? CAGradientLayer
            }
        }
        layerToRemove?.removeFromSuperlayer()

            self.gradient!.colors = [nightTopColor.CGColor, nightBottomColor.CGColor]
            self.toColors = [nightToTopColor.CGColor, nightToBottomColor.CGColor]

        self.view.layer.insertSublayer(self.gradient!, atIndex: 0)
        animateLayer()
    }

    func animateLayer(){

        self.fromColors = self.gradient!.colors!
        self.gradient!.colors = self.toColors as? [AnyObject]
        let animation : CABasicAnimation = CABasicAnimation(keyPath: "colors")
        animation.delegate = self
        animation.fromValue = fromColors
        animation.toValue = toColors
        animation.duration = 3.50
        animation.removedOnCompletion = true
        animation.fillMode = kCAFillModeForwards
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.delegate = self

        self.gradient!.addAnimation(animation, forKey:"animateGradient")
    }

    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {

        self.toColors = self.fromColors;
        self.fromColors = self.gradient!.colors!

        animateLayer()
    }

CommonUtils.colorWithHexString() is a function which converts hex color to UIColor. Btw when i try to change background color to day color while animating, background gradient color got flickered.

Is there anybody who knows solution.

like image 852
Svetoslav Atanasov Avatar asked May 26 '16 21:05

Svetoslav Atanasov


1 Answers

The problem is that when you remove the layer, it stops the animation. But when the animation stops, animationDidStop is still getting called, which is starting a new animation, itself. So, you're removing the layer, which stops the animation, immediately starts another, but you're then starting yet another animation. You have dueling animations.

You can check flag to see if the animation finished properly before animationDidStop should call animateLayer.

override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
    if flag {
        toColors = fromColors;
        fromColors = gradient!.colors!

        animateLayer()
    }
}

Personally, I'm not sure why you're removing and adding and removing the layer. And if you were, I'm not sure why you don't just gradient?.removeFromSuperlayer() rather than iterating through the layers.

Regardless, I'd just keep the gradient layer there, just check its presentationLayer and start the animation from there:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        fromColors = [dayTopColor.CGColor, dayBottomColor.CGColor]
        toColors = [dayToTopColor.CGColor, dayToBottomColor.CGColor]

        gradient = CAGradientLayer()
        gradient!.colors = fromColors!
        gradient!.frame = view.bounds
        view.layer.addSublayer(gradient!)

        animateLayer()
    }

    let dayTopColor = CommonUtils.colorWithHexString("955EAC")
    let dayBottomColor = CommonUtils.colorWithHexString("9F3050")
    let dayToTopColor = CommonUtils.colorWithHexString("D15B52")
    let dayToBottomColor = CommonUtils.colorWithHexString("CC4645")

    let nightTopColor = CommonUtils.colorWithHexString("2D5E7C")
    let nightBottomColor = CommonUtils.colorWithHexString("19337D")
    let nightToTopColor = CommonUtils.colorWithHexString("21334E")
    let nightToBottomColor = CommonUtils.colorWithHexString("101A55")

    var gradient : CAGradientLayer?
    var toColors : [CGColor]?
    var fromColors : [CGColor]?

    var day = true

    func toggleFromDayToNight() {
        day = !day

        if day {
            fromColors = [dayTopColor.CGColor, dayBottomColor.CGColor]
            toColors = [dayToTopColor.CGColor, dayToBottomColor.CGColor]
        } else {
            fromColors = [nightTopColor.CGColor, nightBottomColor.CGColor]
            toColors = [nightToTopColor.CGColor, nightToBottomColor.CGColor]
        }

        let colors = (gradient!.presentationLayer() as! CAGradientLayer).colors // save the in-flight current colors
        gradient!.removeAnimationForKey("animateGradient")                      // cancel the animation
        gradient!.colors = colors                                               // restore the colors to in-flight values
        animateLayer()                                                          // start animation
    }

    func animateLayer() {
        let animation : CABasicAnimation = CABasicAnimation(keyPath: "colors")
        animation.fromValue = gradient!.colors
        animation.toValue = toColors
        animation.duration = 3.50
        animation.removedOnCompletion = true
        animation.fillMode = kCAFillModeForwards
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.delegate = self

        gradient!.colors = toColors

        gradient!.addAnimation(animation, forKey:"animateGradient")
    }

    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        if flag {
            swap(&toColors, &fromColors)
            animateLayer()
        }
    }

    @IBAction func didTapButton() {
        toggleFromDayToNight()
    }

}
like image 72
Rob Avatar answered Feb 09 '23 12:02

Rob