How can I fill the inside of a UIBezierPath with Swift?

Viewed 119

I am trying to fill a UIBezierPath using Swift 5 but when I try to run my function to color the paths, I get many errors. None of them are fatal so the build succeeds, but the path is not drawn on the screen. I am attaching the relevant code and two of the errors. Thanks in advance.

func colorPaths() {    
                let path = leftCorner //Where leftCorner isa UIBezierPath

                let fillColor = UIColor.white
                fillColor.setFill()

                path.lineWidth = 1.0
                let strokeColor = UIColor.blue
                strokeColor.setStroke()

                path.fill()
                path.stroke()
            }

Errors:

2020-05-25 14:35:26.653308-0400 StatsApTBD[50679:10052723] [Unknown process name] CGContextSetFillColorWithColor: invalid context 0x0. Backtrace:
  <$s10StatsApTBD8HeatViewC08changeToD4MapsyyF10colorPathsL_yyF+94>
   <$s10StatsApTBD8HeatViewC08changeToD4MapsyyF+5247>
    <$s10StatsApTBD8HeatViewC8addMarksyyF+626>
     <$s10StatsApTBD8HeatViewC21viewDidLayoutSubviewsyyF+7831>
      <$s10StatsApTBD8HeatViewC21viewDidLayoutSubviewsyyFTo+43>
       <-[UIView(CALayerDelegate) layoutSublayersOfLayer:]+3013>
        <-[CALayer layoutSublayers]+255>
         <_ZN2CA5Layer16layout_if_neededEPNS_11TransactionE+517>
          <_ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE+80>
           <_ZN2CA7Context18commit_transactionEPNS_11TransactionEd+324>
            <_ZN2CA11Transaction6commitEv+643>
             <_afterCACommitHandler+160>
              <__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__+23>
               <__CFRunLoopDoObservers+430>
                <__CFRunLoopRun+1514>
                 <CFRunLoopRunSpecific+438>
                  <GSEventRunModal+65>
                   <UIApplicationMain+1621>
                    <main+75>
                     <start+1>                             1
2020-05-25 14:35:26.655966-0400 StatsApTBD[50679:10052723] [Unknown process name] CGContextSetStrokeColorWithColor: invalid context 0x0. Backtrace:
  <$s10StatsApTBD8HeatViewC08changeToD4MapsyyF10colorPathsL_yyF+175>
   <$s10StatsApTBD8HeatViewC08changeToD4MapsyyF+5247>
    <$s10StatsApTBD8HeatViewC8addMarksyyF+626>
     <$s10StatsApTBD8HeatViewC21viewDidLayoutSubviewsyyF+7831>
      <$s10StatsApTBD8HeatViewC21viewDidLayoutSubviewsyyFTo+43>
       <-[UIView(CALayerDelegate) layoutSublayersOfLayer:]+3013>
        <-[CALayer layoutSublayers]+255>
         <_ZN2CA5Layer16layout_if_neededEPNS_11TransactionE+517>
          <_ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE+80>
           <_ZN2CA7Context18commit_transactionEPNS_11TransactionEd+324>
            <_ZN2CA11Transaction6commitEv+643>
             <_afterCACommitHandler+160>
              <__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__+23>
               <__CFRunLoopDoObservers+430>
                <__CFRunLoopRun+1514>
                 <CFRunLoopRunSpecific+438>
                  <GSEventRunModal+65>
                   <UIApplicationMain+1621>
                    <main+75>
                     <start+1>                             1
2 Answers

Create a CAShapeLayer and set the path for the same like below.

let width: CGFloat = 200
let height: CGFloat = 200

let shapeLayer = CAShapeLayer()
shapeLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)

let path = leftCorner
shapeLayer.path = path
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.white.cgColor

Then add the above shapeLayer to your view.

yourView.layer.addSublayer(shapeLayer)

That should get your path to show on screen.

The issue there is that you are drawing at the view controller but it should be done in a UIView draw(_ rect: CGRect) method.

So you need to subclass a UIView, override the draw method and draw your bezier paths there:

import UIKit

class CanvasView: UIView {
    override func draw(_ rect: CGRect) {
        let bp = UIBezierPath(ovalIn: .init(origin: .zero, size: .init(width: 200, height: 200)))
        bp.lineWidth = 5
        UIColor.red.setFill()
        bp.fill()
        UIColor.yellow.setStroke()
        bp.stroke()
    }
}

Now you can add your CanvasView to your view controller view using the storyboard or programmatically:

override func viewDidLoad() {
    super.viewDidLoad()
    let drawingView = CanvasView(frame: view.frame)
    view.addSubview(drawingView)
}
Related