ios - begin - Formatea el texto de UITextField sin mover el cursor hasta el final
textfielddidchange swift 3 (4)
Estoy tratando de aplicar los estilos NSAttributedString a un UITextField después de procesar una nueva entrada de texto, pulsando tecla por tecla. El problema es que cada vez que sustituyo el texto, el cursor saltará al final de cada cambio. Aquí está mi enfoque actual ...
Recibir y mostrar el cambio de texto inmediatamente (el mismo problema se aplica cuando devuelvo falso y hago el reemplazo de texto manualmente)
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
let range:NSRange = NSRange(location: range.location, length: range.length)
let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string);
return true
}
Me suscribí a la notificación UITextFieldTextDidChangeNotification. Esto dispara el estilo. Cuando se cambia el texto, lo reemplazo ( NSString ) con la versión formateada ( NSAttributedString ) usando alguna función format ().
func textFieldTextDidChangeNotification(userInfo:NSDictionary) {
var attributedString:NSMutableAttributedString = NSMutableAttributedString(string: fullString)
attributedString = format(textField.text) as NSMutableAttributedString
textField.attributedText = attributedString
}
El estilo funciona bien así. Sin embargo, después de cada reemplazo de texto, el cursor salta al final de la cadena. ¿Cómo puedo desactivar este comportamiento o mover manualmente el cursor hacia atrás donde comenzó la edición? ... o hay una mejor solución para estilizar el texto mientras se edita?
Esta es una pregunta antigua, pero tuve un problema similar y lo resolví con el siguiente Swift:
// store the current cursor position as a range
var preAttributedRange: NSRange = textField.selectedRange
// apply attributed string
var attributedString:NSMutableAttributedString = NSMutableAttributedString(string: fullString)
attributedString = format(textField.text) as NSMutableAttributedString
textField.attributedText = attributedString
// reapply the range
textField.selectedRange = preAttributedRange
Funciona en el contexto de mi aplicación, ¡espero que sea útil para alguien!
Este es un código que funciona para Swift 2. ¡Disfrútalo!
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let beginnig: UITextPosition = textField.beginningOfDocument
if let txt = textField.text {
textField.text = NSString(string: txt).stringByReplacingCharactersInRange(range, withString: string)
}
if let cursorLocation: UITextPosition = textField.positionFromPosition(beginnig, offset: (range.location + string.characters.count) ) {
textField.selectedTextRange = textField.textRangeFromPosition(cursorLocation, toPosition: cursorLocation)
}
return false
}
Tenga en cuenta que el último "if let" siempre debe permanecer al final del código.
Gracias @ Stonz2 por el código en Objective-C. ¡Funciona a las mil maravillas! Lo usé en mi proyecto Swift. El mismo código en Swift:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let positionOriginal = textField.beginningOfDocument
let cursorLocation = textField.positionFromPosition(positionOriginal, offset: (range.location + NSString(string: string).length))
/* MAKE YOUR CHANGES TO THE FIELD CONTENTS AS NEEDED HERE */
if(cursorLocation != nil) {
textField.selectedTextRange = textField.textRangeFromPosition(cursorLocation!, toPosition: cursorLocation!)
}
return false
}
La forma de hacer que esto funcione es agarrar la ubicación del cursor, actualizar el contenido del campo y luego colocar el cursor en su posición original. No estoy seguro del equivalente exacto en Swift, pero lo siguiente es cómo lo haría en Obj-C.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
UITextPosition *beginning = textField.beginningOfDocument;
UITextPosition *cursorLocation = [textField positionFromPosition:beginning offset:(range.location + string.length)];
textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
/* MAKE YOUR CHANGES TO THE FIELD CONTENTS AS NEEDED HERE */
// cursorLocation will be (null) if you''re inputting text at the end of the string
// if already at the end, no need to change location as it will default to end anyway
if(cursorLocation)
{
// set start/end location to same spot so that nothing is highlighted
[textField setSelectedTextRange:[textField textRangeFromPosition:cursorLocation toPosition:cursorLocation]];
}
return NO;
}