Swift version: 5.10
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: [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))
}
SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure and A/B test your entire paywall UI without any code changes or app updates.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Available from iOS 10.0
This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.
Link copied to your pasteboard.