6

iPad用の簡単なライティングアプリを開発しています。

でカーソルのピクセル位置を計算しようとしていますUITextView。これを設計するのに数週間を費やしましたが、まだそれを行うことができませんでした.

stackoverflow で、Tony はカーソルのピクセル位置を見つけるための優れたアルゴリズムを 1 つ書きました。

UITextView のカーソルのピクセル位置

少し修正してこれを実装しましたが、カーソルの正しいピクセル位置を与えることはほとんど機能します。ただし、英語のアルファベットでのみ機能します。

行末に中国語または日本語の文字がある場合、UITextView漢字間にスペースがなくても、単語の折り返しではなく、文字の折り返しを実行します。UITextViewTony のアルゴリズムは、単語の折り返し (英語のアルファベット) のみを実行する場合に機能すると思います。

でカーソルのピクセル位置を見つける他の方法はありますUITextViewか?

または、特定の文字が漢字のような文字の折り返しに従うか、英語のような単語の折り返しに従うかを判断する方法はありますか?

添加:

Tony のアルゴリズムに基づく私の実装を次に示します。1 つUITextViewを横向きモードで配置したので、幅は 1024 で、サイズ 21 のカスタム フォントを使用しました。適切に変更する必要がsizeOfContentWidthありsizeOfContentLineます。sizeOfContentWidth実際の幅よりも小さくsizeOfContentLine、実際のフォント サイズよりも大きい (行の高さ > フォント サイズ)。

乱雑なコードとコメントで申し訳ありません。まだいくつかの小さなバグがあり、行末に漢字を入力すると (ワードラップなしで) 間違った位置になります。

#define sizeOfContentWidth 1010
#define sizeOfContentHeight 1000
#define sizeOfContentLine 25

    // Stores the original position of the cursor
NSRange originalPosition = textView.selectedRange;    

// Computes textView's origin
CGPoint origin = textView.frame.origin;

// Checks whether a character right to the current cursor is a non-space character
unichar c = ' ';

if(textView.selectedRange.location != [textView.text length])
    c = [textView.text characterAtIndex:textView.selectedRange.location];

// If it's a non-space or newline character, then the current cursor moves to the end of that word
if(c != 32 && c != 10){
    NSRange delimiter = [textView.text rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]
                                                       options:NSLiteralSearch
                                                         range:NSMakeRange(textView.selectedRange.location, [textView.text length] - textView.selectedRange.location)];

    if(delimiter.location == NSNotFound){
        delimiter.location = [textView.text length];
    }

    textView.selectedRange = delimiter;
}

// Deviation between the original cursor location and moved location
int deviationLocation = textView.selectedRange .location - originalPosition.location;

// Substrings the part before the cursor position
NSString* head = [textView.text substringToIndex:textView.selectedRange.location];

// Gets the size of this part
CGSize initialSize = [head sizeWithFont:textView.font constrainedToSize:CGSizeMake(sizeOfContentWidth, sizeOfContentHeight)];

// Gets the length of the head
NSUInteger startOfLine = [head length];

// The first line
BOOL isFirstLine = NO;

if(initialSize.height / sizeOfContentLine == 1){
    isFirstLine = YES;
}

while (startOfLine > 0 && isFirstLine == NO) {
    // 1. Adjusts startOfLine to the beginning of the first word before startOfLine
    NSRange delimiter = [head rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] options:NSBackwardsSearch range:NSMakeRange(0, startOfLine)];

    // Updates startsOfLine
    startOfLine = delimiter.location;

    // 2. Check if drawing the substring of head up to startOfLine causes a reduction in height compared to initialSize. 
    NSString *tempHead = [head substringToIndex:startOfLine];

    // Gets the size of this temp head
    CGSize tempHeadSize = [tempHead sizeWithFont:textView.font constrainedToSize:CGSizeMake(sizeOfContentWidth, sizeOfContentHeight)];

    // Counts the line of the original
    int beforeLine = initialSize.height / sizeOfContentLine;

    // Counts the line of the one after processing
    int afterLine = tempHeadSize.height / sizeOfContentLine;

    // 3. If so, then you've identified the start of the line containing the cursor, otherwise keep going.
    if(beforeLine != afterLine)
        break;
}

// Substrings the part after the cursor position
NSString* tail;

if(isFirstLine == NO)
    tail = [head substringFromIndex:(startOfLine + deviationLocation)];
else {
    tail = [head substringToIndex:(startOfLine - deviationLocation)];
}

// Gets the size of this part
CGSize lineSize = [tail sizeWithFont:textView.font forWidth:sizeOfContentWidth lineBreakMode:UILineBreakModeWordWrap];

// Gets the cursor position in coordinate
CGPoint cursor = origin;    
cursor.x += lineSize.width;
cursor.y += initialSize.height - lineSize.height;

// Back to the original position
textView.selectedRange = originalPosition;

// Debug
printf("x: %f,   y: %f\n", cursor.x, cursor.y);
4

2 に答える 2

2

IOS7 のみを対象とする場合は、UITextView メソッドを使用できます。

- (CGRect)caretRectForPosition:(UITextPosition *)position;

短いサンプル:

NSRange range; // target location in text that you should get from somewhere, e.g. textview.selectedRange
UITextView textview; // the text view

UITextPosition *start = [textview positionFromPosition:textview.beginningOfDocument offset:range.location];
CGRect caretRect = [self caretRectForPosition:start]; // caret rect in UITextView
于 2013-11-11T19:15:37.250 に答える
0

これはおそらくかなり非効率的ですが、投稿したコードと同じ基本原則を使用して、カーソルが置かれているテキスト行を取得し、個々の文字をループして[NSString sizeWithFont:forWidth:lineBreakMode:]各文字の幅を計算し、すべてを追加できますか?あなたのx位置にそれらはありますか?単なるアイデアですが、ワードラップの問題を解決するのに役立つ場合があります。

于 2011-06-29T21:20:10.877 に答える