2

I'm trying to clip my camera preview (UIView) inside a circle path but the mask I seems to not clip my view.

enter image description here

        let preview = cameraController!.previewLayer
        preview.translatesAutoresizingMaskIntoConstraints = false
        _view.translatesAutoresizingMaskIntoConstraints = false
        


        let path = UIBezierPath(arcCenter: CGPoint(x: _view.frame.size.width/2, y: _view.frame.size.height/2),
                                radius: _view.frame.size.width/2.5,
                                startAngle: CGFloat(0).toRadians(),
                                endAngle: CGFloat(360).toRadians(),
                                clockwise: false)
        
        path.reversing()
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.lineWidth = 5
        preview.layer.mask = shapeLayer
        preview.layer.addSublayer(shapeLayer)
        preview.clipsToBounds = true
        
        _view.addSubview(preview)

What I am missing here ?

nicover
  • 2,213
  • 10
  • 24

1 Answers1

1

Most of the set up was fine, just changed a few things to get it working:

func maskPreview()
{
    // No change from your code
    let path = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width/2,
                                               y: view.frame.size.height/2),
                            radius: view.frame.size.width/2.5,
                            startAngle: CGFloat(0).toRadians(),
                            endAngle: CGFloat(360).toRadians(),
                            clockwise: false)
    
    // Removed this, not sure it was needed
    // Add it back if needed
    //path.reversing()
    
    // No change
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    
    // This should not be transparent since we need
    // the camera preview to be seen through here
    shapeLayer.fillColor = UIColor.white.cgColor
    
    // No change
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.lineWidth = 5
    
    // No change
    previewView.layer.mask = shapeLayer
    
    // You do not need to add the shape layer as a sublayer
    // after defining it as your mask
    // previewView.layer.addSublayer(shapeLayer)
    
    // No change
    previewView.clipsToBounds = true
}

End result

Mask Camera Preview Circle Path UIBezierPath CAShapeLayer Clip UIView Preview Camera AVFoundation

Update to discuss about the mask layers color

The documentation for mask defines this behavior that the alpha channel determines what content, if any will be allowed to show.

mask

An optional view whose alpha channel is used to mask a view’s content.

Discussion

The view’s alpha channel determines how much of the view’s content and background shows through. Fully or partially opaque pixels allow the underlying content to show through but fully transparent pixels block that content.

The fill color is not the circle color as you rightly pointed out. You could change this and it would not matter as long as it is not clear color. It determines whether the mask renders the underlying view or not.

To actually add some color to this, I believe you cannot do it directly through the mask layer and you would need an intermediary layer.

Shawn Frank
  • 4,381
  • 2
  • 19
  • 29
  • Thanks for this Shawn can't understand why the fill color is white ? The fill color is not the circle color then – nicover Feb 08 '22 at 12:20
  • @nicover - I updated the answer with some notes from the documentation. – Shawn Frank Feb 08 '22 at 12:59
  • great thanks again. please one more thing if I want to update the radius value here let say on click/drag I must to re execute all of this code ? or can I update only a part ? for the radius – nicover Feb 08 '22 at 13:38
  • I think you can do something with `CABasicAnimation` - some insights here https://stackoverflow.com/questions/36459532/uiview-layer-mask-animate and it could be a good new question if you are unable to figure it out. – Shawn Frank Feb 08 '22 at 14:20
  • Thanks. regarding this question do you know why the stroke color is gone ? – nicover Feb 08 '22 at 15:18
  • 1
    @nicover - The border works the same as the fill color, that is, anything of the mask that is not transparent will be used to display pixels of the view below it. A quick test you can do is to make your `shapeLayer.fillColor = UIColor.clear.cgColor` clear again and I believe you will see the camera preview in the border only. If you want to add colors or border colors, I believe you will need to add another shape layer in addition to your mask - give it a go, if it is still proving too tricky, maybe open another question. – Shawn Frank Feb 08 '22 at 16:41