使用属性文本在自定义 UILabel 中定位字符坐标
Posted
技术标签:
【中文标题】使用属性文本在自定义 UILabel 中定位字符坐标【英文标题】:Locate character coordinate in Custom UILabel with attributedText 【发布时间】:2017-05-26 11:18:13 【问题描述】:我需要在我的 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)
但不幸的是,我不能真正使用此代码,因为实际 GlyphRange 询问的是 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 中只有 1 行时才准确)
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
我在这个新代码中遗漏了什么吗?它快完成了
【问题讨论】:
可以告诉我们您搜索字符坐标的目的吗? 为什么var glyphRange: NSRange
。在Objective-C中,它使用&glyphRange
,所以layoutManager.characterRange()
的方法实际上是给它一个值。这就是为什么。这与 [myUIColor getRed:&red green:&green blue:&blue alpha:&alpha];
使用的“逻辑”相同。
@elk_cloner 我需要在我的特定角色上方画和弦,例如:“我爱上了你的 [G] 形状”我必须在 s 的顶部画G
来自“形状”@Larme 的词是的,我知道方法是 layoutManager.characterRange()
,但我很困惑如何填充实际 GlyphRange 参数?
How do I locate the CGRect for a substring of text in a UILabel?的可能重复
【参考方案1】:
更容易解决编译错误的方法是使用这个:
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
的解决方案,我会很感兴趣。
【讨论】:
我觉得只要得到预期的结果就可以了,明天我会试试这个 我已经尝试过 UITextView ,但如果有 2 行或更多行,它仍然无法获得准确的位置。我已经更新了我的代码,所以也许我仍然错过了什么? @thm以上是关于使用属性文本在自定义 UILabel 中定位字符坐标的主要内容,如果未能解决你的问题,请参考以下文章
在自定义单元格中调整 iOS 7.1 中的 UILabel 大小
在 UITableViewCell 内动画 UILabel 文本更改
我是不是需要在自定义 UIView 中使用单独的 UILabel 才能在 UITableViewCell 中有单独的 UILabel 行?