0
votes

I'm trying to create something like this image except for those purple corners. Notice how the blue (shown as purple) contentView is not being clipped or masked by its parent containerView.

Card view

The requirements are to have a view which:

  1. Has rounded corners.
  2. Has a shadow.
  3. It's subviews don't leak outside of it or its corners.

Here is the code I'm playing around with and I'm not sure exactly how to get this to work.

let containerView = UIView(frame: CGRect(x: 300, y: 100, width: 200, height: 200))
containerView.backgroundColor = .green
containerView.layer.cornerRadius = 40
containerView.layer.shadowRadius = 50
containerView.layer.shadowOffset = .zero
containerView.layer.shadowColor = UIColor.red.cgColor
containerView.layer.shadowOpacity = 1
view.addSubview(containerView)

let backgroundLayer = CALayer()
backgroundLayer.frame = containerView.layer.bounds
backgroundLayer.backgroundColor = UIColor.black.cgColor
backgroundLayer.opacity = 0.5
backgroundLayer.cornerRadius = containerView.layer.cornerRadius
backgroundLayer.masksToBounds = true
containerView.layer.addSublayer(backgroundLayer)

let contentView = UIView(frame: containerView.bounds)
contentView.backgroundColor = .blue
contentView.alpha = 0.3

// Omitting this line will produce a green square with rounded corners
// and a red shadow.
containerView.addSubview(contentView)

Based on this example code, one of my more specific questions is why doesn't the backgroundLayer which sets masksToBounds = true, mask the view's subview?

1
Impossible. If it has rounded corners and clips to them, it cannot have a shadow. See stackoverflow.com/a/57351560/341994 for a trick you can use.matt
I don't think that's true because if you take the example code and delete the last section or line which adds the contentView as a subview, you'll see a green square with rounded corners with a red shadow.abc123
@matt I tried two views like the answer you linked and that definitely works. I was hoping to get this with a single view. I guess I don't understand why it can't happen, especially when one of the view's layer is masking to bounds.abc123

1 Answers

1
votes

Based on this example code, one of my more specific questions is why doesn't the backgroundLayer which sets masksToBounds = true, mask the view's subview?

Because the subview is the subview of the view, not of the backgroundLayer.

Views are layers. Clipping is masking. A layer masks its own drawing and that of its sublayers. The subview's layer is not a sublayer of the backgroundLayer. It is its sibling, not its child. Your view/layer hierarchy looks like this:

    containerView
     |          \
  [layer]   backgroundLayer
     |         (clips itself and its sublayers,
 contentView    but it has no sublayers)
     |
  [layer]