问题描述
我想获取 UILabel 上点击字符的索引.我已经对 UILabel 进行了子类化.在我的awakeFromNib() 我有这个:
I'd like to get the index for the tapped character on a UILabel. I've subclassed a UILabel. In my awakeFromNib() I have this:
layoutManager = NSLayoutManager()
textStorage = NSTextStorage(attributedString: self.attributedText)
textStorage.addLayoutManager(layoutManager)
textContainer = NSTextContainer(size: CGSizeMake(self.frame.size.width, self.frame.size.height))
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = self.numberOfLines
textContainer.lineBreakMode = self.lineBreakMode
textContainer.size = self.frame.size
layoutManager.addTextContainer(textContainer)
对于标签的前 5 个字符,它按照我希望的方式工作,就像我点击第一个字符一样,在 touchesEnded 中,我得到的索引为 0:
It is working how I want it to for the first 5 characters of the label, as in I tap the first character and in my touchesEnded I get an index of 0:
var touchCharacterIndex = layoutManager.characterIndexForPoint(touch.locationInView(self), inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
但是当我点击 UILabel 的前四个字符之后的任何地方时,我得到的是 4 或 0,这是不正确的.
But when I tap anywhere past the first four characters of the UILabel, I get either 4 or 0, which is incorrect.
谢谢,
更新
根据评论中的建议,我添加了以下内容:
From a suggestion in the comments, I've added this:
func updateTextStorage() {
if let attributedText = self.attributedText {
textStorage = NSTextStorage(attributedString: attributedText)
}
textStorage?.addLayoutManager(layoutManager)
textContainer = NSTextContainer(size: CGSizeMake(self.frame.size.width, self.frame.size.height))
textContainer?.lineFragmentPadding = 7
textContainer?.maximumNumberOfLines = self.numberOfLines
textContainer?.lineBreakMode = self.lineBreakMode
textContainer?.size = self.bounds.size
layoutManager.addTextContainer(textContainer!)
layoutManager.textStorage = textStorage
}
我在 layoutSubviews()
、awakFromNib
和 bounds
、frame
、 的 setter 中调用它>attributedText
和 text
.
I call this in layoutSubviews()
, awakFromNib
and the setters of bounds
, frame
, attributedText
and text
.
它现在给了我一些奇怪的索引,比如如果文本长度是 21,点击第一个字母会给我 6.
And it is now giving me some weird indexes, like if text length is 21, tapping the first letter gives me 6.
推荐答案
TLDR:你得到了一些奇怪的索引,因为你的 layoutManager
看到的字符串与你实际看到的不同在屏幕上.
TLDR: You are getting some weird indexes because the string seen by your layoutManager
is layed-out differently than the one you actually see on screen.
你得到了一些奇怪的索引:
You are getting some weird indexes from:
- (NSUInteger)characterIndexForPoint:(CGPoint)point
inTextContainer:(NSTextContainer *)container
fractionOfDistanceBetweenInsertionPoints:(nullable CGFloat *)partialFraction;
因为您自己的layoutManager
必须与系统UILabel
的内部layoutManager
同步.这意味着当您在标签上设置字体、大小等时,内部 layoutManager
知道这一点,因为它由 UILabel
处理,但是您的 layoutManager
实例没有.
because your own layoutManager
have to be in sync with the internal layoutManager
from the system UILabel
. Which mean when you set a font, size, etc. on your label, the internal layoutManager
knows about that because it's taken care by UILabel
, but your layoutManager
instance does not.
因此,您的 layoutManager 的seen"文本布局与屏幕上标签呈现的实际文本(我打赌是默认字体和大小)处于不同的位置.
So the text layout "seen" by your layoutManager is in a different position than the actual text rendered by the label on screen (default font and size I bet).
复杂的部分是保持这些属性同步,你可以做的是在你的属性文本上设置这些属性,如:
The complicated part is to keep those properties in sync, what you can do is set those on your attributed text like:
[mutableAttributedString addAttribute:NSFontAttributeName
value:self.font
range:NSMakeRange(0, mutableAttributedString.string.length)];
并将此属性字符串传递给您的 NSTextStorage
实例.这为我解决了所有问题.
And pass this attributed string to your NSTextStorage
instance. This fixed all the issues for me.
信息:为了帮助您调试,您可以使用 layoutManager
呈现字符串seen":
INFO: To help you debug you can render the string "seen" by your layoutManager
using this:
- (void)drawTextInRect:(CGRect)rect
{
[super drawTextInRect:rect];
[self.layoutManager drawGlyphsForGlyphRange:NSMakeRange(0, self.textStorage.length) atPoint:CGPointMake(0, 0)];
}
如果您看到 2 个字符串相互重叠并出现故障,这就是您的问题所在.如果您只能看到一个应该是因为它们完全对齐并且您很好!
If you see 2 strings layed-out on top of each other with some glitch this is your problem right there. If you can only see one that should be because they are perfectly aligned and your are good!
这篇关于从点击获取 UILabel 中的字符索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!