1

I am trying to find out how to create an oval gradient which is not a perfect circle. For example an american football/rugby/eye shape instead of a circle.

At the moment I have created a CALayer subclass as below which creates a circle. How can I get this to a oval shape (as mentioned above)?

class CircleGradientLayer: CALayer {

var startRadius: CGFloat?
var startCenter: CGPoint?
var endCenter: CGPoint?
var endRadius: CGFloat?
var locations: [CGFloat]?
var colors: [UIColor]?

override func drawInContext(ctx: CGContext) {
    super.drawInContext(ctx)


    if let colors = self.colors, let locations = self.locations, let startRadius = self.startRadius, let startCenter = self.startCenter, let endCenter = self.endCenter, let endRadius = self.endRadius {
        var colorSpace: CGColorSpaceRef?

        var components = [CGFloat]()
        for i in 0 ..< colors.count {
            let colorRef = colors[i].CGColor
            let colorComponents = CGColorGetComponents(colorRef)
            let numComponents = CGColorGetNumberOfComponents(colorRef)
            if colorSpace == nil {
                colorSpace = CGColorGetColorSpace(colorRef)
            }
            for j in 0 ..< numComponents {
                let component = colorComponents[j]
                components.append(component)
            }
        }

        if let colorSpace = colorSpace {
            let gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, locations.count)
            CGContextDrawRadialGradient(ctx, gradient, startCenter, startRadius, endCenter, endRadius, CGGradientDrawingOptions.DrawsAfterEndLocation)

        }
    } 
}
}

example

StuartM
  • 6,743
  • 18
  • 84
  • 160
  • You could try setting the transform on the layer (e.g. `CGAffineTransformMakeScale(1.5, 1.0)`). It's not really altering the gradient itself, just stretching the layer, but that might be OK depending on your use case. – Eric Galluzzo Jan 05 '16 at 12:48
  • We already use a transform to show the view itself though. Can the transform be applied to the layer only? – StuartM Jan 05 '16 at 12:52
  • Yes. See here: https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CALayer_class/#//apple_ref/occ/instp/CALayer/transform. The `transform` property on a `CALayer` is of type `CATransform3D`, though, not a `CGAffineTransform`, so you'll want to use `CATransform3DMakeScale` and friends instead. – Eric Galluzzo Jan 05 '16 at 12:55
  • Let me know if that works for you, and I'll convert my comment to an answer so that you can accept it. That way, other people searching for the same thing in future will know that the question has already been answered. – Eric Galluzzo Jan 05 '16 at 13:39
  • Yes it certainly does, I didn't even think about applying a transform my first thought was the shape itself but it works as expected. I'll accept as answer and see if any other suggestions arise. Thanks – StuartM Jan 05 '16 at 13:41
  • OK, cool. I've been doing a bunch of stuff with transforms recently, so it sprang to mind immediately for me. Whether or not it's the best solution is another question, though.... :) You could always try filling an oval path with a gradient color or something, but that sounds fiddly. – Eric Galluzzo Jan 05 '16 at 13:43

1 Answers1

3

One way to do it would be to set your layer's transform by scaling the X up by some factor. For example:

layer.transform = CATransform3DMakeScale(1.5, 1.0)

Not sure if that's the best solution or not, but it should work!

Eric Galluzzo
  • 3,191
  • 1
  • 20
  • 20