在 NSView 中编写

Writing in NSView

我正在尝试在 NSView canvas 中呈现文本。我需要写三行文字,忽略其他内容。 String.draw(in:withAttributes) 与提供的 rect 似乎完美地做到这一点。我的代码如下所示:

func renderText(_ string:String, x:Double, y:Double, numberOfLines: Int, withColor color:Color) -> Double {
    let font = NSFont.boldSystemFont(ofSize: 11)
    let lineHeight = Double(font.ascender + abs(font.descender) + font.leading)
    let textHeight = lineHeight * Double(numberOfLines) + font.leading // three lines
    let textRect = NSRect(x: x, y: y, width: 190, height: textHeight)
    string.draw(in: textRect, withAttributes: [NSFontAttributeName: font, NSForegroundColorAttributeName: color])
    return textHeight
}

renderText("Lorem ipsum...", x: 100, y: 100, numberOfLines: 3, withColor: NSColor.white)

没有调整,我只渲染了两行文本:

我遵循这些准则:https://developer.apple.com/library/content/documentation/TextFonts/Conceptual/CocoaTextArchitecture/FontHandling/FontHandling.html#//apple_ref/doc/uid/TP40009459-CH5-SW18

我错过了什么?

我会尝试在 textHeight 中添加一个小的增量 -- 双精度非常准确。

最终,您的文本通过调用构成 Cocoa 文本架构的 类 显示在屏幕上,因此直接从这些 [=17] 获取有关行高的信息是有意义的=].在下面的代码中,我创建了一个 NSLayoutManager 实例,并设置其排字器行为 属性 以匹配由函数 drawInRect:withAttributes: 创建的机器最终使用的排字器的值。调用布局管理器的 defaultLineHeight 方法然后为您提供所需的高度值。

lazy var layoutManager: NSLayoutManager = {
    var layoutManager = NSLayoutManager()
    layoutManager.typesetterBehavior = .behavior_10_2_WithCompatibility
    return layoutManager
}()

func renderText(_ string:String, x:Double, y:Double, numberOfLines: Int, withColor color:NSColor) -> Double {
    let font = NSFont.boldSystemFont(ofSize: 11)
    let textHeight = Double(layoutManager.defaultLineHeight(for: font)) * Double(numberOfLines)
    let textRect = NSRect(x: x, y: y, width: 190, height: textHeight)
    string.draw(in: textRect, withAttributes: [NSFontAttributeName: font, NSForegroundColorAttributeName: color])
    return textHeight
}

您正在将文本写入精确的排版边界,但系统可能会调整屏幕显示文本的大小以使文本更清晰(例如,将屏幕字体替换为矢量字体)。使用精确的排版边界也会导致上升或下降超出边界的字符出现问题。例如 "A-ring" 字符或带有重音符号的大写字母 E。

要使用将在其中绘制的 CGContext 规则查找文本的边界,我建议 boundingRectWithSize:options:context:(对于 NSAttributedString)和 boundingRectWithSize:options:attributes:context:(对于 NSString)