0

我正在使用核心文本进行文本选择。选择机制本身正在工作,除了一件非常奇怪的事情。我只能在文本视图的最后一行选择罚款。所有先前的行都捕捉到全部选定或根本不选定。这是逻辑(取自Apple的示例代码):

 NSArray *lines = (NSArray *) CTFrameGetLines(_frame);
for (int i = 0; i < [lines count]; i++) {
    CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
    CFRange lineRange = CTLineGetStringRange(line);
    NSRange range = NSMakeRange(lineRange.location, lineRange.length);
    NSRange intersection = [self RangeIntersection:range withSecond:selectionRange];
    if (intersection.location != NSNotFound && intersection.length > 0) {
        // The text range for this line intersects our selection range
        CGFloat xStart = CTLineGetOffsetForStringIndex(line, intersection.location, NULL);
        CGFloat xEnd = CTLineGetOffsetForStringIndex(line, intersection.location + intersection.length, NULL);
        CGPoint origin;
        // Get coordinate and bounds information for the intersection text range
        CTFrameGetLineOrigins(_frame, CFRangeMake(i, 0), &origin);
        CGFloat ascent, descent;
        CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
        // Create a rect for the intersection and draw it with selection color
        CGRect selectionRect = CGRectMake(xStart, origin.y - descent, xEnd - xStart, ascent + descent);
        UIRectFill(selectionRect);
    }
}    

我注意到一件非常奇怪的事情。调用CTFrameGetLineOrigin似乎破坏了 xStart 和 xEnd 内部的值。我插入日志如下:

NSLog(@"BEFORE: xStart (%p) = %f, xEnd (%p) = %f, origin (%p) = %@", &xStart, xStart, &xEnd, xEnd, &origin, NSStringFromCGPoint(origin));
CTFrameGetLineOrigins(_frame, CFRangeMake(i, 0), &origin);
NSLog(@"AFTER: xStart (%p) = %f, xEnd (%p) = %f, origin (%p) = %@", &xStart, xStart, &xEnd, xEnd, &origin, NSStringFromCGPoint(origin));

不起作用的行的输出如下

2012-09-19 12:08:39.831 SimpleTextInput[1172:11603] 之前:xStart (0xbfffcefc) = 18.000000, xEnd (0xbfffcef8) = 306.540009, 原点 (0xbfffcef0) = {0, -0}

2012-09-19 12:08:39.831 SimpleTextInput[1172:11603] 之后:xStart (0xbfffcefc) = 370.000000,xEnd (0xbfffcef8) = 0.000000,原点 (0xbfffcef0) = {0, 397}

如果我执行以下操作,它会自行修复......但我不知道为什么:

CGFloat xStart = CTLineGetOffsetForStringIndex(line, intersection.location, NULL);
CGFloat xEnd = CTLineGetOffsetForStringIndex(line, intersection.location + intersection.length, NULL);
CGFloat xStart2 = 0.f; //HACK, not used at all except to pad memory
CGPoint origin;

似乎CTFrameGetLineOrigin不尊重origin(记录xStart2显示其值以相同方式损坏)的内存边界,但如果是这种情况,那么为什么最后一行文本会按预期工作?谁可以给我解释一下这个?

4

2 回答 2

3

CTFrameGetLineOrigins 中没有奇怪的错误。

在 CTFrameGetLineOrigins 中,第二个参数: CFRange是您希望复制的线原点范围。如果范围的范围长度为 0,则复制操作从范围的起始索引继续到最后一行原点。

你正在路过CFRangeMake(i, 0)。在第一次循环迭代 (i=0) 中,它将尝试用所有行起点(0 到终点行)填充 &origin 并覆盖其他一些内存。

尝试以下代码,这将解决问题。

NSArray *lines = (NSArray *) CTFrameGetLines(_frame);
CGPoint origins[lines.count]; //allocate enough space for buffer.
// Get all line origins...
CTFrameGetLineOrigins(_frame, CFRangeMake(0, 0), origins);

for (int i = 0; i < [lines count]; i++) {
    CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
    CFRange lineRange = CTLineGetStringRange(line);
    NSRange range = NSMakeRange(lineRange.location, lineRange.length);
    NSRange intersection = [self RangeIntersection:range withSecond:selectionRange];
    if (intersection.location != NSNotFound && intersection.length > 0) {
        // The text range for this line intersects our selection range
        CGFloat xStart = CTLineGetOffsetForStringIndex(line, intersection.location, NULL);
        CGFloat xEnd = CTLineGetOffsetForStringIndex(line, intersection.location + intersection.length, NULL);
        
        CGFloat ascent, descent;
        CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
        // Create a rect for the intersection and draw it with selection color
        CGRect selectionRect = CGRectMake(xStart + origins[i].x, origins[i].y - descent, xEnd - xStart, ascent + descent);
        UIRectFill(selectionRect);
    }
}    
于 2012-10-19T05:37:05.293 回答
0

这看起来像是drawRangeAsSelection来自SimpleTextInput示例。如果是这种情况,您可以这样做:

CTFrameGetLineOrigins(_frame, CFRangeMake(i, 1), &origin);

它将仅检索您需要的一行的原点(这是此方法的目的)。我还注意到他们在:cursorRectForIndexfirstRectForNSRange. 感谢@RobNapier 帮助我解决了这个问题。

于 2014-07-23T21:36:06.407 回答