fields ios xcode notifications first-responder

ios - fields - ¿Por qué se llama a UIKeyboardWillShowNotification cada vez que se selecciona otro TextField?



text field ios 11 (6)

Tengo un proyecto que contiene un UIScrollView y muchos UITextField dentro de él.

Por primera vez selecciono un UITextField , se llama a UIKeyboardWillShowNotification , lo cual está bien. Pero cada vez que selecciono un nuevo UITextField (EL TECLADO TODAVÍA ALLÍ), se llama nuevamente a UIKeyboardWillShowNotification !!!, lo cual es extraño.

También establecí un punto de corte simbólico para [UIResponder resignFirstResponder] y veo que se golpea antes y después de que se UIKeyboardWillShowNotification !!!

La otra cosa es que UIKeyboardWillHideNotification solo se llama cuando UIKeyboardWillHideNotification botón "Done" en el teclado

Estoy seguro de no llamar a ningún resignFirstResponder , becomeFirstResponder , endEditing cualquier lugar. (Quiero decir que no llame incorrectamente)

Qué puede causar este problema ?

Aquí está la stacktrace


El mejor enfoque es Agregar notificación y eliminarla una vez que se resuelva su propósito.

Me gusta esto .

- (void)viewWillAppear:(BOOL)animated { // register for keyboard notifications [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide) name:UIKeyboardWillHideNotification object:nil]; }

Ahora escriba su código para el movimiento de las vistas y campo de texto en el tecladoWillShow y vuelva a colocarlos en la posición en los métodos keyboardWillHide .

Eliminar también a los observadores

- (void)viewWillDisappear:(BOOL)animated { // unregister for keyboard notifications while not visible. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; }

También puede renunciar al respondedor cuando presiona la tecla return .

-(BOOL)textFieldShouldReturn:(UITextField *)textField { [_txtFieldEmail resignFirstResponder]; [_txtFieldPassword resignFirstResponder]; return YES; }

Eso debería resolver su problema.


El problema es que configuro inputAccessoryView para UITextField , y esto UIKeyboardWillShowNotification se llame nuevamente a UITextField cuando se selecciona un nuevo UITextField

Este artículo Working With Keyboard en iOS explica esto bien

Cambios adicionales tienen lugar cuando conectamos un teclado externo al iPad. En este caso particular, el comportamiento de notificación depende de la propiedad inputAccessoryView del control que fue la razón para mostrar el teclado.

Si inputAccessoryView no está presente o su altura es igual a 0 puntos, no se envían notificaciones de teclado. Supongo que esto se debe a que en este caso, no se producen cambios visuales en la aplicación. De lo contrario, todas las notificaciones se comportan como se espera, lo que significa que se envían como en la mayoría de los casos cuando el teclado se muestra u oculta en un estado normal (no desacoplado o dividido).

Cada UITextField se selecciona una nueva UITextField , el sistema operativo necesita calcular nuevamente el marco para el teclado y se publican las siguientes notificaciones

UIKeyboardWillChangeFrameNotification UIKeyboardWillShowNotification UIKeyboardDidChangeFrameNotification UIKeyboardDidShowNotification

Lo mismo se aplica cuando TextField pierde su estado de primera respuesta

Tenga en cuenta que el uso de la misma vista para inputAccessoryView hará que UIKeyboardWillShowNotification solo se llame una vez


Para solucionar el problema, utilicé el siguiente código para cancelar la UIKeyboardWillShowNotification llamada UIKeyboardWillShowNotification si el marco del teclado no está cambiando.

func keyboardWillShow(notification: NSNotification) { let beginFrame = notification.userInfo![UIKeyboardFrameBeginUserInfoKey]!.CGRectValue() let endFrame = notification.userInfo![UIKeyboardFrameEndUserInfoKey]!.CGRectValue() // Return early if the keyboard''s frame isn''t changing. guard CGRectEqualToRect(beginFrame, endFrame) == false else { return } ... }


En general, creo que muchas cosas pueden causar falsas notificaciones UIKeyboardWillShow y UIKeyboardWillHide . Mi solución es usar una propiedad para rastrear si el teclado ya está mostrando:

func keyboardShow(_ n:Notification) { if self.keyboardShowing { return } self.keyboardShowing = true // ... other stuff } func keyboardHide(_ n:Notification) { if !self.keyboardShowing { return } self.keyboardShowing = false // ... other stuff }

Esos guardias bloquean exactamente las notificaciones espurias, y todo va bien después de eso. Y la propiedad keyboardShowing puede ser útil por otras razones, por lo que es algo que vale la pena seguir de todos modos.



He luchado con esto, después de medio día de búsqueda y experimentación creo que este es el código más corto y confiable. Es una mezcla de varias respuestas, la mayoría de las cuales olvido dónde encontré (partes de las cuales se mencionan aquí).

Mi problema era un WKWebView que (cuando el usuario cambiaba los campos) generaría una carga de notificaciones de WillShow, WillHide, etc. Además, tuve un problema con el teclado externo que todavía tiene la barra táctil en pantalla.

Esta solución usa el mismo código de animación para "Abrir" y "Cerrar" el teclado, también soportará que se adjunte un teclado externo y vistas de teclado personalizadas.

Primero regístrese para UIKeyboardWillChangeFrameNotification.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

Luego, simplemente necesita asignar los cambios a su vista en la forma en que lo haga (cambie una constante de restricción de altura o de fondo).

- (void)keyboardWillChangeFrame:(NSNotification *)notification { NSDictionary *userInfo = notification.userInfo; CGRect keyboardEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect convertedEnd = [self.view convertRect:keyboardEnd fromView:nil]; // Convert the Keyboard Animation to an Option, note the << 16 in the option UIViewAnimationCurve keyAnimation = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; // Change the Height or Y Contraint to the new value. self.keyboardHeightConstraint.constant = self.view.bounds.size.height - convertedEnd.origin.y; [UIView animateWithDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue] delay:0.0 options:keyAnimation << 16 animations:^{ [self.view layoutIfNeeded]; } completion:nil]; }

La conversión de Animación a Opción parece funcionar (solo puedo encontrar ejemplos de cómo se usa y no cómo / por qué), sin embargo, no estoy convencido de que siga siendo así, por lo que sería aconsejable usar una opción de "stock". Parece que el teclado usa alguna animación no especificada.