我正在使用核心文本进行文本选择。选择机制本身是有效的,除了一件非常奇怪的事情。我可以在 TextView 的最后一行只选择好。所有先前的行都捕捉到全部选中或根本未选中。这是逻辑(取自 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] BEFORE: xStart (0xbfffcefc) = 18.000000, xEnd (0xbfffcef8) = 306.540009, origin (0xbfffcef0) = {0, -0}
2012-09-19 12:08:39.831 SimpleTextInput[1172:11603] AFTER: xStart (0xbfffcefc) = 370.000000, xEnd (0xbfffcef8) = 0.000000, origin (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
显示其值以相同的方式损坏),但如果是这种情况,那么为什么最后一行文本会按预期工作?谁能给我解释一下?
最佳答案
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);
}
}
关于objective-c - CTFrameGetLineOrigin 令人难以置信的奇怪错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12488106/