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.
Para aquellos que no usan inputAccessoryView pero aún tienen problemas, puede deberse al uso de campos sensibles (contraseña). Consulte esta publicación de y responda: keyboardWillShow en IOS8 con UIKeyboardWillShowNotification
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.