Bytes of Bits
Published in

Bytes of Bits

Swift Tip: Adding Rounded Corners and Shadows to a UIView

Why things that seem easy are hard

The Backstory

I’ve been working on an application for a couple of years and received a simple design request: Round the corners on a view and add a drop shadow. Easy right?

// set the corner radius
layer.cornerRadius = 6.0
layer.masksToBounds = true
// set the shadow properties
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 1.0)
layer.shadowOpacity = 0.2
layer.shadowRadius = 4.0

WRONG!
If you’ve tried this before, you know exactly what happens. The corners will be rounded, but the shadow will be missing. If you set masksToBounds to false, the shadow will appear, but the corners will not be rounded.

CALayerWhyAreYouDoingThisToMe

The reason why is actually a bit obvious in hindsight, layer.masksToBounds = true clips everything outside of the layer. A shadow will be drawn outside of the layer, thus it is clipped, too. So, we cannot use the same layer for both of these effects.

The Solution

I’ll share what I found to be the path of least resistance. I opted to create an inner containerView pinned to the edges of the parent view. The shadow is applied to the parent view’s layer, while the rounded corners are applied to the containerView. Then, just add all content to the containerView and be on your way.

I’m certain this can also be accomplished using sublayers and masks, but this has some friction when using AutoLayout since we don’t know the size of the view when it’s laid out. That would require overriding layoutSubviews in the view or viewDidLayoutSubviews in the view controller in order to update the layer paths, but frankly, that’s more effort than it is worth for something so seemingly trivial.

Checkout the gist below. It’s well commented, so it should be easy to follow.

The Result

Update!

I stumbled on a StackOverflow post (of course) and found an alternative solution that you can use to avoid adding subviews. The magic happens with:shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath

The layoutSubviews method

If you have other solutions or suggestions, I would love to hear them! Thanks for reading and I hope this helps!

--

--

Tech, Swift, Audio and Whatever Else

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store