Sto sviluppando un'applicazione di scrittura semplice per iPad.Come trovare una posizione dei pixel di un cursore in UITextView?
Sto provando a calcolare la posizione dei pixel del cursore in UITextView
. Trascorro un paio di settimane per progettare questo, ma non riesco ancora a capire di farlo.
In stackoverflow, Tony ha scritto un buon algoritmo per trovare la posizione dei pixel del cursore.
Pixel-Position of Cursor in UITextView
ho attuato questo con una piccola modifica, e funziona quasi che dà la corretta pixel-posizione del cursore. Tuttavia, funziona solo con alfabeti inglesi.
Se alla fine della riga è presente un carattere cinese o giapponese, lo UITextView
esegue il wrapping dei caratteri, anziché il ritorno a capo, anche se non vi è spazio tra i caratteri cinesi. Penso che l'algoritmo di Tony funzioni quando UITextView
esegue solo il word-wrapping (con alfabeti inglesi).
C'è un altro modo per trovare la posizione dei pixel del cursore in UITextView
?
O c'è un modo per determinare se un particolare personaggio segue il carattere come caratteri cinesi o il wordwrap come l'inglese?
Aggiunta:
Ecco la mia implementazione basata su un algoritmo di Tony. Ho inserito uno UITextView
in modalità orizzontale, quindi la sua larghezza è 1024 e ho utilizzato il carattere personalizzato con la dimensione 21. È necessario modificare sizeOfContentWidth
e sizeOfContentLine
in modo appropriato. sizeOfContentWidth
è più piccola della larghezza effettiva e sizeOfContentLine
è più grande della dimensione del carattere reale (altezza della linea> dimensione del carattere).
Siamo spiacenti per il codice e commenti disordinati! Ci sono ancora alcuni piccoli bug, e dà una posizione sbagliata se si digitano caratteri cinesi alla fine della riga (nessun word-wrap).
#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);
Potrebbe condividere la modifica che hai fatto a Tony di, come sono sicuro che molti altri sono alla ricerca di una risposta su come trovare la posizione dei pixel del cursore di inserimento/cursore. Grazie. – Joshua
Ciao, ho aggiunto la mia implementazione basata sull'algoritmo di Tony. Un'aggiunta all'algoritmo di Tony è che all'inizio ho spostato il cursore corrente alla fine della parola. – pnmn
Questo algoritmo si basa sul presupposto che UITextView stia facendo solo il word-wrapping. Penso che abbiamo bisogno di un approccio diverso per calcolare la giusta posizione dei pixel del cursore per farlo funzionare con qualsiasi tipo di carattere.Una soluzione è che possiamo creare una vista del testo completamente nuova utilizzando CoreText, UITextInput e UIKeyInput partendo da zero, ma non voglio farlo solo per una posizione del cursore. – pnmn