CATextLayer 和 NSTextView 的相同 NSAttributedString 的不同字体输出
在 macOS 中,对 CATextLayer 和 NSTextView 使用相同的 NSMutableAttributedString 似乎会给出不同的渲染结果。 NSTextView
的字体比 CATextLayer
稍大。这种行为似乎发生在任何类型的字体结构(NSFont
、CTFontCreateWithName
等)提供给控件的情况下。当控件默认为系统字体时,即使不定义字体也会导致这种情况发生。这是一个将作为 Playground 运行的精简片段。它在左侧创建一个 CATextLayer ,在右侧创建一个 NSTextView 。使用完全相同的字体和字符串。有人解决这个问题了吗?
import Cocoa
let attributes = [NSAttributedString.Key.font: NSFont(name: "Helvetica", size: 23.0)!,
NSAttributedString.Key.foregroundColor: NSColor.gray]
let theString = NSMutableAttributedString(string: "The Quick Brown Fox Jumped Over The Lazy Dogs Back", attributes: attributes)
var parentView = NSView(frame: NSRect(origin: NSPoint(x: 0, y: 0), size: CGSize(width: 300, height: 300)))
// create CATextLayer - left side
var textLayer = CATextLayer()
textLayer.isWrapped = true
textLayer.contentsScale = NSScreen.main!.backingScaleFactor
textLayer.backgroundColor = CGColor.white
textLayer.foregroundColor = CGColor.black
textLayer.string = theString
var layerView = NSView(frame: NSRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 90, height: 300)))
layerView.wantsLayer = true
layerView.layer = textLayer
parentView.addSubview(layerView)
// create NSTextView - right side
var textView = NSTextView(frame: NSRect(origin: NSPoint(x: 100, y: 0), size: CGSize(width: 90, height: 300)))
textView.textStorage?.setAttributedString(theString as NSAttributedString)
parentView.addSubview(textView)
// final display
parentView
In macOS using the same NSMutableAttributedString
for a CATextLayer
and a NSTextView
seems to give different rendering results. The NSTextView
has a slightly larger font than a CATextLayer
. This behavior seems to occur with any type of font structure (NSFont
, CTFontCreateWithName
, etc) fed to the controls. Even not defining a font will cause this to happen when the controls default to the system font. Here's a distilled down snippet that will run as a Playground. It creates a CATextLayer
on the left side and a NSTextView
on the right side. Uses the exact same font and string. Anyone solved this one yet?
import Cocoa
let attributes = [NSAttributedString.Key.font: NSFont(name: "Helvetica", size: 23.0)!,
NSAttributedString.Key.foregroundColor: NSColor.gray]
let theString = NSMutableAttributedString(string: "The Quick Brown Fox Jumped Over The Lazy Dogs Back", attributes: attributes)
var parentView = NSView(frame: NSRect(origin: NSPoint(x: 0, y: 0), size: CGSize(width: 300, height: 300)))
// create CATextLayer - left side
var textLayer = CATextLayer()
textLayer.isWrapped = true
textLayer.contentsScale = NSScreen.main!.backingScaleFactor
textLayer.backgroundColor = CGColor.white
textLayer.foregroundColor = CGColor.black
textLayer.string = theString
var layerView = NSView(frame: NSRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 90, height: 300)))
layerView.wantsLayer = true
layerView.layer = textLayer
parentView.addSubview(layerView)
// create NSTextView - right side
var textView = NSTextView(frame: NSRect(origin: NSPoint(x: 100, y: 0), size: CGSize(width: 90, height: 300)))
textView.textStorage?.setAttributedString(theString as NSAttributedString)
parentView.addSubview(textView)
// final display
parentView
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
最终裁决是 - NSTextView 和 CATextLayer 将以不同的方式呈现。 Apple 是这样说的:
“这是一个有趣的问题,我之前与其他开发人员讨论过这个问题。是的,你是对的。CATextLayers 内部的文本渲染与 NSTextView 中的文本渲染不同。我之前曾与工程人员讨论过这些差异我认为没有办法解决您使用 CATextLayer 提出的问题。原因如下:
绘制到 CATextLayer 的属性字符串使用与常规属性字符串不同的属性 - https://developer.apple.com/documentation/coretext/styling_attributed_strings。使用一些常规属性字符串属性,因此您会看到某些字符串似乎可以工作,但不支持常规属性字符串使用的某些属性,例如删除线文本。不支持。
CATextLayer 的大小和间距概念与绘制到常规图层时不同。这是没有记录的,我不知道如何将这些差异与 NSTextView 输出相协调。
所以,总而言之,是的,由于上述原因,我希望有时您绘制到 CATextLayer 的任何内容看起来都会与您在 NSTextView 内看到的绘制内容有所不同。这些差异没有记录在案,而且我们没有论坛来映射 CATextLayer 和 NSTextView 中绘制的文本。我建议改用图层支持的视图。”
The final ruling is - NSTextView and CATextLayer are going to render differently. Here is what Apple says:
"This is an interesting question and I have visited this before with other developers. Yes, you are correct. The text rendering inside of CATextLayers is different than in an NSTextView. I have talked with engineering about these differences before and I do not think there is a solution to the problem you have posed using CATextLayer. Here is why:
Attributed strings drawn to a CATextLayer use different attributes than regular attributed strings. These are described here - https://developer.apple.com/documentation/coretext/styling_attributed_strings. There is some pairity with some of the regular attributed string attributes so you'll see some strings will seem to work, but some of the atrributes used by regular attributed strings are not supported. For example, strike-through text is not supported.
CATextLayer also has a different concept of sizing and spacing than when drawing to regular layers. This is undocumented and I do not know how to reconcile these difference with NSTextView output.
So, in summary, yes, for the reasons mentioned above, I expect that sometimes whatever you are drawing to CATextLayer will look different than what you are seeing drawn inside of an NSTextView. These differences are not documented and we do not have a forumula to map between text drawn in CATextLayer and NSTextView. I recommend using a layer-backed view instead."