El teclado del iPad no se descartará si el estilo de presentación modal de ViewController es UIModalPresentationFormSheet


214

Nota:

Vea la respuesta aceptada (no la más votada) para la solución a partir de iOS 4.3.

Esta pregunta es sobre un comportamiento descubierto en el teclado del iPad, donde se niega a ser descartado si se muestra en un diálogo modal con un controlador de navegación.

Básicamente, si presento el controlador de navegación con la siguiente línea de la siguiente manera:

navigationController.modalPresentationStyle = UIModalPresentationFormSheet;

El teclado se niega a ser descartado. Si comento esta línea, el teclado desaparece bien.

...

Tengo dos campos de texto, nombre de usuario y contraseña; el nombre de usuario tiene un botón Siguiente y la contraseña tiene un botón Listo. El teclado no desaparecerá si presento esto en un controlador de navegación modal.

TRABAJOS

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
[self.view addSubview:b.view];

NO FUNCIONA

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
[[UINavigationController alloc]
 initWithRootViewController:b];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
navigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

Si elimino la parte del controlador de navegación y presento 'b' como un controlador de vista modal por sí mismo, funciona. ¿Es el controlador de navegación el problema?

TRABAJOS

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
b.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:b animated:YES];
[b release];

TRABAJOS

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
    [[UINavigationController alloc]
         initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

La siguiente pregunta SO parece tener el mismo problema, pero no hay respuestas: stackoverflow.com/questions/3019709/…
Kalle

+1 Gracias por tu gran explicación. Pero, ¿dónde tengo que poner ese método? Parece que no funciona donde creo el código para presentar el controlador del modelo ...
Lorenzo B

1
Tiene que estar en la clase modal del controlador de vista en sí.
Kalle

Gracias. Veo. Resolví ponerlo en una categoría para la UINavigationControllerclase. Salud.
Lorenzo B

Estoy tan en deuda con usted por esta pregunta. Me sorprendió que se resignFirstResponderestuviera ejecutando pero el teclado aún se mostraba. Mi escenario (presentationFormSheet con navig contrllr) es exactamente el mismo que el suyo. ¡¡Gracias una tonelada!!
sErVerdevIL

Respuestas:


115

En el controlador de vista que se presenta modalmente, simplemente anule disablesAutomaticKeyboardDismissalpara devolver NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

Sí, desde 4.3 este parece ser el caso. Se actualizará la pregunta. ¡Gracias!
Kalle

2
Esto debe agregarse al controlador de navegación
pottedmeat

1
Sí, funciona cuando lo sobrescribe en el NavigationController. Eso es lo único que realmente funcionó para mí.
James Laurenstin

Salvavidas! ¿Por qué Apple hace cosas como esta? Seguramente debería tener el valor predeterminado NO y permitirnos cambiarlo si realmente queremos
SomaMan

No funciona en la clase derivada de UIViewController, deshabilitaAutomaticKeyboardDismissal nunca se llama
Jorge Arimany

172

Esto ha sido clasificado como "funciona según lo previsto" por los ingenieros de Apple. Archivé un error para esto hace un tiempo. Su razonamiento es que el usuario a menudo va a ingresar datos en una forma modal, por lo que intentan ser "útiles" y mantener el teclado visible donde normalmente varias transiciones dentro de la vista modal pueden hacer que el teclado se muestre / oculte repetidamente.

editar: aquí está la respuesta de un ingeniero de Apple en los foros de desarrolladores:

¿Tu vista fue presentada por casualidad con el estilo UIModalPresentationFormSheet? Para evitar animaciones frecuentes de entrada y salida, el teclado a veces permanecerá en la pantalla incluso cuando no haya un primer respondedor. Esto no es un error.

Esto le está dando problemas a muchas personas (incluido yo mismo) pero en este momento no parece haber una forma de solucionarlo.

ACTUALIZAR:

En iOS 4.3 y versiones posteriores, ahora puede implementar `-disablesAutomaticKeyboardDismissal 'en su controlador de vista para devolver NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

Esto soluciona el problema.


77
pausa Wow, está bien. Muchas gracias por el aviso. Damn Apple .. :(
Kalle

¿Enviaste un informe de error a Apple? Lo hice con el ID # 8384423. También presenté una solicitud de muestra para reproducir el comportamiento.
Shaggy Frog

3
A partir de iOS 4.3 ahora hay un método disablesAutomaticKeyboardDismissal que soluciona este problema.
Kalle

55
Intento que deshabilita el método de teclado automático automático, pero aún así no resolvió el problema, ¿cómo resolverlo?
R. Dewi

3
@Snips: debe crear una UINavigationControllersubclase que se anule disablesAutomaticKeyboardDismissalpara devolver NOy usar esto como controlador de navegación cuando presente una hoja de formulario modal. Vea la respuesta de @ miha-hribar a continuación.
Pascal

149

Tenga cuidado si está mostrando el modal con a UINavigationController. Luego debe configurarlo disablesAutomaticKeyboardDismissalen el controlador de navegación y no en el controlador de vista. Puedes hacer esto fácilmente con categorías.

Archivo: UINavigationController + KeyboardDismiss.h

#import <Foundation/Foundation.h>

@interface UINavigationController (KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal;

@end

Archivo: UINavigationController + KeyboardDismiss.m

#import "UINavigationController+KeyboardDismiss.h"

@implementation UINavigationController(KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal
{
    return NO;
}

@end

No olvide importar la categoría en el archivo donde usa UINavigationController.


19
1, por fin ver la pieza que falta de la información para este problema puesto de manifiesto: que uno tiene que anulan disablesAutomaticKeyboardDismissalde UINavigationController, no el propio controlador de vista, para solucionar este problema.
DarkDust

¡Agradable! Justo lo que necesitaba. Gracias.
Justin

Perfecto. No está claro en los documentos oficiales, pero tiene sentido debido a que UINavigationController está en la cadena de respuesta. Excelente respuesta ¡Gracias!
imnk

1
Estoy presentando un diálogo modal desde un UISplitViewController. Intenté el código anterior, pero sustituí UISplitViewController por UINavigationController, pero aún no funciona. ¿Este método también debería funcionar en un UISplitViewController?
Snips

66
No es una buena idea implementar un método duplicado en una categoría. Nunca puede estar seguro de qué implementación se llamará, por lo que, en el mejor de los casos, puede esperar un comportamiento inconsistente. Es mejor heredar de UINavigationController y anular el método en su clase personalizada.
Sean Woodward

51

Resolví esto usando el UIModalPresentationPageSheetestilo de presentación y redimensionándolo inmediatamente después de presentarlo. Al igual que:

viewController.modalPresentationStyle = UIModalPresentationPageSheet;
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
viewController.view.superview.autoresizingMask = 
    UIViewAutoresizingFlexibleTopMargin | 
    UIViewAutoresizingFlexibleBottomMargin;    
viewController.view.superview.frame = CGRectMake(
    viewController.view.superview.frame.origin.x,
    viewController.view.superview.frame.origin.y,
    540.0f,
    529.0f
);
viewController.view.superview.center = self.view.center;
[viewController release];

Hmmm ... esto no está del todo bien ... el cambio de tamaño hace que el modal pinte divertido ... es como si aplastara el contenido para que quepa en el nuevo cuadro de tamaño o algo así ... todo parece divertido. :(
toofah

También hay problemas de rotación con este ... si gira mientras este modal está activo, se reducirá / crecerá como si fuera una vista de página completa
toofah

2
Toofah, edité el código para tratar el problema de reducción / crecimiento al rotar; solo es cuestión de darle a la supervista un margen superior e inferior flexible. No estoy seguro de ver el otro comportamiento.
azdev

1
esto funciona solo mientras no presione otra vista encima de esta. Porque cuando cierra la vista empujada por encima de la vista presentada por UIModalPresentationPageSheet, vuelve a su tamaño original.
V1ru8

Funcionó. Pero la palabra en la vista se ve un poco borrosa. No se porque.
jeswang

1

Si alterna una pantalla modal diferente, puede hacer que el teclado desaparezca. No es bonito y no se anima, pero puedes hacer que desaparezca.

Sería genial si hubiera una solución, pero por ahora esto funciona. Puedes ponerlo en una categoría UIViewControllery llamarlo cuando quieras que el teclado desaparezca:

@interface _TempUIVC : UIViewController
@end

@implementation _TempUIVC
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
@end

@implementation UIViewController (Helpers)

- (void)_dismissModalViewController {
    [self dismissModalViewControllerAnimated:NO];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [self release];
}

- (void)forceKeyboardDismissUsingModalToggle:(BOOL)animated {
    [self retain];
    _TempUIVC *tuivc = [[_TempUIVC alloc] init];
    tuivc.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentModalViewController:tuivc animated:animated];
    if (animated) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_dismissModalViewController) name:UIKeyboardDidHideNotification object:nil];
    } else
        [self _dismissModalViewController];
    [tuivc release];
}

@end

Sin embargo, tenga cuidado con esto cuando veaDidAppear / viewDidDisappear y se invoquen todos esos métodos. Como dije, no es bonito, pero funciona.

-Adán


1

También puede solucionar esto en una aplicación universal simplemente comprobando el idioma y, si se trata de un iPad, no abra el teclado automáticamente y deje que el usuario toque lo que quiera editar.

Puede que no sea la mejor solución, pero es muy sencillo y no necesita ningún truco elegante que rompa con la próxima versión principal de iOS :)


1

Ponga este código en su vista WillDisappear: el método del controlador actual es otra forma de solucionar esto:

Class UIKeyboardImpl = NSClassFromString(@"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:@selector(activeInstance)];
[activeInstance performSelector:@selector(dismissKeyboard)];

1

Encontré eso disablesAutomaticKeyboardDismissaly agregar una disablesAutomaticKeyboardDismissalfunción no funcionó para miUITextField en un diálogo modal.

El teclado en pantalla simplemente no desaparecería.

Mi solución fue deshabilitar todos los controles de entrada de texto en mi cuadro de diálogo, y luego volver a habilitar los relevantes una fracción de segundo más tarde.

Parece que cuando iOS ve que ninguno de los UITextFieldcontroles están habilitados, entonces no deshacerse del teclado.


0

Estoy seguro de que ha visto esto, pero está seguro de que su clase de controlador está correctamente conectada como delegado de UITextField, ¿verdad?


Lo configuré manualmente, y los métodos de delegado se llaman, así que sí.
Kalle

0

tal vez no devuelva NO, pero SÍ. Entonces puede desaparecer.

¿Y también tienes un textFieldShouldEndEditingSI?

¿ Y por qué estás disparando [nextResponder becomeFirstResponder]? lo siento, veo ahora

También tengo un número de UITextViews que tienen su propiedad "editable" establecida en FALSE.

¿Podemos suponer que ninguno de ellos, por casualidad, tiene un tagvalor de secondField.tag+1? Si es así, les está diciendo que se conviertan en el primer respondedor, en lugar de renunciar al primer respondedor. Tal vez ponga algo de NSLog () en esa estructura if.


1
NO = no inserte nueva línea, por lo que puedo decir. Y establecerlo en SÍ no lo solucionó.
Kalle

1
Un UITextField, siendo una línea por definición, no hace mucho con las nuevas líneas, creo. Por lo tanto, se trata más de procesar presionar el botón Volver / Listo, como se indica en los documentos.
mvds

¿Estás seguro de haber conectado todo de la manera correcta? ¿Ha puesto un NSLog("tf %x / method ...",textField);en todas las funciones de delegado?
mvds

Bueno, las funciones de delegado se invocan de manera adecuada, y no lo serían si el delegado no estuviera configurado adecuadamente. Y el NSLog da un EXC_BAD_ACCESS. También me advierte acerca de que sea un tipo incompatible en XCode.
Kalle

D'oh Lo siento, debería haberlo visto yo mismo. He actualizado la respuesta anterior con los resultados de estos NSLogs Ya que el formateo se gook sí en comunicación ..
Kalle

0

Para aquellos que tienen problemas con UINavigationController, vea mi respuesta a una pregunta similar aquí: https://stackoverflow.com/a/10507689/321785

Editar: Considero que esto es una mejora para la solución de Miha Hribar (ya que la decisión se está tomando donde debería), y a diferencia del comentario de Pascal con respecto a una categoría en UIViewController


0

puede no ser una solución perfecta, pero funciona
[self.view endEditing: YES];
desde donde se implementa su botón o gesto para presentar modal


0
Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.