0

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?

abc123
  • 8,043
  • 7
  • 49
  • 80
  • 1
    Impossible. If it has rounded corners and clips to them, it cannot have a shadow. See https://stackoverflow.com/a/57351560/341994 for a trick you can use. – matt Nov 25 '20 at 02:23
  • 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 Nov 25 '20 at 13:51
  • @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 Nov 25 '20 at 14:35

1 Answers1

1

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]
matt
  • 515,959
  • 87
  • 875
  • 1,141