¿Cómo encontrar una position de píxel de un cursor en UITextView?

Estoy desarrollando una aplicación de escritura simple para iPad.

Estoy tratando de calcular la position de píxeles del cursor en UITextView . Pasé algunas semanas para diseñar esto, pero todavía no pude resolverlo.

En stackoverflow, Tony escribió un buen algorithm para encontrar la position de píxeles del cursor.

Posición de píxeles del cursor en UITextView

Implementé esto con una pequeña modificación, y casi funciona que da la position correcta del píxel del cursor. Sin embargo, solo funciona con alfabetos en inglés.

Si hay un carácter chino o japonés al final de la línea, UITextView realiza el UITextView caracteres, en lugar del UITextView de palabras, aunque no haya espacio entre los caracteres chinos. Creo que el algorithm de Tony funciona cuando UITextView solo realiza el UITextView palabras (con alfabetos en inglés).

¿Hay alguna otra forma de encontrar la position de píxeles del cursor en UITextView ?

¿O hay una forma de determinar si un personaje en particular sigue el ajuste de caracteres como los caracteres chinos o el ajuste de palabras como el inglés?

Adición:

Aquí está mi implementación basada en el algorithm de Tony. UITextView una UITextView en modo horizontal, por lo que su ancho es 1024, y utilicé la fuente personalizada con el tamaño 21. Debe cambiar sizeOfContentWidth y sizeOfContentLine . sizeOfContentWidth es más pequeño que el ancho real, y sizeOfContentLine es más grande que el tamaño de fuente real (altura de línea> tamaño de fuente).

Perdón por el código desorderado y los comentarios! Todavía hay algunos pequeños errores, y da una position incorrecta si escribe caracteres chinos al final de la línea (no hay ajuste de palabra).

 #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 networkinguction in height companetworking 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); 

Si segmenta a IOS7 solo podría usar el método UITextView:

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

Muestra corta:

 NSRange range; // target location in text that you should get from somewhere, eg 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 

Probablemente esto sea ineficiente, pero podría tomar el mismo principio básico del código que ha publicado y tomar la línea de text en que está el cursor, y recorrer cada carácter individual y hacer [NSString sizeWithFont:forWidth:lineBreakMode:] para calcular el ancho de cada carácter, y usted podría agregar todos esos para su position x? Solo una idea, pero puede ayudar a solucionar el problema con el ajuste de palabras.