Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 2.1: CAGradientLayer color location & distribution

My need is to show 3-colored distribution in a view. So I'm using following code.

func drawWithGradientLayer() {

        // total contains sum of all values contained in segmentValues variable.
        // I'm using green -> Orange -> Red colors as colors

        if total == 0 {
            return
        }

        if gradientLayer.superlayer != nil {
            gradientLayer.removeFromSuperlayer()
        }

        var previous: CGFloat = (CGFloat(segmentValues[0])/CGFloat(total))
        var locations: [NSNumber] = [previous]

        for var i=1; i<segmentValues.count; i++ {
            previous = previous + (CGFloat(segmentValues[i])/CGFloat(total))
            locations.append(previous)
        }

        locations.append(1.0) // Line may need to be commented

        gradientLayer = CAGradientLayer()
        gradientLayer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)

        gradientLayer.startPoint = CGPointMake(0.0, 0.5);
        gradientLayer.endPoint = CGPointMake(1.0, 0.5);

        gradientLayer.colors = colors
        gradientLayer.locations = locations

        self.layer.insertSublayer(gradientLayer, atIndex: 0)
}

But problem is that gradient colors are not distributed according to my requirements. E.g if ihave values of [1,0,1] so bar should display 50% red & 0% orange and 50% red. If values are [0,0,1] then only redColor should be drawn. How can I achieve this without grid lines? enter image description here

any other better solution will always be appreciated :)

like image 410
Abid Hussain Avatar asked Nov 18 '15 19:11

Abid Hussain


Video Answer


1 Answers

The key here is to understand how locations in CAGradientLayer work:

The gradient stops are specified as values between 0 and 1. The values must be monotonically increasing.

So you cannot specify locations like [1, 0, 1], but should rather use something like [0.0, 0.33, 0.67, 1.0], and the number of location values must be the same as your colors count.

To make a gradient with short color transitions like in your images, you have to repeat each color twice and specify the appropriate locations: gradients

So your code should be something like:

    gradientLayer.colors =  [
        UIColor.greenColor().CGColor,  UIColor.greenColor().CGColor,
        UIColor.orangeColor().CGColor, UIColor.orangeColor().CGColor,
        UIColor.redColor().CGColor,    UIColor.redColor().CGColor
    ]
    gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
    gradientLayer.locations = [0.0, 0.2, 0.3, 0.7, 0.8, 1.0]

If you want to get a 2-color gradient while not changing its colors, you can set a value less than 0 for startPoint.x or greater than 1 for endPoint.x, and set multiple locations to zero, e.g.:

    gradientLayer.startPoint = CGPoint(x: -0.01, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
    gradientLayer.locations = [0.0, 0.0, 0.0, 0.0, 0.1, 1.0]

which would give a result similar to this:

2-color gradient

like image 131
maxkonovalov Avatar answered Oct 26 '22 22:10

maxkonovalov