1

I refer to a previous problem (resolved) since it raised a new question:

I now have my linear gradient but I am not able to make it start at the center and end at the opposite side of my pie chart segment (UIBezierPath).

func arc(myRadius: CGFloat, myStartAngle: CGFloat, myEndAngle: CGFloat) {

    context?.saveGState()

    var finalRadius: CGFloat = myRadius
    (...)

    let myBezier = UIBezierPath()
    myBezier.move(to: center)
    myBezier.addArc(withCenter: center, radius: finalRadius, startAngle: myStartAngle, endAngle: myEndAngle, clockwise: false)
    myBezier.close()
    myColor.setFill()
    myBezier.fill()
    context?.addPath(myBezier.cgPath)

    context?.clip()

    let shape = CAShapeLayer()
    shape.frame = self.bounds
    shape.path = myBezier.cgPath
    shape.strokeColor = UIColor.black.cgColor
    shape.lineWidth = 0.5
    shape.fillColor = nil

    let grad = CAGradientLayer()
    grad.frame = self.bounds // I tried here myBezier.bounds without any success (I don't see any gradient)
    grad.colors = [UIColor.brown.cgColor, UIColor.yellow.cgColor]
    grad.locations = [0.0, 1.0]

    // StartPoint and endPoint not showing what I want...
    grad.startPoint = center
    grad.endPoint = CGPoint(x: centerX + cos(myStartAngle), y: centerY + sin(myStartAngle))

    let mask = CAShapeLayer()
    mask.frame = self.bounds
    mask.path = myBezier.cgPath
    mask.fillColor = UIColor.black.cgColor
    grad.mask = mask

    self.layer.addSublayer(grad)
    self.layer.addSublayer(shape)
    }

    context?.restoreGState()
}

Maybe I should go with a radial gradient starting from the center and I don't care about any segment, I just apply it on the mask and it should work. But I think there should be a way to apply a linear gradient to a specific frame in the view and set the start and endPoint to this frame. The problem is that it does not go the way I would like when trying to insert angles...

This is what I get:

enter image description here

Does anyone have an idea how I should change my CAGradientLayer to get a linear gradient starting at the center and ending at the arc (opposite side)?

Community
  • 1
  • 1
Trichophyton
  • 625
  • 5
  • 21

1 Answers1

0

grad.startPoint and grad.endPoint are defined as:

The point is defined in the unit coordinate space and is then mapped to the layer’s bounds rectangle when drawn.

You want:

grad.startPoint = CGPoint(x: center.x/self.bounds.width, y: center.y/self.bounds.height)
grad.endPoint = CGPoint(x: (center.x+(cos(myStartAngle)* finalRadius))/self.bounds.width, y: (center.y+(sin(myStartAngle)* finalRadius))/self.bounds.height)

BTW: a really good way to debug this is to comment out grad.mask = mask so you can see the entire gradient and see how start/end are working.

Here is code for a playground if you still have trouble getting it working

//: Playground - noun: a place where people can play

import UIKit
import QuartzCore

class Arc: UIView {
    public override init(frame: CGRect) {
        super.init(frame:frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        if let context = UIGraphicsGetCurrentContext() {
            let myBezier = UIBezierPath()
            let center = CGPoint(x:80, y:140)
            let r: CGFloat = 450
            myBezier.move(to: center)
            myBezier.addArc(withCenter: center, radius: r, startAngle: 0.1, endAngle: 0.5, clockwise: true)
            myBezier.close()
            UIColor.blue.setFill()
            myBezier.fill()
            context.addPath(myBezier.cgPath)
            context.clip()
            let shape = CAShapeLayer()
            shape.frame = self.bounds
            shape.path = myBezier.cgPath
            shape.strokeColor = UIColor.red.cgColor
            shape.lineWidth = 0.5
            shape.fillColor = nil

            let grad = CAGradientLayer()
            grad.frame = self.bounds // I tried here myBezier.bounds without any success (I don't see any gradient)
            grad.colors = [UIColor.black.cgColor, UIColor.white.cgColor]

            grad.startPoint = CGPoint(x: center.x/self.bounds.width, y: center.y/self.bounds.height)
            grad.endPoint = CGPoint(x: (center.x+(cos(0.1)*r))/self.bounds.width, y: (center.y+(sin(0.1)*r))/self.bounds.height)

            let mask = CAShapeLayer()
            mask.frame = self.bounds
            mask.path = myBezier.cgPath
            mask.fillColor = UIColor.black.cgColor
            grad.mask = mask

            self.layer.addSublayer(grad)
            self.layer.addSublayer(shape)
        }
    }
}

let v = Arc(frame: CGRect(x: 0, y: 0, width: 600, height: 600))
v.backgroundColor = .green
Lou Franco
  • 87,846
  • 14
  • 132
  • 192