【发布时间】:2019-07-08 13:23:05
【问题描述】:
使用 Swift,我想在 UILabel 中的 draw#rect 中获取字形的 boundingRect。
UILabel 已经具有大小(例如在示例中为 300x300)和质量,例如文本居中。
class RNDLabel: UILabel {
override func draw(_ rect: CGRect) {
let manager = NSLayoutManager()
let store = NSTextStorage(attributedString: NSAttributedString(
string: text!,
attributes: [NSAttributedString.Key.font: font]))
store.addLayoutManager(manager)
let textContainer = NSTextContainer(size: rect.size)
// note, intrinsicContentSize is identical there, no difference
manager.addTextContainer(textContainer)
let glyphRange = manager.glyphRange(
forCharacterRange: NSRange(location: 0, length: 1),
actualCharacterRange: nil)
let glyphRect = manager.boundingRect(
forGlyphRange: glyphRange, in: textContainer)
print("glyphRect \(glyphRect)")
...context?.addRect(glyphRect), context?.drawPath(using: .stroke)
super.draw(rect)
}
绿色方块不正确 - 它应该更像这些红色方块!
似乎有很多问题:
我做的 layoutManager 肯定应该获得 UILabel 的品质,例如“居中文本”? (不过,我相信您实际上不能直接访问 UILabel 的 layoutManager 吗?)
我们应该使用类似 CTLineGetOffsetForStringIndex 的东西吗?这甚至可能在draw#rect中
请注意,除了没有正确的偏移量外,绿色框似乎还是错误的高度。 (它看起来更像是一个普通的旧的 intrinsicContentSize 而不是字形边界框。)
怎么做?
为了记录,我的总体目标是根据实际的字形框(当然对于“y”、“X”等不同)来移动字形。但总的来说,了解字形的框有很多有用的理由。
【问题讨论】:
-
很简单,TextKit 堆栈与 UILabel 没有直接关系的问题不是吗? UILabel 绘图不是 TextKit 绘图。如果这是一个 UITextView,或者只是一个您使用 TextKit 自己绘制的视图,那么您要求做的事情会更加直接。
-
是的,但是您将很难找出偏移量是多少。 “你会认为有办法” 不,我不会。也许你会这么想。就个人而言,如果我有一个像拖动字形这样的目标,我不会从 UILabel 开始。我是那些喜欢使用框架而不是对抗它的人之一。
-
基本上,是的。可以使 UITextView 的行为与 UILabel 非常相似(使其不可编辑和不可滚动),但重要的区别是整个文本工具包堆栈直接公开。这就是我要开始的地方。当然,你做什么取决于你。
-
"他们不会在 UILabel 中公开 layoutManager。"为什么你认为 UILabel 有一个布局管理器?我没有看到有人使用 lldb 或 Hopper。我可能会遗漏一些东西,但我不会特别期望 Apple 会改造 UILabel 以使用 NSLayoutManager。这是可能的,但你有理由期待这是真的吗?反编译
drawText(in:),好像是调用textRect(forBounds:),好像是手工布局。我没有看到任何布局管理器。 -
过去我已经构建了您所描述的几次;我总是用 Core Text 完成布局。如果我今天再写一次,也许我会使用 TextKit。但我不明白你为什么要在 UILabel 上构建它。如果只是出于好奇,那就太好了,但我会花一些时间在 Hopper 中看看 UILabel 是如何在幕后工作的。它主要基于 CoreGraphics 和 NSAttributedString,而不是 CoreText 或 NSLayoutManager。
标签: ios swift drawrect nslayoutmanager