使用attributedText在Custom UILabel中找到字符坐标

时间:2017-05-26 11:18:13

标签: ios swift3 uilabel glyph nslayoutmanager

我需要在我的UILabel中找到我的角色位置(它有ParagraphLineSpacing和带有多线的AttributedText),

我有我的角色索引,但现在我无法从我的索引获得X和Y坐标。

我找到了这个http://techqa.info/programming/question/19417776/how-do-i-locate-the-cgrect-for-a-substring-of-text-in-a-uilabel

我翻译成我的Swift 3.1代码

func boundingRect(forCharacterRange range: NSRange) -> CGRect {

    let textStorage = NSTextStorage(attributedString: self.attributedText!)
    let layoutManager = NSLayoutManager()
    textStorage.addLayoutManager(layoutManager)
    let textContainer = NSTextContainer(size: bounds.size)
    textContainer.lineFragmentPadding = 0
    layoutManager.addTextContainer(textContainer)
    var glyphRange: NSRange
    // Convert the range for glyphs.

    layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: glyphRange)
    return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)

}

但是,不幸的是,我无法真正使用此代码,因为actualGlyphRange询问NSRangePointer,而不是NSRange,所以我将我的翻译代码更改为

func boundingRect(forCharacterRange range: NSRange) -> CGRect {

    let textStorage = NSTextStorage(attributedString: self.attributedText!)
    let layoutManager = NSLayoutManager()
    textStorage.addLayoutManager(layoutManager)
    let textContainer = NSTextContainer(size: bounds.size)
    textContainer.lineFragmentPadding = 0
    layoutManager.addTextContainer(textContainer)
    //var glyphRange: NSRange

    let a = MemoryLayout<NSRange>.size
    let pointer:NSRangePointer = NSRangePointer.allocate(capacity: a)
    layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: pointer)
    return layoutManager.boundingRect(forGlyphRange: range, in: textContainer)
}

我不明白

 var glyphRange: NSrange 

用法,所以我删除它,现在代码工作,但结果是60%不准确,尤其是当我的角色位于第二行或第三行时。我在这里弄乱了翻译吗?或者有没有更好的方法来准确地获得我的角色坐标?

我用

NSMakeRange(index, 1) 

我的参数找到一个特定的角色

=======修订=======

我已尝试使用自定义UITextView访问其布局管理器,但不幸的是,如果有2行或更多行,则位置仍然不准确。 (只有在我的textView中只有一行时才准确)

class LyricTextView: UITextView {
  func boundingRect(forCharacterRange range: NSRange) -> CGRect {
    let inset = self.textContainerInset
    let rect = self.layoutManager.boundingRect(forGlyphRange: range, in: textContainer).offsetBy(dx: inset.left, dy: inset.top)

    return rect
  }
}

我在这段新代码中遗漏了什么?它差不多完成了

1 个答案:

答案 0 :(得分:0)

更容易解决编译错误的方法是使用它:

var glyphRange = NSRange()
layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange)

然而,当我尝试它时,我也只能在第一行获得正确的文本矩形。

如果您可以使用UITextView,则可以访问其布局管理器和文本容器:

@IBOutlet var textView: UITextView!
...

let rect = textView!.layoutManager.boundingRect(
    forGlyphRange: glyphRange, in: textView!.textContainer)

看来你还需要考虑文本视图的文本容器插入,所以以下方法让我在第二行找到文本的边界矩形:

let inset = textView!.textContainerInset
let rect = textView!.layoutManager.boundingRect(
    forGlyphRange: glyphRange, in: textView!.textContainer)
    .offsetBy(dx: inset.left, dy: inset.top)

如果有人找到适用于UILabel的解决方案,我会感兴趣。