0

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

Nitish
  • 13,845
  • 28
  • 135
  • 263
  • 2
    `gradientLayer.colors = [color2, color1, color1, color2]; gradientLayer.locations = [0.0, 0.2, 0.8, 1.0]`? You need to understand that it means that the colors will be at the locations you gave. But in your code it's `[0.0, 0.10, 0.9]`. So imagine writing a blue line at 0, a green at 0.1 and a blue at 0.9. (in a diagonal way according to you start/endpoint). Now between each of theses lines you apply the gradual change of color ("two gradual changes from two consecutive lines meet at halfway") . That's then normal that you got your previous output instead of the expected one. – Larme Jul 05 '18 at 11:05
  • @Larme : Apologies, I am finding it hard to get the point. – Nitish Jul 05 '18 at 11:16
  • 1
    But the colors/locations I gave made it work? I'm working on a visual explanation. Might come in a few hours (do it at home) – Larme Jul 05 '18 at 11:18
  • @Larme : It did. Exactly, it did. – Nitish Jul 05 '18 at 11:19
  • 1
    `cgColor as CGColor` casting from CGColor to CGColor is pointless – Leo Dabus Jul 05 '18 at 12:05
  • @LeoDabus : Thanks for noticing. Silly mistake !! – Nitish Jul 06 '18 at 10:04

1 Answers1

4

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.

Larme
  • 24,190
  • 6
  • 51
  • 81
  • Many thanks for your inputs @Larne. Though your comment helped fix the issue yesterday, but this is enough explanation to get clarity on the subject. – Nitish Jul 06 '18 at 10:01