在 UILabel 的 draw#rect 中获取字形 boundingRect

Getting a glyph boundingRect in draw#rect in UILabel

使用 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)
    }

绿色方块不正确 - 它应该更像这些红色方块!

似乎存在一些问题:

怎么办?

郑重声明,我的总体目标是根据实际字形框移动字形(当然 "y"、"X" 等不同)。但总的来说,有很多有用的理由来了解一个字形的盒子。

原来这道题的答案好像是:

事实上,不管是否令人惊讶,您基本上没有 访问 UILabel 中的字形信息。

实际上,您无法在 UILabel 中获得那些字形“实际形状”。

尤其是 RobN。指出,一项调查表明,在 UILabel 中,_drawTextInRect:baselineCalculationOnly 完成了工作,那是一大堆临时代码。

情况的总结似乎是 UILabel 简单地早于 NSLayoutManager / Core Text 并且(到目前为止)只是简单地不使用那些现代系统。

只有那些现代系统才能给你这个...

...可以访问 glyph-by-glyph 个形状。

你原来的问题有点毫无疑问,因为它说了两个完全相反的事情。

  • 一方面你说UILabel.

  • 另一方面,您使用 NSLayoutManager 和 NSTextStorage 以及 NSTextContainer 等术语 — TextKit 堆栈。

这些是相反的,因为 UILabel 不是用 TextKit 堆栈绘制的。所以你要求做的就像试图用磁铁吸起一张纸;磁铁确实能举起东西,但它们举起的是磁性材料,纸不是其中之一。可以肯定的是,UILabel 必须以某种确定性的方式进行绘制,但是 什么 这种方式是完全未知且不透明的,并且与 TextKit 无关。

另一方面,UITextView,或者您自己使用 TextKit 绘制的视图,确实使用 TextKit,现在所有 TextKit 工具都适用。因此,如果此 一个 UITextView(或您使用 TextKit 自己绘制的视图),那么您要执行的操作会简单得多。

这不需要对界面的外观做太多改变。可以使 UITextView 的行为很像 UILabel(使其不可编辑和不可滚动),但重要的区别是整个文本工具包堆栈是直接公开的。这就是我要开始的地方。我是那些更喜欢 使用 框架而不是 对抗 框架的人之一。