我想获取UILabel上点击字符的索引。我已经将UILabel子类化了。在我的awakeFromNib()中,我有这个:
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的索引:
var touchedCharacterIndex = layoutManager.characterIndexForPoint(touch.locationInView(self), inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
但是当我点击UILabel的前四个字符时,我得到4或0,这是不正确的。
谢谢,
更新
根据评论中的建议,我已经添加了这个:
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
,attributedText
和text
的制定者中将其称为。</ p>
它现在给了我一些奇怪的索引,比如文本长度是21,点击第一个字母给我6。
答案 0 :(得分:6)
TLDR:你得到了一些奇怪的索引,因为layoutManager
看到的字符串与你在屏幕上看到的字符串的布局不同。
你得到了一些奇怪的索引:
- (NSUInteger)characterIndexForPoint:(CGPoint)point
inTextContainer:(NSTextContainer *)container
fractionOfDistanceBetweenInsertionPoints:(nullable CGFloat *)partialFraction;
因为您自己的layoutManager
必须与系统layoutManager
中的内部UILabel
同步。这意味着当您在标签上设置字体,大小等时,内部layoutManager
知道这一点,因为它由UILabel
处理,但您的layoutManager
实例却没有。
因此,layoutManager的文本布局“ see ”与屏幕上标签所呈现的实际文本位于不同的位置(我打赌的默认字体和大小)。
复杂的部分是保持这些属性同步,你可以做的就是在你的属性文本中设置这些属性,如:
[mutableAttributedString addAttribute:NSFontAttributeName
value:self.font
range:NSMakeRange(0, mutableAttributedString.string.length)];
将此属性字符串传递给您的NSTextStorage
实例。这为我解决了所有问题。
信息:为了帮助您进行调试,您可以使用以下内容通过layoutManager
呈现字符串“ see ”:
- (void)drawTextInRect:(CGRect)rect
{
[super drawTextInRect:rect];
[self.layoutManager drawGlyphsForGlyphRange:NSMakeRange(0, self.textStorage.length) atPoint:CGPointMake(0, 0)];
}
如果你看到2个字符串叠加在一起并带有一些故障,那么这就是你的问题。如果你只能看到一个应该是因为它们完全一致并且你很好!
答案 1 :(得分:2)
我一直在努力找到适用于此的东西。这是我能够上班的。它从其他一些例子中提取,但我必须包括段落样式才能使它完全排列。希望这可以帮助别人。
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
NSTextStorage *textStorage;
NSMutableParagraphStyle *paragraphStyle = NSMutableParagraphStyle.new;
paragraphStyle.alignment = self.label.textAlignment;
// Configure textContainer
textContainer.lineFragmentPadding = 0.0;
textContainer.lineBreakMode = self.label.lineBreakMode;
textContainer.maximumNumberOfLines = self.label.numberOfLines;
CGPoint locationOfTouchInLabel = [tapGesture locationInView:tapGesture.view];
CGSize labelSize = tapGesture.view.bounds.size;
textContainer.size = self.label.bounds.size;
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.noPoliciesDescriptionLabel.attributedText];
[attributedText addAttributes:@{NSFontAttributeName: self.label.font, NSParagraphStyleAttributeName: paragraphStyle} range:NSMakeRange(0,self.label.attributedText.string.length)];
textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedText];
// Configure layoutManager and textStorage
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
CGRect textBoundingBox = [layoutManager usedRectForTextContainer:textContainer];
CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
locationOfTouchInLabel.y - textContainerOffset.y);
NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInTextContainer
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:nil];
NSRange range = NSMakeRange(indexOfCharacter, 1);
NSString *value = [self.label.text substringWithRange:range];
NSLog(@"%@, %zd, %zd" , value, range.location, range.length);
答案 2 :(得分:1)
我认为问题源于NSTextContainer将文本设置为UITextView,这意味着它不会像UILabel那样垂直居中。
如果您运行以下代码,您可以看到字形布局的位置。
var location = layoutManager.locationForGlyphAtIndex(0);
它应该显示字形被布置在textContainer的顶部。
所以无论你在哪里打电话
var point = tapGesture.locationInView(self);
需要调整以考虑UILabel的垂直位移。