[Core Animation] What should you know about shadows?

Introduction
A shadow is an image painted underneath and offset from a graphics object. It mimics the effect of a light source cast on the graphics object. Shadows are used to indicate layering and priority (for example when a modal alert is presented in front of others view). Also, they are used for cosmetic purposes (to improve control appearance).

Little theory
CALayer has different properties for shadow configuration. The most significant are:
shadowOpacity
: the opacity of the layer’s shadow. The value of this property must be in the range0.0
(invisible) to1.0
(opaque). The default value of this property is0.0
.

shadowOpacity property works
shadowColor
: the color of the layer’s shadow. The type of this property is CGColor?, just like thebackgroundColor
andborderColor
properties. The default value of this property is an opaque black color (colored shadows are rare in real life and can look a bit strange).

shadowColor property works
shadowRadius
: the blur radius used to render the layer’s shadow. A value of zero creates a hard-edged shadow that exactly matches the shape of the view. A larger value creates a soft-edged shadow that looks more natural. The default value of this property is3.0
.

shadowRadius property works
shadowOffset
: the offset of the layer’s shadow. The type of this property is CGSize. Width controls the shadow’s horizontal offset, and the height controls its vertical offset. The default value of this property is(0.0, -3.0)
.

shadowOffset property works
Also, CALayer has a shadow
property. It assigns the NSShadow object as layer shadow. An instance of NSShadow created using the shadowColor
, shadowOffset
, shadowOpacity
and shadowRadius
properties of the view’s layer. The default value of this property is normally nil
.
Assigning a new shadow object to this property sets the corresponding shadow-related properties on the view’s layer. It is important to note that if the view
does not have a layer
, setting the value of shadow
property has no effect.
Shadow Clipping
The layer’s shadow derives from the exact shape of its contents
, not just the bounds
and cornerRadius
. To calculate the shape of the shadow, Core Animation looks at the backing image and sublayers (if exist). It uses these to create a shadow that perfectly matches the shape of the layer.

Important, you need to use a PNG image with an alpha component as backing image that includes an alpha mask.
Shadows Limitation
Layer shadows have a limitation when combined with clipping. The shadow is usually drawn outside the layer bounds.
Example 1: masksToBounds property.
If you enable the masksToBounds
property, the shadow will clip along with any other content that protrudes outside of the layer.

Look at the code below. Difference between two views is a value of the masksToBounds
property. Value of this property on the left view set to false
. A right view set masksToBounds
to true
.
This behavior is understandable from a technical perspective. It is unlikely to be the effect that you wanted. If you want to clip the contents and cast a shadow, you need to use two layers: an outer layer that just draws the shadow and an inner that has masksToBounds
enabled for clipping content. We need to update our code. Let’s do it!
Look at the picture below. We have a gorgeous shadow!

Example 2: Layer Masking.
You should know that mask is an optional layer whose alpha channel is used to mask the parent layer’s content. Layer mask also clips the shadow.
We have a simple layer with an image as contents
. Also, we add a shadow. Look at the picture below.

We want to clip it using CAShapeLayer as mask
.

Simple code example.
As you can see from the picture, the shadow is cropped. We need to change our code. Let’s do it!
And now we have a great shadow!

Also, you can read more about Layer Masking in my article.
Shadow Performance
So, we know that layer shadows are not always square. Shadow derives from the shape of the contents. This looks wonderful. You need to know that it’s very expensive to calculate shadow shape in real time particularly if the layer contains multiple sublayers with alpha-masked backing images. How can we keep our layer shadows and still have good performance?
So, if you know what the shape of your shadow needs to be, you can improve performance by specifying a shadowPath
property. The default value of this property is nil
, which causes the layer to use a standard shadow shape. If you specify a value for this property, the layer creates its shadow using the specified path instead of the layer’s composited alpha channel. So, we can use this property to determine the shape of shadow independently of the layer’s shape.

And what about programming code? All you need is to set up shadowPath
property.
Also for triangle shape.
Summary
To sum up, Core Animation makes easy to generate dynamic shadows and attach them to any shape. You need to set up them correctly, and that’s all. Don’t forget about performance 🐶. If you know what the shape of your shadow needs to be, you can use shadowPath
property to determine the shape of shadow independently of the layer’s shape.
Thanks for reading! I hope this information was useful for you. Please don’t forget to 💚 if you found this article useful.