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);
    }
}    

非常に奇妙なことに気づきました。CTFrameGetLineOriginxStartと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、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は、その値が同じように破損していることを示しています)が、その場合、テキストの最後の行が期待どおりに機能するのはなぜですか?誰かが私にこれを説明できますか?

4

2 に答える 2

3

CTFrameGetLineOriginsに奇妙なバグはありません。

CTFrameGetLineOriginsの2番目のパラメータ: CFRangeコピーする線の原点の範囲です。範囲の範囲の長さが0の場合、コピー操作は範囲の開始インデックスから最後の行の起点まで続行されます。

あなたは合格してCFRangeMake(i, 0)います。ここで、最初のループ反復(i = 0)では、&originをすべての行の原点(0から終了行)で埋め、他のメモリをオーバーライドしようとします。

次のコードを試してください。これで問題が解決します。

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);

これは、必要な1行だけの原点を取得するだけです(これは、このメソッドで意図されているものです)。私はまた、彼らが同じ間違いをしたことに気づきました:cursorRectForIndexfirstRectForNSRange。これを理解するのを手伝ってくれた@RobNapierにクレジットがあります。

于 2014-07-23T21:36:06.407 に答える