Animar el teclado en sincronía con UIView mientras se desliza de nuevo en iOS7
iphone keyboard (3)
Me gustaría obtener el comportamiento similar a la aplicación Messages (también es común en la mayoría de las aplicaciones de mensajes de texto) en iOS7, donde en una vista de conversación, deslizar el dedo desde el borde izquierdo de la pantalla se comporta como el botón de retroceso en un controlador UINavigation.
He logrado implementar este comportamiento, sin embargo, si el teclado está abierto en la vista de presentación, cuando comienzo a deslizar hacia atrás, el teclado se atasca y no se anima con la vista a la derecha cuando muevo el dedo. Me gustaría animar el teclado y la vista de presentación como una unidad, no como si el teclado estuviera encima de las otras vistas y estuvieran animándose detrás, lo que obtengo ahora (vea la segunda captura de pantalla):
( ACTUALIZACIÓN: tenga en cuenta que el teclado eventualmente desaparecerá una vez finalizada la animación de la vista principal; en lo que estoy enfocado es en la posición del teclado durante el proceso de deslizamiento, y cuando sigue tocando el dispositivo por la mitad del camino, no está sincronice con la vista real. La segunda captura de pantalla aclara el comportamiento deseado. También me pregunto por qué no es el predeterminado.
Es fácil replicar el problema simplemente creando una nueva aplicación de iPhone con detalles maestros en Xcode 5.0.2 y agregando un Campo de texto a la vista de detalles (preferiblemente en algún lugar en la mitad superior) en el Tablero de Historias, ejecutando la aplicación, agregando un elemento , tocándolo para ir a la vista de detalles y hacer clic en el campo de texto que agregó. Deslice el borde desde el lado izquierdo del dispositivo mientras mantiene el dedo sobre él y verá el problema.
Comportamiento deseado:
Comportamiento actual:
Simplemente debería funcionar automáticamente, pero a veces no es así debido a algunas condiciones.
Si el firstResponder
actual se encuentra dentro de UIViewController
activo y se despide a través del mecanismo UINavigationController
, la animación del teclado (horizontal) esperada se realizará automáticamente. Por lo tanto, a veces este comportamiento predeterminado se rompe por otros factores extraños y el teclado comienza a desaparecer con una animación deslizante en lugar de una animación horizontal.
Pasé algunos días con tareas de depuración de UIKit interno (alrededor de los métodos needDeferredTransition
allowCustomTransition
needDeferredTransition
, allowCustomTransition
y otros) para encontrar un factor especial que juega un papel clave en mi caso.
Descubrí que la lógica dentro de UIPeripheralHost
verifica el frame
de la UIViewConroller
actual de UIViewConroller
, el frame
de la vista de UINavigationController
(contenedor) y el size
pantalla y, si no es igual entre sí, UIPeripheralHost
decide que esta situación actual parece una ventana modal y establece la bandera allowCustomTransition = NO
. Esa desactivación de UINavigationController
animación horizontal específica.
Solucionar el problema con el frame
s soluciona completamente mi problema.
Si experimenta los mismos problemas, puede intentar depurar los elementos UIKit internos con estos métodos privados y encontrar las condiciones que desactivan la animación horizontal:
Puede usar https://github.com/cotap/TAPKeyboardPop si no necesita nada especial.
En mi caso, tengo algo de lógica conectada con UIKeyboardWillShowNotification
y UIKeyboardWillHideNotification
que se UIKeyboardWillShowNotification
UIKeyboardWillHideNotification
de "deslizar hacia atrás". Combino esta respuesta con TAPKeyboardPop
y esto es lo que tengo:
- (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated {
[super beginAppearanceTransition:isAppearing animated:animated];
if (isAppearing || !animated || !_keyboardIsShown) {
return;
}
if ([self respondsToSelector:@selector(transitionCoordinator)]) {
UIView *keyboardView = self.searchBar.inputAccessoryView.superview;
[self.searchBar becomeFirstResponder];
[self.transitionCoordinator animateAlongsideTransitionInView:keyboardView
animation:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
CGRect endFrame = CGRectOffset(keyboardView.frame, CGRectGetWidth(keyboardView.frame), 0);
keyboardView.frame = endFrame;
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
if (![context isCancelled]) {
[self.searchBar resignFirstResponder];
}
}];
}
}
EDITAR:
He agregado la compatibilidad y la lógica de iOS7 para saber cuándo se muestra el teclado ( _keyboardIsShown
se establece en UIKeyboardWillShowNotification/UIKeyboardWillHideNotification
o en UIKeyboardDidHideNotification/UIKeyboardDidShowNotification
).
Desafortunadamente, no hay un método incorporado para hacer eso. Realmente espero que haya algo como UIScrollViewKeyboardDismissModeInteractive
para UIViewController
s.
Por ahora, para hacer animaciones intermedias entre viewControllers, debes usar unitor de transitionCoordinator :
- (BOOL)animateAlongsideTransition:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))animation
completion:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))completion;
- (BOOL)animateAlongsideTransitionInView:(UIView *)view
animation:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))animation
completion:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))completion;
Para el teclado debes hacer algo como esto:
[self.transitionCoordinator animateAlongsideTransitionInView:self.keyboardSuperview
animation:
^(id<UIViewControllerTransitionCoordinatorContext> context) {
self.keyboardSuperview.x = self.view.width;
}
completion:nil];
En cuanto a keyboardSuperview
, puede obtenerlo creando un inputAccessoryView
falso:
self.textField.inputAccessoryView = [[UIView alloc] init];
Entonces la supervisión será self.textField.inputAccessoryView.superview