Search code examples
iosswiftcagradientlayer

CAGradientLayer locations not coming correct


I followed this post for setting gradient location.

My Code :

let color1 = UIColor(red: 0.0/255.0, green: 231.0/255.0, blue: 198.0/255.0, alpha: 0.9).cgColor as CGColor
let color2 = UIColor(red: 0.0/255.0, green: 198.0/255.0, blue: 255.0/255.0, alpha: 0.9).cgColor as CGColor      
self.gradientLayer.colors = [color2, color1, color2]
self.gradientLayer.locations = [0.0, 0.10, 0.9]
self.gradientLayer.startPoint = CGPoint(x: 0, y: 0)
self.gradientLayer.endPoint = CGPoint(x: 1, y: 1)
viewMain.layer.insertSublayer(self.gradientLayer, at: 0)  

My output :

enter image description here

Expected output :

enter image description here


Solution

  • I changed the startPoint/endPoint for the sake of the illustration. This code can be used in XCode Playground. That's not the best Swifty code, but focus on logic/explanation rather than pure Swift code

    Shared settings:

    import Foundation
    import UIKit
    
    let viewsWidth: CGFloat = 300.0
    let viewsHeight: CGFloat = 400.0
    

    The way to fix you code is to modify locations:

    let viewMain: UIView = UIView(frame: CGRect(x: 0, y: 0, width: viewsWidth, height: viewsHeight))
    let color1 = UIColor(red: 0.0/255.0, green: 231.0/255.0, blue: 198.0/255.0, alpha: 0.9).cgColor
    let color2 = UIColor(red: 0.0/255.0, green: 198.0/255.0, blue: 255.0/255.0, alpha: 0.9).cgColor
    var gradientLayer = CAGradientLayer.init()
    gradientLayer.frame = viewMain.bounds
    gradientLayer.colors = [color2, color1, color1, color2]
    gradientLayer.locations = [0.0, 0.2, 0.8, 1.0]
    gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
    viewMain.layer.insertSublayer(gradientLayer, at: 0)
    
    viewMain //That's just for the Show Result action in Playground
    

    ViewMain:

    enter image description here

    Some explanations now.

    Let's first draw a line at each of the locations:

    let otherView = UIView(frame: viewMain.bounds)
    if let locations = gradientLayer.locations, let colors = gradientLayer.colors {
        for (index, aLocation) in locations.enumerated() {
            let aLine = UIView(frame: CGRect(x: viewsWidth*CGFloat(aLocation.floatValue)-2,
                                             y: 0,
                                             width: 4,
                                             height: viewsHeight))
            aLine.backgroundColor = UIColor(cgColor: colors[index] as! CGColor)
            otherView.addSubview(aLine)
        }
    }
    
    otherView //That's just for the Show Result action in Playground
    

    OtherView:

    enter image description here

    Now, let's draw a gradient, for each line, but only one (the rest of the colors is set to white to simplify).

    if let locations = gradientLayer.locations, let colors = gradientLayer.colors {
        let offset = 5
        let bigView = UIView(frame: CGRect(x: 0,
                                           y: 0,
                                           width: viewsWidth * CGFloat(locations.count) + CGFloat(offset),
                                           height: viewsHeight))
    
        for (index, _) in locations.enumerated() {
    
            let aGradientView = UIView(frame: CGRect(x: 0 + (viewsWidth + CGFloat(offset))*CGFloat(index),
                                                     y: 0,
                                                     width: viewsWidth,
                                                     height: viewsHeight))
            let aGradientLayer = CAGradientLayer()
            aGradientLayer.frame = aGradientView.bounds
    
            var aGradientColors = [CGColor](repeating: UIColor.white.cgColor, count: colors.count)
            aGradientColors[index] = colors[index] as! CGColor
            aGradientLayer.colors = aGradientColors
            aGradientLayer.locations = gradientLayer.locations
            aGradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            aGradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
            aGradientView.layer.insertSublayer(aGradientLayer, at: 0)
    
            aGradientView.layer.borderColor = UIColor.black.cgColor
            aGradientView.layer.borderWidth = 2.0
            aGradientView.clipsToBounds = false
            bigView.addSubview(aGradientView)
        }
    
        bigView //That's just for the Show Result action in Playground
    }
    

    BigView: enter image description here

    The illustration shown speak for itself.

    At each "line" (exhibit 2), when you want to apply the gradient (exhibit 3), the color goes from that line until the next one. That's why your first locations were not giving the expected results. You need to put intermediary steps.