¿Cómo detectar la clave de eliminación en un UITextField en iOS 8?

He subclasificado UITextField e implementado el método deleteBackward del protocolo UIKeyInput para detectar el retroceso que se está presionando. Esto funciona bien en iOS 7 pero no en iOS 8.

deleteBackward ya no se llama en el UITextField cuando presiono la tecla de retroceso.

Revisé la documentación y las notas de la versión y nada indica la razón por la que esto podría suceder. ¿Alguna sugerencia?

Debe ver un ejemplo para MBContactPicker en github. Eliminación de contactos en MBContactPicker a través del botón Retroceso en iOS8 probado por mí. ¡Y funciona mucho! Puedes usarlo como ejemplo.

El autor de MBContactPicker utiliza el siguiente método: Cuando UITextField debe estar vacío (o antes de llamar a becomeFirstResponder cuando está vacío), guarda allí un símbolo de espacio en blanco. Y luego, cuando presiona el botón Retroceso (cuando se ajustó el foco al final del texto de su UITextField), el método

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 

trabajará. Dentro de él debes usar un cheque como este:

 NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:string]; BOOL isPressedBackspaceAfterSingleSpaceSymbol = [string isEqualToString:@""] && [resultString isEqualToString:@""] && range.location == 0 && range.length == 1; if (isPressedBackspaceAfterSingleSpaceSymbol) { // your actions for deleteBackward actions } 

Por lo tanto, siempre debe controlar que UITextField contenga un solo espacio en blanco.

Esto no es pirateo. Entonces, el usuario no se dará cuenta de que se modificó algún comportamiento

Mucha gente ha estado diciendo que esto es un error, pero dado que este problema aún existe en el DJ, estoy empezando a pensar que podría ser un cambio en la lógica. Dicho esto, escribí este código para mi aplicación y lo probé en iOS 7-8.

Agregue el siguiente método a su subclase UITextField .

 - (BOOL)keyboardInputShouldDelete:(UITextField *)textField { BOOL shouldDelete = YES; if ([UITextField instancesRespondToSelector:_cmd]) { BOOL (*keyboardInputShouldDelete)(id, SEL, UITextField *) = (BOOL (*)(id, SEL, UITextField *))[UITextField instanceMethodForSelector:_cmd]; if (keyboardInputShouldDelete) { shouldDelete = keyboardInputShouldDelete(self, _cmd, textField); } } BOOL isIos8 = ([[[UIDevice currentDevice] systemVersion] intValue] == 8); BOOL isLessThanIos8_3 = ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3f); if (![textField.text length] && isIos8 && isLessThanIos8_3) { [self deleteBackward]; } return shouldDelete; } 

Este código es ligeramente anterior a la línea roja de las API privadas, sin embargo, no debería tener problemas para usarlo. Mi aplicación con este código está en la tienda de aplicaciones.

Para explicarlo un poco, llamamos a la súper implementación de este método para evitar la pérdida de código. Después iban a llamar -deleteBackward si no hay texto y la versión de iOS está entre 8-8.2.

EDITAR : 22/1/15

También podría ser útil hacer una subclase del método -deleteBackward de su UITextField subclasificado. Esto soluciona algunos errores condicionales. Un ser si usa un teclado personalizado. Aquí hay un ejemplo del método.

 - (void)deleteBackward { BOOL shouldDismiss = [self.text length] == 0; [super deleteBackward]; if (shouldDismiss) { if ([self.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) { [self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""]; } } } 

EDITAR : 13/4/15

Como @ Gee.E comentó, iOS 8.3 ha solucionado este problema. El código ha sido actualizado para reflejar los cambios.

Puede detectar cuándo el usuario elimina el texto mediante el uso de retroceso al implementar el método delegado UITextField:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (range.length==1 && string.length==0) NSLog(@"backspace tapped"); return YES; } 

En iOS8, algunos teclados personalizados eliminan la palabra completa, por lo tanto, solo marque string.length.

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (string.length==0) { //Delete any cases if(range.length > 1){ //Delete whole word } else if(range.length == 1){ //Delete single letter } else if(range.length == 0){ //Tap delete key when textField empty } } return YES; } 

Swift 2.2:

 func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { if text == "" { print("Backspace has been pressed") } return true } 

Versión de Swift 2.0 para detectar la eliminación basada en BackSpace, haciendo referencia a publicaciones de códigos de almas

 //For Detecting Backspace based Deletion of Entire Word in TextField func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if (range.length == 1 && string.isEmpty){ print("Used Backspace") } return true } 
 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { const char * _char = [string cStringUsingEncoding:NSUTF8StringEncoding]; int isBackSpace = strcmp(_char, "\b"); if (isBackSpace == -8) { NSLog(@"Backspace was pressed"); } return YES; } 

Básicamente, este método detecta qué botón está presionando (o lo acaba de presionar). Esta entrada viene como un NSString. Convertimos este NSString en un tipo de carácter C y luego lo comparamos con el carácter de retroceso tradicional (\ b). Entonces, si este strcmp es igual a -8, podemos detectarlo como un retroceso.

Swift 2:

 if (string.characters.count == 0 && range.length == 1) { return true } 

deberías usar este string.characters.count

Esto no responde explícitamente la pregunta original, pero no vale la pena en la documentación de textField(_:shouldChangeCharactersIn:replacementString:) , dice:

string : la cadena de reemplazo para el rango especificado. Durante la escritura, este parámetro normalmente solo contiene el único carácter nuevo que se tipeó, pero puede contener más caracteres si el usuario está pegando texto. Cuando el usuario elimina uno o más caracteres, el La cadena de reemplazo está vacía.

Por lo tanto, podemos detectar retrocesos en un UITextFieldDelegate si implementamos textField(_:shouldChangeCharactersIn:replacementString:) y verificamos si la longitud de la string es 0.

Muchas otras respuestas aquí han usado esta misma lógica sin hacer referencia a la documentación, por lo que es de esperar que hacerlo correctamente desde la fuente haga que las personas se sientan más cómodas al usarla.