¿Cómo se descarta el teclado al editar un UITextField?


181

Sé que necesito decirle a mi UITextField que renuncie al primer respondedor cuando quiero cerrar el teclado, pero no estoy seguro de cómo saber cuándo el usuario ha presionado la tecla "Listo" en el teclado. ¿Hay alguna notificación que pueda ver?


2
[self.view endEditing: YES]; en contacto comenzó delegado es la mejor solución
Zar E Ahmer

Respuestas:


351

Puse el delegado de la UITextFielda mi ViewControllerclase.

En esa clase implementé este método de la siguiente manera:

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

Vea el ejemplo anterior ... conecte ese uso de IntefaceBuilder a la acción en lo que sea que esté usando como controlador ... cada vez que el usuario cierre el sistema de entrada de texto (presiona hecho), esto se invocará ...
Jason Coco

2
Cualquiera de estos funcionará: el campo de texto envía su acción cuando el usuario presiona la tecla Retorno ("Listo", lo que sea) y también envía su delegado -textFieldShouldReturn :.
Noah Witherspoon, el

Por cierto, esto también funciona para un UISearchBar. Por ejemplo, mi código tenía un miembro IBOutlet searchBarTusb; Cuando se hizo clic en mi 'tecla de retorno' (UIReturnKeySearch), - (nulo) searchBarSearchButtonClicked :, puse la declaración [searchBarTusb resignFirstResponder]; También tenga en cuenta que la 'clave de retorno' se configuró en la NIB utilizando Interface Builder.
mobibob

¿Por qué volver en NOlugar de YES?
Iulian Onofrei

@IulianOnofrei El comportamiento predeterminado del botón de retorno es agregar un retorno de línea y mantener el teclado en pantalla. Al regresar NO, evita agregar un retorno de línea al texto.
kubi

47

Si conecta el evento DidEndOnExit del campo de texto a una acción (IBAction) en InterfaceBuilder, se le enviará un mensaje cuando el usuario cierre el teclado (con la tecla de retorno) y el remitente será una referencia al UITextField que activó el evento.

Por ejemplo:

-(IBAction)userDoneEnteringText:(id)sender
{
    UITextField theField = (UITextField*)sender;
    // do whatever you want with this text field
}

Luego, en InterfaceBuilder, vincule el evento DidEndOnExit del campo de texto a esta acción en su controlador (o lo que sea que esté utilizando para vincular eventos desde la IU). Siempre que el usuario ingrese texto y descarte el campo de texto, el controlador recibirá este mensaje.


El único evento que parece que podría funcionar es textFieldDidEndEditing, que establece que solo se envía después de que UITextField renuncia al estado del primer respondedor. ¿Cómo sé cuándo necesito renunciar al estado de primer respondedor?
kubi

Lo siento por la terminología ... no es una notificación (evento) real ... Voy a editar mi respuesta con un ejemplo rápido y una explicación, así que mira eso :)
Jason Coco

1
Para aclarar esta respuesta, textField envía el evento "Did End On Exit" cuando presiona la tecla de retorno, por lo que es el que necesita vincular a su controlador. Creo que este método es más fácil que el que describí anteriormente.
kubi

2
¿podría editar esta respuesta para que mencione QUÉ evento conectar, por favor? Obviamente, esto es mejor que configurar el delegado.
Dan Rosenstark

1
Desea votar a favor esta respuesta, pero no puede hasta que mencione el evento DidEndOnExit. Alguien con privilegios de edición, haga el cambio si el OP no lo hará.
James Hart

32

También puede crear un método en su controlador

 -(IBAction)editingEnded:(id)sender{
    [sender resignFirstResponder]; 
}

y luego en Connection Inspector en IB, conecte el Evento "Terminó al salir".


1
Esto es casi incorrecto, o al menos se pierde el punto. Al suscribirse al DidEndOnExitevento, no necesita llamar resignFirstResponder. Puede probar esto poniendo un punto de interrupción simbólico [UIResponder resignFirstResponder]. Tenga en cuenta que incluso si no llama a resignFirstResponder, el sistema aún lo llama. Esto se explica en los excelentes libros de Matt Neuburg: apeth.com/iOSBook/…
Chris Conover

19

Kubi, gracias. Tu código funcionó. Solo para ser explícito (para los novatos como), ya que dice que debe establecer los UITextField's delegatepara que sean iguales al ViewController en el que reside el campo de texto. Puedes hacer esto donde quieras. Elegí el viewDidLoadmétodo.

- (void)viewDidLoad 
{
    // sets the textField delegates to equal this viewController ... this allows for the keyboard to disappear after pressing done
    daTextField.delegate = self;
}

Si agregó un campo de texto a su guión gráfico o NIB, también puede establecer los campos de texto delegateallí. No tiene que hacer esto mediante programación, como se demostró anteriormente. Cualquiera de los dos enfoques funciona bien.
Rob

18

Aquí hay un truco para obtener un comportamiento de descarte automático del teclado sin ningún código. En el plumín, edite el objeto proxy Primer respondedor en el inspector de identidad, agregando una nueva acción de primer respondedor; Digamos que es dummy:. Ahora conecte el evento Did End on Exit del campo de texto a la dummy:acción del objeto proxy First Responder. ¡Eso es! Dado que el evento Did End on Exit del campo de texto ahora tiene un par acción-objetivo, el campo de texto descarta automáticamente su teclado cuando el usuario toca Retorno; y dado que no hay penalización por no encontrar un controlador para un mensaje enviado por la cadena de respuesta, la aplicación no se bloquea a pesar de que no hay implementación de dummy:ninguna parte.


@matt Descubrí que SI agrego un segmento de desenrollado Y conecto el evento didEndOnExit ENTONCES el desenlace de desenrollado se activará al presionar Retorno. Sin la conexión del evento, el segue no se activa. Genial pero ¿eh? ¿Alguna observación? Por cierto: tengo sus libros Swift (terminado) y iOS10 (en el capítulo 6). ¡Me han ayudado muchísimo!
Verticon

@Verticon, la pregunta y la respuesta no tienen nada que ver con segues, por lo que no entiendo el problema ... :( esto es puramente sobre el descarte del teclado
mate

@matt Lo siento, hombre. Estaba a cuestas porque 1) Me encontré con este hilo mientras trataba de cómo manejar la clave de retorno de UITextField; y 2) fue una oportunidad de interactuar contigo (gracias por los libros). No hay "problema". Solo una falta de comprensión de mi parte sobre por qué / cómo funciona de la manera en que lo hace.
Verticon

@Verticon Me disculpo por no poder ayudar. Siéntase libre de formular una nueva pregunta con más información (¿proyecto de demostración?) Y eliminarme, si puedo ser útil.
mate


11

Solo agrega

[textField endEditing:YES];

donde desea desactivar el teclado y mostrar la vista del selector.


10

En Swift, puede escribir una IBAction en el controlador y establecer el evento Did End On Exit del campo de texto para esa acción

@IBAction func returnPressed(sender: UITextField) {
    self.view.endEditing(true)
}

5

Swift 4.2 y funcionará al 100%

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        self.textField.delegate = self

    }

    // hide key board when the user touches outside keyboard

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

    // user presses return key

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }

}

4

También puedes usar

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
  {

   [self.yourTextField resignFirstResponder];

  }

El mejor si tienes muchos Uitextfields:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 {    
     [self.view endEditing:YES];
 }

2

Esto es lo que tuve que hacer para que funcione, y creo que es necesario para cualquier persona con un teclado numérico para un teclado (o cualquier otro sin un botón listo:

  1. Cambié la UIView en ViewController a UIControl.
  2. Creé una función llamada

    -(IBAction)backgroundIsTapped:(id)sender

Esto también se definió en el archivo .h.

Después de esto, me vinculé al bit 'touchdown' para ViewController en Interface Builder.

En la función 'se toca el fondo', pongo esto:

    [answerField resignFirstResponder];

Solo recuerde cambiar 'answerField' por el nombre del UITextField del que desea quitar el teclado (obviamente, asegúrese de que su UITextField esté definido como se muestra a continuación :)

    IBOutlet UITextField * <nameoftextfieldhere>;

Sé que este tema probablemente murió hace mucho tiempo ... ¡pero espero que esto ayude a alguien, en algún lugar!


... pero no funciona tan bien si el usuario toca otro control.
ragnarius

2

Notará que el método "textFieldShouldReturn" proporciona el objeto de campo de texto que ha pulsado la tecla HECHO. Si configura el TAG, puede activar ese campo de texto. O puede rastrear y comparar el puntero del objeto con algún valor de miembro almacenado por su creador.

Mi enfoque es así para un autoestudio:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    NSLog(@"%s", __FUNCTION__);

    bool fDidResign = [textField resignFirstResponder];

    NSLog(@"%s: did %resign the keyboard", __FUNCTION__, fDidResign ? @"" : @"not ");

    return fDidResign;
}

Mientras tanto, pongo la prueba de "validación" que niega la renuncia que sigue. Es solo para ilustración, por lo que si el usuario escribe NO! en el campo, no se despedirá. El comportamiento fue el que quería, pero la secuencia de salida no fue la que esperaba.

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    NSLog(@"%s", __FUNCTION__);

    if( [[textField text] isEqualToString:@"NO!"] ) {
        NSLog(@"%@", textField.text);
        return NO;
    } else {
        return YES;
    }
}

A continuación se muestra mi salida NSLog para esta denegación seguida de la aceptación. ¿Te darás cuenta de que estoy devolviendo el resultado de la renuncia, pero esperaba que me devolviera FALSO para informar a la persona que llama? Aparte de eso, tiene el comportamiento necesario.

13.313 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]
13.320 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldEndEditing:]
13.327 StudyKbd [109: 207] ¡NO!
13.333 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]: renunció al teclado
59.891 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]
59.897 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldEndEditing:]
59.917 StudyKbd [109: 207] - [StudyKbdViewController doneEditText]: NO
59.928 StudyKbd [109: 207] - [StudyKbdViewController textFieldShouldReturn:]: renunció al teclado

1
¿Puede explicar ... si devuelvo NO o SÍ en ambos casos suceden las mismas cosas, entonces cuál es la necesidad de devolver sí en el método de delegado textFieldShouldReturn
K. Jaiswal

1

Aquí hay una manera bastante limpia de finalizar la edición con la tecla de retorno o un toque en segundo plano.

En el generador de interfaces, incruste sus campos en una vista de la clase UIFormView

Qué hace esta clase:

  • Se adjunta automáticamente como delegado de campos (ya sea despertado de la punta o agregado manualmente)
  • Mantener una referencia en el campo editado actual
  • Descarte el teclado al regresar o toque en segundo plano

Aquí está el código:

Interfaz

#import <UIKit/UIKit.h>

@interface UIFormView : UIView<UITextFieldDelegate>

-(BOOL)textFieldValueIsValid:(UITextField*)textField;
-(void)endEdit;

@end

Implementación

#import "UIFormView.h"

@implementation UIFormView
{
    UITextField* currentEditingTextField;
}

// Automatically register fields

-(void)addSubview:(UIView *)view
{
    [super addSubview:view];
    if ([view isKindOfClass:[UITextField class]]) {
        if ( ![(UITextField*)view delegate] ) [(UITextField*)view setDelegate:self];
    }
}

// UITextField Protocol

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    currentEditingTextField = textField;
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
    currentEditingTextField = NULL;
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self endEdit];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if ([self textFieldValueIsValid:textField]) {
        [self endEdit];
        return YES;
    } else {
        return NO;
    }
}

// Own functions

-(void)endEdit
{
    if (currentEditingTextField) {
        [currentEditingTextField endEditing:YES];
        currentEditingTextField = NULL;
    }
}


// Override this in your subclass to handle eventual values that may prevent validation.

-(BOOL)textFieldValueIsValid:(UITextField*)textField
{
    return YES;
}

@end
  • Al subclasificar el formulario y anular el textFieldValueIsValid:método, puede evitar el final de la edición si el valor no es correcto para el campo dado.

  • Si un campo tiene un delegado establecido en Interface Builder, el formulario no lo cambia. No veo muchas razones para establecer un delegado diferente para un campo en particular, pero por qué no ...

Hay muchas maneras de mejorar esta clase de vista de formulario: Adjunte un delegado, haga un diseño, maneje cuando el teclado cubra un campo (usando el marco currentEditingTextField), inicie automáticamente la edición para el siguiente campo, ...

Personalmente lo mantengo en mi marco, y siempre lo subclasifico para agregar características, a menudo es útil "tal cual".

Espero que te sirva de ayuda. Saludos a todos


1
Clase útil. Un pequeño punto, no debe anteponer sus propias clases con "UI". En el objetivo-c debe usar su propio prefijo ("TL"?), En Swift, no use nada.
kubi

Gracias @kubi. Así es. Es MF en mi marco, como MooseFactory;)
Moose

1

si desea toda la edición en un UIViewController puede usar.

[[self view]endEditing:YES];

y si desea descartar una ocultación de teclado UITextField perticular, use.

1.agregue delegado en su viewcontroller.h

<UITextFieldDelegate>
  1. hacer que la delegación no pueda en su campo de texto.

    self.yourTextField.delegate = self;

  2. agregue este método a su viewcontroller.

    - (BOOL) textFieldShouldEndEditing: (UITextField *) textField {[textField resignFirstResponder]; devuelve SÍ;}


1

Configure programáticamente el delegado de UITextField en swift 3

Implemente UITextFieldDelegate en su archivo ViewController.Swift (por ejemplo, clase ViewController: UIViewController, UITextFieldDelegate {)

 lazy var firstNameTF: UITextField = {

    let firstname = UITextField()
    firstname.placeholder = "FirstName"
    firstname.frame = CGRect(x:38, y: 100, width: 244, height: 30)
    firstname.textAlignment = .center
    firstname.borderStyle = UITextBorderStyle.roundedRect
    firstname.keyboardType = UIKeyboardType.default
    firstname.delegate = self
    return firstname
}()

lazy var lastNameTF: UITextField = {

    let lastname = UITextField()
    lastname.placeholder = "LastName"
    lastname.frame = CGRect(x:38, y: 150, width: 244, height: 30)
    lastname.textAlignment = .center
    lastname.borderStyle = UITextBorderStyle.roundedRect
    lastname.keyboardType = UIKeyboardType.default
    lastname.delegate = self
    return lastname
}()

lazy var emailIdTF: UITextField = {

    let emailid = UITextField()
    emailid.placeholder = "EmailId"
    emailid.frame = CGRect(x:38, y: 200, width: 244, height: 30)
    emailid.textAlignment = .center
    emailid.borderStyle = UITextBorderStyle.roundedRect
    emailid.keyboardType = UIKeyboardType.default
    emailid.delegate = self
    return emailid
}()

// Marca: - manejo de delegado textField ..

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

    if textField == firstNameTF {

        lastNameTF.becomeFirstResponder()
    }

    else if textField == lastNameTF {

        emailIdTF.becomeFirstResponder()
    }
    else {
        view.emailIdTF(true)
    }
    return true
}

0

Cree una función hidekeyboard y vincúlela al campo de texto en el archivo .xib y seleccione DidEndOnExit

-(IBAction)Hidekeyboard    
{    
      textfield_name.resignFirstResponder;    
}  

0

Si ha creado la vista usando Interface Builder, use lo siguiente Simplemente cree un método,

-(IBAction)dismissKeyboard:(id)sender
{
[sender resignFirstResponder];
}

Simplemente haga clic con el botón derecho en el campo de texto en la vista, configure el evento como Finalizado al salir y conéctelo al método "despedir Teclado".

La mejor guía para principiantes es "Head First iPhone and iPad Development, 2nd Edition"


0

prueba esto

- (BOOL) textView: (UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text
{
    if ([text isEqualToString:@"\n"]) {
        [textView resignFirstResponder];
        return NO;
    }
    return YES;
}

0
//====================================================
//                  textFieldShouldReturn:
//====================================================
-(BOOL) textFieldShouldReturn:(UITextField*) textField { 
    [textField resignFirstResponder];
    if(textField.returnKeyType != UIReturnKeyDone){
        [[textField.superview viewWithTag: self.nextTextField] becomeFirstResponder];
    }
    return YES;
}

0

Cualquiera que busque Swift 3

1) Asegúrese de que su Delegado de UITextField esté conectado a su ViewController en el Guión gráfico

2) Implemente UITextFieldDelegate en su archivo ViewController.Swift (por ejemplo, clase ViewController: UIViewController, UITextFieldDelegate {)

3) Use el método de delegado a continuación

func textFieldShouldReturn(textField: UITextField) -> Bool { 
   textField.resignFirstResponder()  
return false }

0

Así es como descarto el teclado en Swift 4.2 y funciona para mí:

    override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: 
    #selector(dismissKeyboard))

    view.addGestureRecognizer(tap)
    }

    @objc func dismissKeyboard (_ sender: UITapGestureRecognizer) {
    numberField.resignFirstResponder()
    }

-2

Swift 3, iOS 9+

@IBAction private func noteFieldDidEndOnExit(_ sender: UITextField) {}

UPD: Todavía funciona bien para mí. Creo que el tipo que dedicó esta respuesta simplemente no entendió que necesita vincular esta acción al UITextField en el guión gráfico.


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.