Search code examples
swiftuiviewsubviewcashapelayer

Adding a CAShapeLayer to a subView


I trying to add a CAShapeLayer to a smaller UIView on the main view (single view application). I have the shape Layer animated and reacting to touch gesture to start drawing it. But it is drawn from the center of the main view and I need to be able to move it and constrain it for layout purposes. I have seen another post which seemed to have the same issues but i think i have confused myself more. I have the below code in the viewDidLoad function on the main ViewController.

It is a test project i am playing with to add new functionality to my existing app once I have it working.

I have tried adding a UIView in the MainStoryBoard of the project and adding linking it to the ViewController.swift file (control drag) to create an outlet then adding both shapeLayer & trackLayer to the UIView.

Code below

@IBOutlet weak var gaugeView: UIView!


override func viewDidLoad() {
    super.viewDidLoad()

    let centre = view.center

    let circularPath = UIBezierPath(arcCenter: centre, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)

    // Track Layer Under Gauge
    trackLayer.path = circularPath.cgPath
    trackLayer.strokeColor = UIColor.lightGray.cgColor
    trackLayer.lineWidth = 10
    trackLayer.fillColor = UIColor.clear.cgColor
    //view.layer.addSublayer(trackLayer)
    gaugeView.layer.addSublayer(trackLayer)

    // Animated Circular Guage
    shapeLayer.path = circularPath.cgPath
    shapeLayer.strokeColor = UIColor.green.cgColor
    shapeLayer.lineWidth = 10
    shapeLayer.lineCap = .round
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeEnd = 0
    //view.layer.addSublayer(shapeLayer)
    gaugeView.layer.addSublayer(shapeLayer)
  }

Once I have the app in the simulator it draws and animates the circle when the view.layer.addSubLayer is not commented out but will not add it to the UIView container with the gaugeView.layer.addSubView is in there.

Screen dump of the main storyboard

Screen dump once let center = gaugeView.center updated..


Solution

  • You need to set the center to gaugeView center instead of view.center here,

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let centre = CGPoint(x: gaugeView.frame.width/2, y: gaugeView.frame.height/2)
        ...
    }
    

    Note: While using Autolayout, viewDidLoad is never the right place to use frame of a subView that is not yet laid out by the autolayout. Best place to get and use the frame is viewDidLayoutSubviews.