aFella
aFella

Reputation: 205

Getting frame from graphed UIBezierPath in Swift

I have created a graph drawing points and creating a UIBezierPath between those points, but now I want to add a gradient to the plotted lines (similar to picture). The issue is I need a frame for the CAGradientLayer, which I do not know how to create given the plotted lines on a UIView. I have a stored array of CGPoint which contains all the points that are graphed, is there a way to create frame for the gradient with that array? Anyone know what to do here?

contains all points graphed

var graphedInvestedPoints = [CGPoint]()

func addGradient(){
        let colorTop = UIColor(hexString: blueHexString)
        let colorBottom = UIColor.white
        
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorTop, colorBottom]
        gradientLayer.locations = [0.0, 1.0]
        //gradientLayer.frame = ?
        self.layer.insertSublayer(gradientLayer, at: 0)
    }

Current design enter image description here

desired design with gradient enter image description here

Upvotes: 0

Views: 306

Answers (1)

DonMag
DonMag

Reputation: 77682

Here is one simple example, using a masked gradient layer.

Use your graphedInvestedPoints to create the shape of the graph, apply that as the .path property of a CAShapeLayer and then apply that layer as the .mask property of a CAGradientLayer:

class GradientPathView: UIView {
    
    let gradientLayer = CAGradientLayer()
    let shapeLayer = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() -> Void {
        
        layer.addSublayer(gradientLayer)

        // can be any opaque color
        shapeLayer.fillColor = UIColor.white.cgColor
        
        self.backgroundColor = .clear
        
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let path = UIBezierPath()
        
        var pt: CGPoint = .zero
        
        pt.x = 0
        pt.y = bounds.maxY

        // move to bottom-left corner           
        path.move(to: pt)
        
        pt.y = bounds.maxY * 0.75
        
        // add line up left side to first point on the graph line
        path.addLine(to: pt)
        
        // let's add 20 points across the X-axis
        //  decrementing Y to make an upward curve
        
        let xInc: CGFloat = bounds.maxX / 20.0
        var yInc: CGFloat = 1.0
        
        for _ in 1...20 {
            pt.x += xInc
            pt.y -= yInc
            path.addLine(to: pt)
            yInc += 0.75
        }
        
        pt.x = bounds.maxX
        pt.y = bounds.maxY
        
        // add line to bottom-right corner
        path.addLine(to: pt)
        
        // close the path (bottom-right to bottom-left corners)
        path.close()
        
        shapeLayer.path = path.cgPath
        
        gradientLayer.frame = bounds
        
        let topColor: UIColor = .systemBlue
        let botColor: UIColor = .white
        
        gradientLayer.colors = [topColor.cgColor, botColor.cgColor]
        
        // adjust startPoint / endPoint (or .locations) as desired
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
        gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)

        // apply mask to gradient layer
        gradientLayer.mask = shapeLayer

    }
    
}

Output on a 240 x 240 view (the red dashed-outline is just there to show the frame of the view):

enter image description here

Upvotes: 0

Related Questions