skip to Main Content

I have an image.cgImage that I set as the contents to a CAShapeLayer() but it’s not appearing. I force unwrap the image so I know that it definitely exists. The round shape appears but the image inside of it doesn’t.

let shapeLayer = CAShapeLayer()
var didSubviewsLayout = false

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if !didSubviewsLayout {
        didSubviewsLayout = true

        setupShapeLayer()
    }
}

func setupShapeLayer() {
    
    shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 200, y: 200, width: 50, height: 50), cornerRadius: 25).cgPath
    
    shapeLayer.strokeColor = nil
    
    shapeLayer.fillColor = UIColor.orange.cgColor
    
    shapeLayer.contents = UIImage(named: "myIcon")!.cgImage // this doesn't crash so the image definitely exists
    
    view.layer.addSublayer(shapeLayer)
}

2

Answers


  1. You could create the rounded path in a separate layer and add it as a mask to the layer that contains the image. Firstly, I would add a frame to the parent layer so that the image can be centred within the layer using contentsGravity.

    shapeLayer.frame = CGRect(x: 200, y: 200, width: 50, height: 50)
    
    shapeLayer.contents = UIImage(named: "myIcon")!.cgImage
            
    // Center the image within the layer
    shapeLayer.contentsGravity = .center
            
    // We can set the orange color here
    shapeLayer.backgroundColor = UIColor.orange.cgColor
    

    Then, create the layer that would have the rounded path and set it as a mask to the image layer:

    let maskLayer = CAShapeLayer()
            
    maskLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 50, height: 50), cornerRadius: 25).cgPath
            
    shapeLayer.mask = maskLayer
    

    Your modified code:

    func setupShapeLayer() {
        shapeLayer.frame = CGRect(x: 200, y: 200, width: 50, height: 50)
    
        shapeLayer.contents = UIImage(named: "myIcon")!.cgImage
            
        // Center the image within the layer
        shapeLayer.contentsGravity = .center
            
        // We can set the orange color here
        shapeLayer.backgroundColor = UIColor.orange.cgColor
            
        // Create mask layer
        let maskLayer = CAShapeLayer()
            
        maskLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 50, height: 50), cornerRadius: 25).cgPath
            
        shapeLayer.mask = maskLayer
            
        view.layer.addSublayer(shapeLayer)
    }
    
    Login or Signup to reply.
  2. The problem is that your shape layer has no size. You have not given it a frame, so it is just an invisible dot at the top right corner. Unfortunately, you can still see the shape, so you’re not aware of the fact that you’re doing this all wrong. But the content doesn’t draw, because the layer is just a dot, so it reveals your code’s feet of clay.

    So, in this case, change

    shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 200, y: 200, width: 50, height: 50), cornerRadius: 25).cgPath
    

    To

    shapeLayer.frame = CGRect(x: 200, y: 200, width: 50, height: 50)
    shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 50, height: 50), cornerRadius: 25).cgPath
    

    Incidentally, that is not how to draw a circle correctly, so if that’s your goal, stop it. Use ovalIn; that’s what it’s for. Complete example:

        let shapeLayer = CAShapeLayer()
    
        shapeLayer.frame = CGRect(x: 200, y: 200, width: 50, height: 50)
        shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 50, height: 50)).cgPath
        shapeLayer.strokeColor = UIColor.orange.cgColor
        shapeLayer.lineWidth = 4
        shapeLayer.fillColor = nil
        shapeLayer.contents = UIImage(named: "smiley")?.cgImage
    
        self.view.layer.addSublayer(shapeLayer)
    

    Result:

    enter image description here

    Note too that you are probably making this mistake with all your shape layers, not just this one, so you will want to go back through all the code in this app (or better, all the code you’ve ever written!) and write all your shape layers correctly. Layers need frames!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search