iphone - rapido - Teclado “WillShow” y “WillHide” vs. Rotación
editar centro de control ios 11 (7)
Tengo un controlador de vista que escucha tanto UIKeyboardWillShowNotification como UIKeyboardWillHideNotification. Los manejadores de estas notificaciones ajustan varias partes de la vista, que es un procedimiento estándar.
El siguiente código se usa para convertir el teclado directamente de las coordenadas de la pantalla:
CGRect keyboardBounds = [self.view convertRect:[keyboardBoundsValue CGRectValue] fromView:nil];
De nuevo, el procedimiento estándar. Desafortunadamente, hay una situación crítica en la que falla esta conversión. Mira lo que sucede cuando un iPhone se gira de vertical a horizontal mientras se implementa el teclado:
1) iOS dispara automáticamente UIKeyboardWillHideNotification ; self.interfaceOrientation se reporta como retrato ; keyboardBounds.height es 216.0 . Esto tiene sentido . ¿Por qué? Debido a que el controlador de notificaciones tiene la oportunidad de "limpiar" antes de que la vista cambie al modo horizontal.
2) iOS automáticamente dispara UIKeyboardWillShowNotification ; self.interfaceOrientation se reporta como retrato ; keyboardBounds.height es 480.0 . Esto NO tiene sentido . Por qué no? ¡Porque el manejador de notificaciones va a hacer su trabajo pensando que la altura del teclado es 480.0!
¿Apple dejó caer la pelota en este caso, o estoy haciendo algo mal?
Tenga en cuenta que escuchar UIKeyboard Did ShowNotification no es una solución válida, ya que degrada significativamente la experiencia del usuario. ¿Por qué? Porque animar mis cambios en la vista después de que se produzca la animación de implementación del teclado es ... bueno, bastante terrible.
¿Alguien ha logrado que la autorotación funcione perfectamente mientras se implementa el teclado? Parece una explosión de caos que Apple ha pasado completamente por alto. >: |
Aquí está mi solución:
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float keyboardHeight = self.interfaceOrientation == UIInterfaceOrientationPortrait ? keyboardSize.height : keyboardSize.width;
Espero que esto ayude :)
Bueno, trata de mirar el ancho del teclado. Si es el valor que está esperando, asumo que los valores simplemente se cambian;). 480 tiene sentido como ancho de teclado para ir al paisaje, que es lo que me da esta corazonada.
Si eso falla, simplemente almacene los rectángulos de retrato y paisaje por separado. Están bien documentados ;)
Me encontré con el mismo problema. iOS me da ancho / alto incorrecto del teclado. Usé el siguiente recorte en un controlador keyboardDidShow:
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGSize keyboardSize2 = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
LogDbg(@"keyboard size: frameBegin=%@; frameEnd=%@", NSStringFromCGSize(keyboardSize), NSStringFromCGSize(keyboardSize2));
y para los modos retrato y paisaje de iPad obtuve respectivamente:
2012-06-14 04:09:49.734 -[LoginViewController keyboardDidShow:] 132 [DBG]:keyboard size: frameBegin={768, 264}; frameEnd={768, 264}
2012-06-14 04:10:07.971 -[LoginViewController keyboardDidShow:] 132 [DBG]:keyboard size: frameBegin={352, 1024}; frameEnd={352, 1024}
Suponiendo que el ancho del teclado debería ser mayor que la altura (sí, soy tan ingenuo) hice una solución como la siguiente:
if (keyboardSize.width < keyboardSize.height)
{
// NOTE: fixing iOS bug: http://.com/questions/9746417/keyboard-willshow-and-willhide-vs-rotation
CGFloat height = keyboardSize.height;
keyboardSize.height = keyboardSize.width;
keyboardSize.width = height;
}
Recientemente, escribí una publicación en el blog sobre este problema exacto que describiste y cómo resolverlo de manera breve y elegante. Aquí está el enlace a la publicación: Sincronización de la animación de rotación entre el teclado y la vista adjunta
Si no desea profundizar en la explicación larga que se describe en la publicación del blog, aquí tiene una breve descripción con un ejemplo de código:
El principio básico es usar el mismo método que usan todos: observar las notificaciones del teclado para animar la vista adjunta hacia arriba y hacia abajo. Pero además de eso, tiene que cancelar estas animaciones cuando se activan las notificaciones del teclado como consecuencia del cambio de orientación de la interfaz.
Ejemplo de rotación sin cancelación de animación personalizada en el cambio de orientación de la interfaz:
Ejemplo de rotación con cancelación de animación en el cambio de orientación de la interfaz:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(adjustViewForKeyboardNotification:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(adjustViewForKeyboardNotification:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]
removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]
removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
self.animatingRotation = YES;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
self.animatingRotation = NO;
}
- (void)adjustViewForKeyboardNotification:(NSNotification *)notification {
NSDictionary *notificationInfo = [notification userInfo];
// Get the end frame of the keyboard in screen coordinates.
CGRect finalKeyboardFrame = [[notificationInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
// Convert the finalKeyboardFrame to view coordinates to take into account any rotation
// factors applied to the window’s contents as a result of interface orientation changes.
finalKeyboardFrame = [self.view convertRect:finalKeyboardFrame fromView:self.view.window];
// Calculate new position of the commentBar
CGRect commentBarFrame = self.commentBar.frame;
commentBarFrame.origin.y = finalKeyboardFrame.origin.y - commentBarFrame.size.height;
// Update tableView height.
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.height = commentBarFrame.origin.y;
if (!self.animatingRotation) {
// Get the animation curve and duration
UIViewAnimationCurve animationCurve = (UIViewAnimationCurve) [[notificationInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
NSTimeInterval animationDuration = [[notificationInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// Animate view size synchronously with the appearance of the keyboard.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[UIView setAnimationBeginsFromCurrentState:YES];
self.commentBar.frame = commentBarFrame;
self.tableView.frame = tableViewFrame;
[UIView commitAnimations];
} else {
self.commentBar.frame = commentBarFrame;
self.tableView.frame = tableViewFrame;
}
}
Esta respuesta también se publicó en una pregunta similar: UIView en la parte superior del teclado similar a la aplicación iMessage
Sé que esta es una respuesta muy tardía. Ahora solo me topé con esta situación y encontré la pregunta sin respuesta. Así que pensé en compartir mi solución. Habrá otra forma mejor, pero de la siguiente manera también podemos resolver esto.
El KBKeyboardHandler que usé es de: UITextField: mueve la vista cuando aparece el teclado
Acabo de cambiar mi delegado de la siguiente manera:
- (void)keyboardSizeChanged:(CGSize)delta
{
CGRect frame = self.view.frame;
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
switch (interfaceOrientation) {
case UIInterfaceOrientationPortrait:
frame.origin.y-=delta.height;
break;
case UIInterfaceOrientationPortraitUpsideDown:
frame.origin.y+=delta.height;
break;
case UIInterfaceOrientationLandscapeLeft:
frame.origin.x-=delta.height;
break;
case UIInterfaceOrientationLandscapeRight:
frame.origin.x+=delta.height;
break;
default:
break;
}
self.view.frame = frame;
}
Y estaba funcionando bien.
Tal vez un poco tarde, pero acabo de encontrarme con el mismo problema y tengo una buena solución para eso que evita cualquier tipo de trabajo (a menos que Apple cambie las cosas)
Básicamente, cuando el centro de notificaciones llama a su método para UIKeyboardWillShowNotification
(o cualquiera de las otras notificaciones), el marco que le proporciona para UIKeyboardFrameBeginUserInfoKey
está en el contexto de la ventana, NO de su vista. El problema con esto, es que el sistema de coordenadas de Windows está siempre en vertical, independientemente de la orientación de los dispositivos, por lo tanto, está encontrando el ancho y la altura al revés.
Si desea evitar su trabajo, simplemente convierta el rectángulo en el sistema de coordenadas de su vista (que cambia según la orientación). Para hacer esto, haz algo como lo siguiente:
- (void) keyboardWillShow:(NSNotification *)aNotification
{
CGRect keyboardFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect convertedFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];
......
/* Do whatever you want now with the new frame.
* The width and height will actually be correct now
*/
......
}
Espero que esto sea lo que buscas :)
Uso el siguiente código para obtener el tamaño del teclado que funciona bien para todas las rotaciones
NSDictionary *info = [aNotification userInfo];
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
kbHeight = [[NSNumber numberWithFloat:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.width] floatValue];
else
kbHeight = [[NSNumber numberWithFloat:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height] floatValue];
NSLog(@"keyboard height = %F",kbHeight);
Luego pruebo la orientación utilizando la barra de estado (que funciona en el primer estuche de lanzamiento para el iPad) y cambio la vista en la dirección relativa necesaria para hacer espacio para el teclado. Esto funciona perfectamente, si el teclado es visible, entonces se reubica en la posición correcta en las rotaciones.
UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIDeviceOrientationPortrait)
{
NSLog(@"Orientation: portrait");
self.originalCenter = self.view.center;
self.view.center = CGPointMake(self.originalCenter.x, self.originalCenter.y-kbHeight);
}
if (orientation == UIDeviceOrientationPortraitUpsideDown)
{
NSLog(@"Orientation: portrait upside down");
self.originalCenter = self.view.center;
self.view.center = CGPointMake(self.originalCenter.x, self.originalCenter.y+kbHeight);
}
if (orientation == UIDeviceOrientationLandscapeLeft)
{
NSLog(@"Orientation: landscape left");
self.originalCenter = self.view.center;
self.view.center = CGPointMake(self.originalCenter.x+kbHeight,self.originalCenter.y);
}
if (orientation == UIDeviceOrientationLandscapeRight)
{
NSLog(@"Orientation: landscape right");
self.originalCenter = self.view.center;
self.view.center = CGPointMake(self.originalCenter.x-kbHeight,self.originalCenter.y);
}
Puede devolver la vista a su posición original cuando el teclado desaparece o mediante una función textFileDidEndEditing.