¿Forma fácil de descartar el teclado?


377

Tengo bastantes controles dispersos por muchas celdas de tabla en mi tabla, y me preguntaba si hay una manera más fácil de descartar el teclado sin tener que recorrer todos mis controles y renunciar a todos como el primer respondedor. Supongo que la pregunta es ... ¿Cómo obtendría la primera respuesta actual al teclado?


buen complemento a esta pregunta: stackoverflow.com/questions/1490573/…
ericsoco

Una advertencia a todas las respuestas a continuación. Si realiza una segue justo después de renunciar a la KB, la KB queda huérfana y no se puede descartar. Debe descartar la KB en el método textFieldShouldReturn.
gjpc

26
[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
Descanso

Encontré este video útil pinkstone.co.uk/… . Quizás pueda ayudar a otros.
enthusiasticgeek

Respuestas:


797

Tratar:

[self.view endEditing:YES];

1
Esto parece funcionar (probado en ios4.1). Aunque solo está disponible en iOS 3.2 en adelante. No estoy seguro de si esto realmente garantiza que funcione, o es solo un efecto secundario no garantizado de llamar a una API de una manera que no está documentada para funcionar.
JosephH

3
Esto funcionó perfectamente para mí, y ciertamente es preferible a algunas de las otras respuestas a esta pregunta. Los documentos dicen que está disponible en iOS 2.0 y versiones posteriores.
antsyawn

8
Como dice la documentación: "Este método analiza la vista actual y su jerarquía de subvista para el campo de texto que actualmente es el primer respondedor. Si encuentra uno, le pide a ese campo de texto que renuncie como primer respondedor. Si se establece el parámetro de fuerza a SÍ, el campo de texto nunca se pregunta; se ve obligado a renunciar ". - Entonces, esta es la respuesta correcta de la OMI a la pregunta original (caso de uso: tengo un formulario con millones de campos, bueno, diez ... más o menos, y necesito descartar el teclado).
joshis

14
La respuesta no es incorrecta, pero es un poco incorrecta, en realidad debería serlo: los [self.view endEditing:YES];valores BOOL son SÍ / NO en Objective-C.
chrisben

24
Chrisben: puede usar SÍ / NO, VERDADERO / FALSO, 0/1.
Michael Superczynski

126

Puede forzar la vista de edición actual para que renuncie a su primer estado de respuesta con [view endEditing:YES]. Esto oculta el teclado.

A diferencia -[UIResponder resignFirstResponder], -[UIView endEditing:]buscará en subvistas para encontrar el primer respondedor actual. Por lo tanto, puede enviarlo a su vista de nivel superior (por ejemplo, self.viewen a UIViewController) y hará lo correcto.

(Esta respuesta anteriormente incluía un par de otras soluciones, que también funcionaron pero fueron más complicadas de lo necesario. Las eliminé para evitar confusiones).


Pero eso solo impedirá que el componente se convierta en firstResponder, no eliminará el estado actual de firstResponder de un elemento.
Kendall Helmstetter Gelner el

Lo que quise decir al anular se convirtió en FirstResponder para almacenar el primer respondedor en algún lugar, para que se pueda acceder (en este caso, renunciar) más tarde. El problema básico es que Cocoa Touch no proporciona una manera de preguntar una ventana o ver cuál es su primer respondedor.
Nicholas Riley el

+1 Al agregar BecomeFirstResponder se resolvieron los problemas que tenía con toques en otros UITextFields.
Jason George

3
Esto es obsoleto. La [self.view endEditing:YES];respuesta es mejor.
ftvs

1
Esto no es obsoleto, esta respuesta explica exactamente cómo [UIView endediting:]funciona. En una de las aplicaciones que he desarrollado, se agregó un cuadro de búsqueda en UINavigationViewController, si solo llama [self.view endEditing:YES], como selfsu controlador de vista, esto no funcionará, en su lugar, llamé a este método directamente en el alcance de la vista donde se agregó el cuadro de búsqueda, por ejemplo: [self.mySearchBoxView endEditing:YES].
Jan Cássio

92

Puede enviar una acción específica nula a la aplicación, renunciará al primer respondedor en cualquier momento sin tener que preocuparse sobre qué vista tiene actualmente el estado del primer respondedor.

C objetivo:

[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

Swift 3.0:

UIApplication.shared.sendAction(#selector(resignFirstResponder), to: nil, from: nil, for: nil)

Las acciones dirigidas a cero son comunes en Mac OS X para los comandos de menú, y aquí hay un uso para ellas en iOS.


14
La mejor solución de toda la página.
Leo Natan

Absolutamente la mejor manera de deshacerse del teclado desde cualquier lugar en la aplicación iOS.
Ben Sinclair

Todavía funciona para mí en iOS8. En mi aplicación, tengo un menú de barra lateral, y hay veces que el controlador de vista "central" muestra el teclado. Y quiero descartar el teclado si aparece el menú de la barra lateral. Así que agregué este código en el menú de mi barra lateral Método de clase 'viewWillAppear'.
Jenn Eve

1
Todavía funciona en iOS 9. Excelente forma de renunciar globalmente al enfoque de un campo de texto y descartar el teclado.
bmjohns

Y para continuar esta racha de comentarios en particular ... Todavía funciona en iOS 10. :-)
Travelling Man

56

Para ser honesto, no estoy loco por ninguna de las soluciones propuestas aquí. Encontré una buena manera de usar un TapGestureRecognizer que creo que llega al corazón de su problema: cuando hace clic en cualquier cosa que no sea el teclado, descarte el teclado.

  1. En viewDidLoad, regístrese para recibir notificaciones de teclado y cree un UITapGestureRecognizer:

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    
    [nc addObserver:self selector:@selector(keyboardWillShow:) name:
    UIKeyboardWillShowNotification object:nil];
    
    [nc addObserver:self selector:@selector(keyboardWillHide:) name:
    UIKeyboardWillHideNotification object:nil];
    
    tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
    action:@selector(didTapAnywhere:)];
  2. Agregue el teclado mostrar / ocultar respondedores. Allí agrega y elimina el TapGestureRecognizer a la UIView que debería descartar el teclado cuando se toca. Nota: No tiene que agregarlo a todas las subvistas o controles.

    -(void) keyboardWillShow:(NSNotification *) note {
        [self.view addGestureRecognizer:tapRecognizer];
    }
    
    -(void) keyboardWillHide:(NSNotification *) note
    {
        [self.view removeGestureRecognizer:tapRecognizer];
    }
  3. TapGestureRecognizer llamará a su función cuando reciba un toque y puede cerrar el teclado de esta manera:

    -(void)didTapAnywhere: (UITapGestureRecognizer*) recognizer {    
        [textField resignFirstResponder];
    }

Lo bueno de esta solución es que solo filtra por Taps, no por deslizamientos. Por lo tanto, si tiene contenido desplazable sobre el teclado, los desplazamientos seguirán desplazándose y dejarán el teclado en pantalla. Al eliminar el reconocedor de gestos después de que el teclado se ha ido, los toques futuros en su vista se manejan normalmente.


A mi @implementation agregué @property (asignar) UITapGestureRecognizer * tapRecognizer; y modificado self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector (didTapAnywhere :)];
Profesor Todd

Estoy tratando de hacer algo similar y no recibo la devolución de llamada. Curioso: ¿por qué se 'asigna' su propiedad?
TahoeWolverine

Más uno, y además este debería ser el comportamiento predeterminado de iOS. O al menos agregue una forma simple de alternar un botón de descartar.
Shaunti Fondrisi

24

Esta es una solución para hacer que el teclado desaparezca cuando se presiona returnen cualquier campo de texto, agregando código en un lugar (por lo que no tiene que agregar un controlador para cada campo de texto):


considere este escenario:

Tengo un viewcontrollercon dos campos de texto (nombre de usuario y contraseña). y el protocolo de viewcontrollerimplementosUITextFieldDelegate

hago esto en viewDidLoad

- (void)viewDidLoad 
{
    [super viewDidLoad];

    username.delegate = self;
    password.delegate = self;
}

y el viewcontroller implementa el método opcional como

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

e independientemente del campo de texto en el que se encuentre, tan pronto como presione returnel teclado, ¡se descarta!

En su caso, lo mismo funcionaría siempre que configure todo el delegado del campo de texto para autoejecutar e implementar textFieldShouldReturn


Bueno, ya tengo el problema resuelto, pero en mi caso quería descartar el teclado por mi cuenta (en código), y no sabía qué textField tenía el estado de primer respondedor.
Seventoes

1
Hay casos en los que es posible que desee cerrar el teclado sin presionar "regresar", por ejemplo, cuando un menú de la barra lateral está a punto de mostrarse
Peter Johnson

Editado para aclarar que esta respuesta solo es relevante en situaciones en las que presionar "regresar" es una solución aceptable. [En mi caso, también quería descartar el teclado cuando el usuario toca fuera del campo que se está editando; esta respuesta no ayuda con eso.]
ToolmakerSteve

14

Un mejor enfoque es tener algo "robar" el estado del primer respondedor.

Como UIApplication es una subclase de UIResponder, puede intentar:

[[UIApplication sharedApplication] becomeFirstResponder]
[[UIApplication sharedApplication] resignFirstResponder]

De lo contrario, cree un nuevo UITextField con un marco de tamaño cero, agréguelo a una vista en algún lugar y haga algo similar (seguido de la renuncia).


1
El truco de la aplicación UIA no funciona (se bloquea, al menos en el simulador) pero no necesita un UITextField de tamaño cero: simplemente elija cualquier campo aleatorio y haga esto con él. NSResponder se convierte en FirstResponder es solo un método de notificación, pero UIResponder no lo es (el diseño es peor, en realidad).
Nicholas Riley, el

1
Ajá, gracias! Se bloquea al llamarlo en la aplicación UIA pero el UITextField de tamaño cero funciona muy bien, y no tengo que recuperar ninguno de mis campos anteriores.
Seventoes

¿Por qué alguien haría esto si hay un método oficial, perfectamente bueno y documentado para esto?
Maciej Swic

2
No verían la respuesta más votada para la mejor solución. Simplemente no era muy conocido en ese momento (mi respuesta fue de 2009, la otra respuesta llegó más de un año después en 2010). pero lo dejo para la posteridad.
Kendall Helmstetter Gelner

8

Guarda esto en alguna clase de utilidad.

+ (void)dismissKeyboard {
    [self globalResignFirstResponder];
}

+ (void) globalResignFirstResponder {
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    for (UIView * view in [window subviews]){
        [self globalResignFirstResponderRec:view];
    }
}

+ (void) globalResignFirstResponderRec:(UIView*) view {
    if ([view respondsToSelector:@selector(resignFirstResponder)]){
        [view resignFirstResponder];
    }
    for (UIView * subview in [view subviews]){
        [self globalResignFirstResponderRec:subview];
    }
}

1
¡Esto es lo que estaba buscando!
aslisabanci

Perfecto, excepto que no necesita el método globalResignFirstResponderRec en absoluto, solo llame a [view endEditing: YES] en su lugar. Hace la misma cosa.
n13

¡Si! ¡La solución definitiva! Lo intenté de muchas maneras, ¡solo esta funciona para mí! ¡Muchas gracias!
douyw

6

@Nicholas Riley y @Kendall Helmstetter Geln y @cannyboy:

¡Absolutamente brillante!

Gracias.

Teniendo en cuenta sus consejos y los consejos de otros en este hilo, esto es lo que he hecho:

Cómo se ve cuando se usa:

[[self appDelegate] dismissKeyboard]; (nota: agregué appDelegate como una adición a NSObject para poder usar en cualquier lugar en cualquier cosa)

Cómo se ve debajo del capó:

- (void)dismissKeyboard 
{
    UITextField *tempTextField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
    tempTextField.enabled = NO;
    [myRootViewController.view addSubview:tempTextField];
    [tempTextField becomeFirstResponder];
    [tempTextField resignFirstResponder];
    [tempTextField removeFromSuperview];
}

EDITAR

Enmienda a mi respuesta a incluido tempTextField.enabled = NO;. La desactivación del campo de texto evitará UIKeyboardWillShowNotificationy UIKeyboardWillHideNotificationnotificaciones que se envían desde el teclado debe confiar en que estas notificaciones a través de su aplicación.


No sé si funciona, pero parece una forma inteligente y fácil.
demonio

5

Consejo rápido sobre cómo descartar el teclado en iOS cuando un usuario toca cualquier parte de la pantalla fuera del UITextField o el teclado. Teniendo en cuenta la cantidad de espacio que puede ocupar el teclado iOS, tiene sentido tener una forma fácil e intuitiva para que sus usuarios descarten el teclado.

Aquí hay un enlace


¡Excelente! agregar a AppDelegate hace que funcione para TODAS las vistas relacionadas.
Jiulong Zhao

5

Aquí hay muchas respuestas demasiado complicadas, tal vez porque no es fácil de encontrar en la documentación de iOS. JosephH lo tenía justo arriba:

[[view window] endEditing:YES];

4

Incluso más simple que la respuesta de Meagar

Sobrescribir touchesBegan:withEvent:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [textField resignFirstResponder];`
}

Esto lo hará dismiss the keyboardcuando toques cualquier parte del background.


3

Esto es lo que uso en mi código. ¡Funciona a las mil maravillas!

En yourviewcontroller.h agregue:

@property (nonatomic) UITapGestureRecognizer *tapRecognizer;

Ahora en el archivo .m, agregue esto a su función ViewDidLoad:

- (void)viewDidLoad {
    //Keyboard stuff
    tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapAnywhere:)];
    tapRecognizer.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:tapRecognizer];
}

Además, agregue esta función en el archivo .m:

- (void)handleSingleTap:(UITapGestureRecognizer *) sender
{
    [self.view endEditing:YES];
}

¡Gracias! Pero debe cambiar el nombre de la función a 'didTapAnywhere' o el reconocedor de gestos a 'handleSingleTap' ;-)
Matthijs

2

En el archivo de encabezado de su controlador de vista, agregue <UITextFieldDelegate>a la definición de la interfaz de su controlador para que se ajuste al protocolo delegado UITextField ...

@interface someViewController : UIViewController <UITextFieldDelegate>

... En el archivo de implementación del controlador (.m) agregue el siguiente método, o el código dentro de él si ya tiene un método viewDidLoad ...

- (void)viewDidLoad
{
    // Do any additional setup after loading the view, typically from a nib.
    self.yourTextBox.delegate = self;
}

... Luego, vincula tu TextBox a tu campo de texto real

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField 
{
    if (theTextField == yourTextBox) {
        [theTextField resignFirstResponder];
    }
    return YES;
}

2

Debe enviar endEditing:a la ventana de trabajo siendo la subclase deUIView

[[UIApplication sharedApplication].windows.firstObject endEditing:NO];

Apuesto a que querías decir SÍ)
Matrosov Alexander

2

La mejor manera de descartar el teclado de UITableView y UIScrollView son:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag

2

En swift 3 puedes hacer lo siguiente

UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)

1

La respuesta de Jeremy no me funcionó, creo que porque tenía una pila de navegación en una vista de pestaña con un diálogo modal encima. Estoy usando lo siguiente en este momento y está funcionando para mí, pero su kilometraje puede variar.

 // dismiss keyboard (mostly macro)
[[UIApplication sharedApplication].delegate dismissKeyboard]; // call this in your to app dismiss the keybaord

// --- dismiss keyboard (in indexAppDelegate.h) (mostly macro)
- (void)dismissKeyboard;

// --- dismiss keyboard (in indexAppDelegate.m) (mostly macro)
// do this from anywhere to dismiss the keybard
- (void)dismissKeyboard {    // from: http://stackoverflow.com/questions/741185/easy-way-to-dismiss-keyboard

    UITextField *tempTextField = [[UITextField alloc] initWithFrame:CGRectZero];

    UIViewController *myRootViewController = <#viewController#>; // for simple apps (INPUT: viewController is whatever your root controller is called.  Probably is a way to determine this progragrammatically)
    UIViewController *uivc;
    if (myRootViewController.navigationController != nil) { // for when there is a nav stack
        uivc = myRootViewController.navigationController;
    } else {
        uivc = myRootViewController;
    }

    if (uivc.modalViewController != nil) { // for when there is something modal
        uivc = uivc.modalViewController;
    } 

    [uivc.view  addSubview:tempTextField];

    [tempTextField becomeFirstResponder];
    [tempTextField resignFirstResponder];
    [tempTextField removeFromSuperview];
    [tempTextField release];

}

Hmm, ¿por qué el voto negativo? Abordé las deficiencias específicas del mundo real en otra respuesta con código probado. Puedo entender la falta de votos positivos, pero votarme en territorio negativo es un verdadero desánimo. Todavía espero que la respuesta anterior ayude a alguien más.
JJ Rohrer

1

También es posible que deba anular UIViewController deshabiliteAutomaticKeyboardDismissal para que esto funcione en algunos casos. Es posible que esto deba hacerse en el UINavigationController si tiene uno.


1

Subclase sus campos de texto ... y también vistas de texto

En la subclase pon este código ...

-(void)conformsToKeyboardDismissNotification{

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissKeyBoard) name:KEYBOARD_DISMISS object:nil];
}

-(void)deConformsToKeyboardDismissNotification{

    [[NSNotificationCenter defaultCenter] removeObserver:self name:KEYBOARD_DISMISS object:nil];
}

- (void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self resignFirstResponder];
}

En el campo de texto delegados (de manera similar para los delegados de vista de texto)

-(void)textFieldDidBeginEditing:(JCPTextField *)textField{
     [textField conformsToKeyboardDismissNotification];
}


- (void)textFieldDidEndEditing:(JCPTextField *)textField{
    [textField deConformsToKeyboardDismissNotification];
}

Todo listo ... Ahora solo publique la notificación desde cualquier parte de su código. Renunciará a cualquier teclado.


1

Y en rapidez podemos hacer

UIApplication.sharedApplication().sendAction("resignFirstResponder", to: nil, from: nil, forEvent: nil)

No entiendo cómo funciona el primer respondedor ... ¿dónde pongo esto? en mi controlador de vista o delegado?
Shayan C

No importa Puedes ponerlo donde quieras. es decir, acción del botón
Eike

1

Para descartar un teclado después de que el teclado ha aparecido, hay 2 casos ,

  1. cuando UITextField está dentro de un UIScrollView

  2. cuando UITextField está fuera de UIScrollView

2.cuando el UITextField está fuera de UIScrollView, anule el método en su subclase UIViewController

también debe agregar delegado para todos los UITextView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}
  1. En una vista de desplazamiento, Tocar afuera no activará ningún evento , por lo que en ese caso use un Reconocimiento de gestos de toque , arrastre y suelte un UITapGesture para la vista de desplazamiento y cree una IBAction para ello .

para crear una IBAction, presione ctrl + clic en UITapGesture y arrástrelo al archivo .h de viewcontroller.

Aquí he nombrado tappedEvent como mi nombre de acción

- (IBAction)tappedEvent:(id)sender {
      [self.view endEditing:YES];  }

la información proporcionada anteriormente se obtuvo del siguiente enlace, consulte para obtener más información o contácteme si no comprende los datos anteriores.

http://samwize.com/2014/03/27/dismiss-keyboard-when-tap-outside-a-uitextfield-slash-uitextview/


0

Odio que no haya una forma "global" de descartar programáticamente el teclado sin usar llamadas privadas de API. Con frecuencia, tengo la necesidad de descartar el teclado mediante programación sin saber qué objeto es el primer respondedor. He recurrido a inspeccionar el selfuso de la API de tiempo de ejecución Objective-C, enumerar todas sus propiedades, extraer aquellas que son de tipo UITextFieldy enviarles el resignFirstRespondermensaje.

No debería ser tan difícil hacer esto ...


0

No es bonito, pero la forma en que renuncio al primer Respondedor cuando no sé cuál es ese respondedor:

Cree un UITextField, ya sea en IB o mediante programación. Hazlo oculto. Vincúlelo a su código si lo hizo en IB. Luego, cuando desea cerrar el teclado, cambia el respondedor al campo de texto invisible e inmediatamente lo renuncia:

  [self.invisibleField becomeFirstResponder];
  [self.invisibleField resignFirstResponder];

0

Puede iterar recursivamente a través de subvistas, almacenar una matriz de todos los UITextFields, y luego recorrerlos y renunciar a todos.

No es realmente una gran solución, especialmente si tiene muchas subvistas, pero para aplicaciones simples debería ser el truco.

Resolví esto de una manera mucho más complicada, pero mucho más eficiente, pero usando un singleton / manager para el motor de animación de mi aplicación, y cada vez que un campo de texto se convirtió en el respondedor, asignaría asignarlo a una estática que obtendría barrido (resignado) basado en ciertos otros eventos ... es casi imposible para mí explicarlo en un párrafo.

Sé creativo, solo me tomó 10 minutos pensar en esto para mi aplicación después de encontrar esta pregunta.


Resuelto esto hace meses;) Terminé simplemente guardando el campo activo en foco y usándolo.
Seventoes

0

Un método un poco más robusto que necesitaba usar recientemente:

- (void) dismissKeyboard {
    NSArray *windows = [UIApplication sharedApplication].windows;

    for(UIWindow *window in windows) [window endEditing:true];

    //  Or if you're only working with one UIWindow:

    [[UIApplication sharedApplication].keyWindow endEditing:true];
}

Descubrí que algunos de los otros métodos "globales" no funcionaban (por ejemplo, UIWebViewy me WKWebViewnegué a renunciar).


0

Agregue A Tap Gesture Recognizer a su vista y defínalo como una acción

su archivo .m será como

    - (IBAction)hideKeyboardGesture:(id)sender {
    NSArray *windows = [UIApplication sharedApplication].windows;
    for(UIWindow *window in windows) [window endEditing:true];
    [[UIApplication sharedApplication].keyWindow endEditing:true];
}

Me ha funcionado


0

Sí, endEditing es la mejor opción. Y desde iOW 7.0, UIScrollViewtiene una característica genial para descartar el teclado al interactuar con la vista de desplazamiento. Para lograr esto, puede establecer la keyboardDismissModepropiedad de UIScrollView.

Establezca el modo de descarte del teclado como:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag

Tiene pocos otros tipos. Echa un vistazo a este documento de Apple .



0

la forma más fácil es llamar al método

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    if(![txtfld resignFirstResponder])
    {
        [txtfld resignFirstResponder];
    }
    else
    {

    }
    [super touchesBegan:touches withEvent:event];
}

No necesita el 'si' allí, resignFirstResponder lo hará de todos modos. Tal vez quisiste decir: (BOOL) canResignFirstResponder?
Seventoes

0

Tienes que usar uno de estos métodos,

[self.view endEditing:YES];

o

[self.textField resignFirstResponder];
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.