Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update CAGradientLayer colors on runtime in iOS swift?

I am using a UIView extension for applying a gradient layer to a UIView. I need to change the gradient colors on runtime while scrolling a tableview. I use the scrollview contentoffset value to update the gradient color.

What I tried: I tried to remove the layer from superlayer and create a new gradientlayer with new colors. But app is getting memory issues and the UI is freezing sometimes.

Is it possible to update the CAGradientLayer gradient colors on runtime?

extension UIView {
    func applyGradient(withColours colours: [UIColor], gradientOrientation orientation: GradientOrientation) {
        let gradient: CAGradientLayer = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = colours.map { $0.cgColor }
        gradient.startPoint = orientation.startPoint
        gradient.endPoint = orientation.endPoint
        self.layer.insertSublayer(gradient, at: 0)
    }
}
like image 352
abhimuralidharan Avatar asked May 24 '17 10:05

abhimuralidharan


2 Answers

The answer to this question is to change the color property of the gradient layer from within the same scope. I tried doing this before, but from a different scope.Now it is working. The answer is given below.

Swift 3.1 code:

let gradient = CAGradientLayer()

gradient.frame = view.bounds
gradient.colors = [UIColor.white.cgColor, UIColor.black.cgColor]
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 1, y: 1)
view.layer.insertSublayer(gradient, at: 0)

DispatchQueue.main.asyncAfter(deadline: .now() + 10) { 
// this will be called after 10 seconds.
    gradient.colors = [UIColor.red.cgColor, UIColor.black.cgColor]
}
like image 111
abhimuralidharan Avatar answered Oct 17 '22 17:10

abhimuralidharan


An alternative solution would be to use an animation block to change the gradient colors...

extension CAGradientLayer
{
    func animateChanges(to colors: [UIColor],
                        duration: TimeInterval)
    {
        CATransaction.begin()
        CATransaction.setCompletionBlock({
            // Set to final colors when animation ends
            self.colors = colors.map{ $0.cgColor }
        })
        let animation = CABasicAnimation(keyPath: "colors")
        animation.duration = duration
        animation.toValue = colors.map{ $0.cgColor }
        animation.fillMode = kCAFillModeForwards
        animation.isRemovedOnCompletion = false
        add(animation, forKey: "changeColors")
        CATransaction.commit()
    }
}
like image 28
nananta Avatar answered Oct 17 '22 17:10

nananta