2010-10-13 9 views
6

Ich entwickle eine einfache Schreib-App für iPad.Wie findet man eine Pixelposition eines Cursors in UITextView?

Ich versuche, die Pixel-Position des Cursors in UITextView zu berechnen. Ich habe ein paar Wochen damit verbracht, das zu entwerfen, aber ich konnte es immer noch nicht herausfinden.

In Stackoverflow hat Tony einen guten Algorithmus geschrieben, um die Pixelposition des Cursors zu finden.

Pixel-Position of Cursor in UITextView

ich realisierte dies mit einer kleinen Änderung, und es funktioniert fast, dass es die richtige Pixel-Position des Cursors gibt. Es funktioniert jedoch nur mit englischen Alphabeten.

Wenn am Ende der Zeile ein chinesisches oder japanisches Zeichen steht, führt UITextView das Zeichenumbruch statt des Zeilenumbruchs aus, obwohl zwischen den chinesischen Zeichen kein Leerzeichen steht. Ich denke Tonys Algorithmus funktioniert, wenn UITextView nur Wortumbruch (mit englischen Alphabeten) durchführt.

Gibt es eine andere Möglichkeit, die Pixelposition des Cursors in UITextView zu finden?

Oder gibt es eine Möglichkeit zu bestimmen, ob ein bestimmtes Zeichen Zeichenumbruch wie chinesische Zeichen oder Word-Wrapping wie Englisch folgt?

Zusatz:

Hier ist meine Implementierung basiert auf Tonys Algorithmus. Ich legte eine UITextView in einen Querformat-Modus, so dass seine Breite 1024 ist, und ich verwendete die benutzerdefinierte Schriftart mit der Größe 21. Sie sollten sizeOfContentWidth und sizeOfContentLine entsprechend ändern. sizeOfContentWidth ist kleiner als die tatsächliche Breite und sizeOfContentLine ist größer als die tatsächliche Schriftgröße (Zeilenhöhe> Schriftgröße).

Entschuldigung wegen unordentlichem Code und Kommentaren! Es gibt immer noch ein paar kleine Fehler, und es gibt eine falsche Position, wenn Sie am Ende der Zeile chinesische Zeichen eingeben (kein Zeilenumbruch). Diese

#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); 
+1

Könnten Sie die Änderung, die Sie an Tonys gemacht teilen, wie ich bin sicher, dass viele andere suchen nach einer Antwort, wie man die Pixelposition des Caret/Cursors findet. Vielen Dank. – Joshua

+0

Hallo, ich habe meine Implementierung basierend auf Tonys Algorithmus hinzugefügt. Eine Ergänzung zu Tonys Algorithmus ist, dass ich am Anfang den aktuellen Cursor an das Ende des Wortes bewegt habe. – pnmn

+0

Dieser Algorithmus basiert auf der Annahme, dass UITextView nur Word-Wrapping ausführt. Ich denke, wir brauchen einen anderen Ansatz, um die richtige Pixelposition des Cursors zu berechnen, damit er mit jeder Art von Charakter funktioniert.Eine Lösung ist, dass wir mit CoreText, UITextInput und UIKeyInput von Grund auf eine völlig neue benutzerdefinierte Textansicht erstellen können, aber ich möchte das nicht nur für eine Cursorposition tun. – pnmn

Antwort

0

ist wohl eher ineffizient, konnte aber nehmen Sie das gleiche Grundprinzip der Code, den Sie geschrieben haben, und nehmen Sie die Textzeile der Cursor eingeschaltet ist, und Schleife durch jeden einzelnen Charakter und tun [NSString sizeWithFont:forWidth:lineBreakMode:] jeweils berechnen Zeichenbreite, und Sie könnten all diese für Ihre X-Position hinzufügen? Nur eine Idee, kann aber helfen, das Problem mit dem Zeilenumbruch zu beheben.

2

Wenn Sie IOS7 Ziel nur könnten Sie UITextView Methode verwenden:

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

Kurz Beispiel:

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 
Verwandte Themen