Sir*_*III 4 nslayoutmanager uilabel ios nstextstorage nstextcontainer
我想得到UILabel上的tapped字符的索引.我已经将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)
Run Code Online (Sandbox Code Playgroud)
这是我想要它的标签的前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
}
Run Code Online (Sandbox Code Playgroud)
我称这种现象layoutSubviews(),awakFromNib和的制定者bounds,frame,attributedText和text.
它现在给了我一些奇怪的索引,比如文本长度是21,点击第一个字母给我6.
TLDR:你得到一些奇怪的索引,因为你看到的字符串layoutManager与你在屏幕上看到的字符串不同.
您将获得一些奇怪的索引:
- (NSUInteger)characterIndexForPoint:(CGPoint)point
inTextContainer:(NSTextContainer *)container
fractionOfDistanceBetweenInsertionPoints:(nullable CGFloat *)partialFraction;
Run Code Online (Sandbox Code Playgroud)
因为你自己layoutManager必须与layoutManager系统内部同步UILabel.这意味着当你在标签上设置字体,大小等时,内部就layoutManager知道这一点,因为它是由UILabel你照顾的,但是你的layoutManager实例没有.
因此,layoutManager " 看到 " 的文本布局与屏幕上标签呈现的实际文本位于不同的位置(我打赌的默认字体和大小).
复杂的部分是保持这些属性同步,你可以做的是在你的属性文本上设置如下:
[mutableAttributedString addAttribute:NSFontAttributeName
value:self.font
range:NSMakeRange(0, mutableAttributedString.string.length)];
Run Code Online (Sandbox Code Playgroud)
并将此属性字符串传递给您的NSTextStorage实例.这为我解决了所有问题.
信息:为了帮助您调试,您可以使用以下方法呈现字符串" see " layoutManager:
- (void)drawTextInRect:(CGRect)rect
{
[super drawTextInRect:rect];
[self.layoutManager drawGlyphsForGlyphRange:NSMakeRange(0, self.textStorage.length) atPoint:CGPointMake(0, 0)];
}
Run Code Online (Sandbox Code Playgroud)
如果你看到2个字符串叠加在一起并带有一些故障,那么这就是你的问题.如果你只能看到一个应该是因为它们完全对齐并且你很好!
我认为这个问题源于 NSTextContainer 像 UITextView 一样布局文本的事实,这意味着它不会像 UILabel 那样垂直居中。
如果运行以下代码,您可以看到字形的布局位置。
var location = layoutManager.locationForGlyphAtIndex(0);
Run Code Online (Sandbox Code Playgroud)
它应该显示字形被放置在文本容器的顶部。
所以无论你打电话
var point = tapGesture.locationInView(self);
Run Code Online (Sandbox Code Playgroud)
需要进行调整以考虑 UILabel 的垂直移位。
| 归档时间: |
|
| 查看次数: |
2761 次 |
| 最近记录: |