NEW! Master Swift design patterns with my latest book! >>

How to render shadows using NSShadow and setShadow()

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
    UIColor.black.set()
    ctx.fill(rect)

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

    let attrs: [NSAttributedStringKey: 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: [NSAttributedStringKey: 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))
}

Available from iOS 10.0

Did this solution work for you? Please pass it on!

Other people are reading…

About the Swift Knowledge Base

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

Want to build macOS apps?

Hacking with macOS delivers 18 awesome projects that teach you macOS development in no time – take control of your desktop today!

MASTER SWIFT NOW
Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Practical iOS 11 Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let me know!

Click here to visit the Hacking with Swift store >>