[Core Animation] What should you know about shadows?

Yevhenii Peteliev
Prototypr
Published in
5 min readMay 28, 2018

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).

CATextLayer with colored shadow

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 range 0.0 (invisible) to 1.0 (opaque). The default value of this property is 0.0.
How shadowOpacity property works
  • shadowColor : the color of the layer’s shadow. The type of this property is CGColor?, just like the backgroundColor and borderColor 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).
How 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 is 3.0.
How 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).
How 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.

The layer shadow follows the exact outline of the layer backing image

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.

The masksToBounds property clips both shadow and content

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!

Clip only layer content, shadow looks pretty

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.

CALayer with an image as contents

We want to clip it using CAShapeLayer as mask.

Incorrect shadow when using mask property

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!

Gorgeous shadow in masked layer

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.

Different shadow shapes applied to the same layer image

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.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in Prototypr

Prototyping, UX Design, Front-end Development and Beyond 👾 | ✍️ Write for us https://bit.ly/apply-prototypr

Written by Yevhenii Peteliev

Senior Research Engineer in TR&D at MacPaw

Responses (1)

Write a response

Hi, great article on shadows. I am wondering how did you get the shadow to work on catextlayer. I have tried everything and it doesn’t work. It works on UILabel or UITextView but not CATextLayer

--