从UITextView和NSLayoutManager获取行信息

为了支持UIAccessibilityReadingContent协议,我需要我的UITextView来回答关于它的行的问题。 这些是我需要实现的协议的方法:

  • accessibilityLineNumberForPoint: < – 提供了一个坐标,返回一个行号
  • accessibilityContentForLineNumber: < – 返回给定行的文本
  • accessibilityFrameForLineNumber: < – 给定一个行号,返回其框架
  • accessibilityPageContent < – 整个文字内容。 我有。 🙂

我认为,NSLayoutManager可以帮助我,但我不是那种经验。 我想到了一些(我认为),但仍然需要一些帮助。

苹果有一些示例代码( 这里 )可以让我在文本视图中的行数:

 NSLayoutManager *layoutManager = [textView layoutManager]; unsigned numberOfLines, index, numberOfGlyphs = [layoutManager numberOfGlyphs]; NSRange lineRange; for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ (void) [layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange:&lineRange]; index = NSMaxRange(lineRange); } 

我用上面的lineRange来计算,我可以在NSLayoutManager上使用这个方法来计算行rects:

 - (NSRect)boundingRectForGlyphRange:(NSRange)glyphRange inTextContainer:(NSTextContainer *)container 

并给lineRanges我应该能够计算一个点使用(通过查找lineRange包含字形索引的行号:

 - (NSUInteger)glyphIndexForPoint:(CGPoint)point inTextContainer:(NSTextContainer *)container fractionOfDistanceThroughGlyph:(CGFloat *)partialFraction 

所以剩下的是,如何得到一个行的内容(作为一个NSString ),给定一个行号?

在一个简单的解决scheme思考,这里是一个小代码,重现你所需要的

 - (void)analyse:(UITextView *)textView { NSLayoutManager *layoutManager = [textView layoutManager]; NSString *string = textView.text; unsigned numberOfLines, index, stringLength = [string length]; NSMutableArray *ranges = [NSMutableArray new]; NSMutableArray *frames = [NSMutableArray new]; for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++) { NSRange tmprange; NSRange range = [string lineRangeForRange:NSMakeRange(index, 0)]; CGRect rect = [layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange:&tmprange]; [ranges addObject:[NSValue valueWithRange:range]]; [frames addObject:[NSValue valueWithCGRect:rect]]; index = NSMaxRange(range); } self.ranges = ranges; self.frames = frames; self.numberOfLines = numberOfLines; } 

请看看属性:

 self.ranges = ranges; self.frames = frames; self.numberOfLines = numberOfLines; 

你可以在你的课堂中创build下面的属性:

 @property (nonatomic) NSInteger numberOfLines; @property (strong, nonatomic) NSArray *ranges; @property (strong, nonatomic) NSArray *frames; 

我build议你在下面的代理中添加分析调用:

 - (void)textViewDidChange:(UITextView *)textView 

在那里你可以例如分析得到第二行的帧刚刚做的: self.frames [1]

或者获取第二行的文本:[textView.text substringWithRange:[self.ranges [1] rangeValue]]

比如像这样:

 if (self.numberOfLines > 1) { NSRange range = [self.ranges[1] rangeValue]; NSLog(@"2nd line = %@", [textView.text substringWithRange:range]); NSLog(@"2nd line frame = %@", self.frames[1]); } 

拥有self.frames中的所有框架,我认为你可以轻松地做其他事情,用坐标猜测行号。