从UITextView和NSLayoutManager获取行信息

Mik*_*søe 12 objective-c nslayoutmanager ios voiceover textkit

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

  • accessibilityLineNumberForPoint: < - 提供坐标,返回行号
  • accessibilityContentForLineNumber: < - 返回给定行的文本
  • accessibilityFrameForLineNumber: < - 给定行号,返回其帧
  • accessibilityPageContent< - 整个文本内容.我有.:)

我认为NSLayoutManager可以帮助我,但我对它没有经验.我已经想到了一些(我认为),但仍然需要一些帮助.

Apple有一些示例代码(此处)可以获取文本视图中的行数:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

- (NSRect)boundingRectForGlyphRange:(NSRange)glyphRange inTextContainer:(NSTextContainer *)container
Run Code Online (Sandbox Code Playgroud)

鉴于lineRanges我应该能够计算一个点的行号(通过找到lineRange包含字形索引的行号):

- (NSUInteger)glyphIndexForPoint:(CGPoint)point inTextContainer:(NSTextContainer *)container fractionOfDistanceThroughGlyph:(CGFloat *)partialFraction
Run Code Online (Sandbox Code Playgroud)

剩下的是,如果给出行号,我如何得到一行(作为一个NSString)的内容?

sou*_*fox 5

在一个简单的解决方案中思考,这是一个小代码,可重现您的需求

- (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(tmpRange);
    }
    self.ranges = ranges;
    self.frames = frames;
    self.numberOfLines = numberOfLines;
}
Run Code Online (Sandbox Code Playgroud)

请看一下属性:

self.ranges = ranges;
self.frames = frames;
self.numberOfLines = numberOfLines;
Run Code Online (Sandbox Code Playgroud)

您可以在类中具有以下内容来创建此属性:

@property (nonatomic) NSInteger numberOfLines;
@property (strong, nonatomic) NSArray *ranges;
@property (strong, nonatomic) NSArray *frames;
Run Code Online (Sandbox Code Playgroud)

我建议您将分析调用添加到以下委托中:

- (void)textViewDidChange:(UITextView *)textView
Run Code Online (Sandbox Code Playgroud)

在那里,例如,您可以在分析后得到刚做的第二行的帧: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]);
}
Run Code Online (Sandbox Code Playgroud)

将所有框架都放在self.frames中,我想您可以轻松地完成另一件事,请使用坐标猜测行号。