Why is the following code not drawing a string in a macOS application?
class MyLayer: CALayer {
override func draw(in ctx: CGContext) {
let font = NSFont.systemFont(ofSize: 18)
let text = "TEXT"
let textRect = CGRect(x: 100, y: 100, width: 100, height: 100)
text.draw(in: textRect, withAttributes: [.font: font])
}
}
CALayer
‘s draw(in:)
method is built on top of Core Graphics. All Core Graphics drawing functions take a CGContext
as an argument (or, in Swift, are methods on CGContext
). That’s why Core Animation passes a CGContext
to your draw(in:)
method.
However, the draw(in:withAttributes:)
method on String
is not part of Core Graphics. It is part of AppKit. AppKit’s drawing methods don’t operate directly on a CGContext
. They operate on an NSGraphicsContext
(which wraps a CGContext
). But, as you can see from the draw(in:withAttributes:)
method, AppKit’s drawing functions don’t take an NSGraphicsContext
argument and aren’t methods on NSGraphicsContext
.
Instead, there’s a global (per-thread) NSGraphicsContext
. The AppKit drawing methods use this global context. Since you’re writing code down at the Core Animation level, AppKit didn’t set up a global NSGraphicsContext
for you. You need to set it up yourself:
class MyLayer: CALayer {
override func draw(in ctx: CGContext) {
let nsgc = NSGraphicsContext(cgContext: ctx, flipped: false)
NSGraphicsContext.current = nsgc
let font = NSFont.systemFont(ofSize: 18)
let text = "TEXT"
let textRect = CGRect(x: 100, y: 100, width: 100, height: 100)
text.draw(in: textRect, withAttributes: [.font: font])
}
}