WWDC23 SALE: Save 50% on all my Swift books and bundles! >>

How to render shadows using NSShadow and setShadow()

Swift version: 5.6

Paul Hudson    @twostraws   

There are two ways to add shadows when rendering images: calling setShadow() and providing offset, blur, and color, or by using an NSShadow attached to an attributed string. Both have their own advantages, so both are worth trying.

First, here’s some example drawing code without a shadow:

let rect = CGRect(x: 0, y: 0, width: 512, height: 256)
let renderer = UIGraphicsImageRenderer(bounds: rect)

let img = renderer.image { ctx in

    let str = """
    He thrusts his fists
    Against the posts
    And still insists
    He sees the ghosts

    let attrs: [NSAttributedString.Key: Any] = [
        .font: UIFont.systemFont(ofSize: 36),
        .foregroundColor: UIColor.white

    let attributedString = NSAttributedString(string: str, attributes: attrs)
    attributedString.draw(in: rect.insetBy(dx: 50, dy: 50))

That draws some white text on a black background.

If we want to add a shadow effect to the text, we can use the setShadow method of the Core Graphics context we’re working with. For example, if you place this line before the draw() call at the end, you’ll make the text have a 5-point red glow:

ctx.cgContext.setShadow(offset: .zero, blur: 5, color: UIColor.red.cgColor)

The advantage of using setShadow() is that once you enable a shadow color, everything you draw has the same color – all text, all images, and all shapes.

When you’re done with the shadow and want normal rendering to resume, just use nil for the color value like this:

ctx.cgContext.setShadow(offset: .zero, blur: 0, color: nil)

The other way of drawing shadows is using NSAttributedString and the NSShadow class. This is an object you create and can attach to any attributed strings you want, giving you the flexibility to add shadowing to only certain parts of a string rather than the whole thing – something that setShadow() can’t do.

First, create an NSShadow instance like this:

let shadow = NSShadow()
shadow.shadowColor = UIColor.red
shadow.shadowBlurRadius = 5

That will create the same 5-point red glow as our earlier call to setShadow().

Now go ahead and put that into your attributed string dictionary using the .shadow key, like this:

let attrs: [NSAttributedString.Key: Any] = [
    .font: UIFont.systemFont(ofSize: 36),
    .foregroundColor: UIColor.white,
    .shadow: shadow

Here the end result will look identical to NSShadow, but as I said you now have the ability to shadow only parts of a string - or even add different shadows across the string.

Pro-tip: If you want to make your shadow stronger – to make it darker so that the color shows through more clearly – just draw your object repeatedly. For example, this will draw our attributed string five times to give it a really strong red glow:

for _ in 1...5 {
    attributedString.draw(in: rect.insetBy(dx: 50, dy: 50))
Save 50% in my WWDC23 sale.

SAVE 50% To celebrate WWDC23, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Available from iOS 10.0

Similar solutions…

About the Swift Knowledge Base

This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.

Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 3.5/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.