2010-10-13 15 views
6

Estoy desarrollando una sencilla aplicación de escritura para iPad.¿Cómo encontrar una posición de píxel de un cursor en UITextView?

Estoy tratando de calcular la posición de píxeles del cursor en UITextView. Pasé unas semanas para diseñar esto, pero todavía no podía resolverlo.

En stackoverflow, Tony escribió un buen algoritmo para encontrar la posición de píxeles del cursor.

Pixel-Position of Cursor in UITextView

He implementado esto con una pequeña modificación, y casi obras que le da al píxel correcta posición del cursor. Sin embargo, solo funciona con alfabetos ingleses.

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

¿Hay alguna otra manera de encontrar la posición de píxeles del cursor en UITextView?

¿O hay una manera de determinar si un personaje en particular sigue el ajuste del carácter como caracteres chinos o el ajuste de palabras como el inglés?

Adición:

Aquí está mi aplicación basado en el algoritmo de Tony. Coloqué uno UITextView en modo apaisado, por lo que su ancho es 1024 y utilicé la fuente personalizada con el tamaño 21. Debe cambiar sizeOfContentWidth y sizeOfContentLine de manera adecuada. 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).

Lo sentimos, código desordenado y comentarios! Todavía hay algunos pequeños errores, y da una posición incorrecta si escribe caracteres chinos al final de la línea (sin ajuste de palabras).

#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

Podría compartir la modificación que hizo al Tony, como estoy seguro que muchos otros están buscando una respuesta sobre cómo encontrar la posición de píxel del cursor/cursor. Gracias. – Joshua

+0

Hola, agregue mi implementación basada en el algoritmo de Tony. Una adición al algoritmo de Tony es que al principio, moví el cursor actual al final de la palabra. – pnmn

+0

Este algoritmo se basa en la suposición de que UITextView solo realiza el ajuste de palabras. Creo que necesitamos un enfoque diferente para calcular la posición de píxel correcta del cursor para que funcione con cualquier tipo de carácter.Una solución es que podemos hacer una vista de texto personalizada totalmente nueva utilizando CoreText, UITextInput y UIKeyInput desde cero, pero no quiero hacerlo solo para la posición del cursor. – pnmn

Respuesta

0

Esta es probablemente bastante ineficiente, pero podría tomar el mismo principio básico del código que has publicado y tomar la línea de texto se encuentra el cursor, y recorrer cada carácter individual y hacer [NSString sizeWithFont:forWidth:lineBreakMode:] para calcular cada ancho del personaje, y puede agregar todos los para su posición x? Solo una idea, pero puede ayudar a solucionar el problema con el ajuste de palabras.

2

Si se orienta a iOS7 sólo se podría utilizar método UITextView:

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

muestra corta:

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 
Cuestiones relacionadas