Descartar el teclado tocando el fondo de UITableView

105

Tengo una UITableViewcon UITextFields como celdas. Me gustaría descartar el teclado cuando UITableViewse toca el fondo del . Estoy tratando de hacer esto creando un UIButtontamaño del UITableViewy colocándolo detrás del UITableView. El único problema es UIButtoncaptar todos los toques incluso cuando el toque está en UITableView. ¿Qué estoy haciendo mal?

¡Gracias!

Hua-Ying
fuente
Preguntas y respuestas repetidas: Q1 , Q2 , Q3 .
Yantao Xie
Esta es la mejor respuesta stackoverflow.com/a/12851794/1418457
onmyway133

Respuestas:

203

Esto se hace fácilmente creando un objeto UITapGestureRecognizer (de forma predeterminada, esto detectará un "gesto" en un solo toque, por lo que no se requiere más personalización), especificando un objetivo / acción para cuando se dispara el gesto y luego adjuntando el objeto reconocedor de gestos a la vista de su mesa.

Por ejemplo, quizás en su viewDidLoadmétodo:

UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
[self.tableView addGestureRecognizer:gestureRecognizer];

Y el hideKeyboardmétodo podría verse así:

- (void) hideKeyboard {
    [textField1 resignFirstResponder];
    [textField2 resignFirstResponder];
    ...
    ...
}

Tenga en cuenta que el gesto no se dispara al tocar el interior de un UITextFieldobjeto. Se dispara en el UITableViewfondo, la vista de pie de página, la vista de encabezado y en UILabelsceldas internas, etc.

mixja
fuente
4
Cuando probé esto, descubrí que impedía que la tabla seleccionara celdas :(. Solución impresionante de lo contrario
Brian
109
Como una solución a continuación señala, puede hacer que esto funcione mucho mejor configurando:gestureRecognizer.cancelsTouchesInView = NO;
Zebs
3
Y no te olvides de liberar el gestoRecognizer una vez que esté adjunto a tableView.
Paul Lynch
39
Para el hideKeyboardmétodo, en lugar de comunicarse directamente con los campos de texto, puede hacerlo [self.view endEditing:NO];. De los documentos de Apple: " Este método examina la vista actual y su jerarquía de subvista para el campo de texto que es actualmente el primer respondedor. Si encuentra uno, le pide al campo de texto que renuncie como primer respondedor. Si el parámetro de fuerza está configurado en SÍ, el campo de texto ni siquiera se pregunta; se ve obligado a renunciar "
Gobot
1
de esta manera, mi método "didSelectRowAtIndexPath" no se llama. alguna solución para esto ??
uniruddh
127

La solución UITapGestureRecognizer funciona con la selección de celdas de la tabla si establece:

gestureRecognizer.cancelsTouchesInView = NO;
Azbuky
fuente
1
Esto permite tocar la celda, pero el gesto también se reconoce, tal vez deberíamos implementar estos métodos de delegadoshouldReceiveTouch
onmyway133
61

Esta es la mejor forma de hacerlo. Solo haz esto

[self.view endEditing:YES];

o

[[self.tableView superView] endEditing:YES];
Saad
fuente
¿Dónde debo poner este código? lo siento soy principiante. Y proporcione un código rápido.
John
54

También puedes hacerlo desde Storyboard: ingrese la descripción de la imagen aquí

Ben
fuente
1
Lo que elija: Descartar al arrastrar, Descartar interactivamente, cuando toco la celda de la tabla, se selecciona. Estoy usando Xcode 8, swift 3. por favor ayuda
John
22

Como UITableViewes una subclase de UIScrollView, implementar un método de delegado a continuación proporciona una solución rápida y extremadamente fácil. No hay necesidad de involucrarse, resignFirstResponderya que la jerarquía de vista hace introspecciones y encuentra al respondedor actual y le pide que renuncie a su estado de respondedor.

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}

Y recuerde agregar UIScrollViewDelegateal archivo de encabezado.

Rajive Jain
fuente
2
Esto se puede hacer a través de este delineador como lo señaló @Joe Masilotti si está apuntando a iOS7 y superior: self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
atulkhatri
¿Qué sucede si toca un campo de texto en la parte inferior de la pantalla que se supone que se desplaza hacia arriba para mostrar el teclado? - Tu teclado estará oculto.
Islam Q.14 de
Swift 4 - self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag
RobLabs
13

En primer lugar, escuche scrollViewWillBeginDraggingsu UIViewControlleragregando elUIScrollViewDelegate :

En archivo .h:

@interface MyViewController : UIViewController <UIScrollViewDelegate> 

En archivo .m:

- (void)scrollViewWillBeginDragging:(UIScrollView *)activeScrollView {

    [self dismissKeyboard];

}

Luego escuche otras interacciones:

- (void)setupKeyboardDismissTaps {

    UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeUpGestureRecognizer.cancelsTouchesInView = NO;
    swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
    [self.tableView addGestureRecognizer:swipeUpGestureRecognizer];

    UISwipeGestureRecognizer *swipeDownGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeDownGestureRecognizer.cancelsTouchesInView = NO;
    swipeDownGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
    [self.tableView addGestureRecognizer:swipeDownGestureRecognizer];

    UISwipeGestureRecognizer *swipeLeftGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeLeftGestureRecognizer.cancelsTouchesInView = NO;
    swipeLeftGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.tableView addGestureRecognizer:swipeLeftGestureRecognizer];

    UISwipeGestureRecognizer *swipeRightGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeRightGestureRecognizer.cancelsTouchesInView = NO;
    swipeRightGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
    [self.tableView addGestureRecognizer:swipeRightGestureRecognizer];


    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    tapGestureRecognizer.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tapGestureRecognizer];

}

Luego implemente dismissKeyboard:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    [yourTextFieldPointer resignFirstResponder];

}

Y si, como yo, quisiera descartar el teclado para un UITextField dentro de una celda de tabla personalizada:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    CustomCellClass *customCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
    [customCell.textFieldInCell resignFirstResponder]; 

}

¡Espero que ayude a cualquiera que busque!

bbeckford
fuente
12
tableView.keyboardDismissMode = .onDrag
Dom Bryan
fuente
estaba buscando eso: D
Tobias
8

Aquí está la versión rápida para su placer de codificación:

Agrega un reconocedor de gestos de toque y luego cierra el teclado. ¡No se requiere salida para TextField!

override func viewDidLoad() {
    super.viewDidLoad()
    view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleTap:"))
}

func handleTap(sender: UITapGestureRecognizer) {
    if sender.state == .Ended {
        view.endEditing(true)
    }
    sender.cancelsTouchesInView = false
}
Biodave
fuente
1
¡Esto funciona incluso con un tableViewCell personalizado! He pasado mucho tiempo tratando de resolver esto. Muchas gracias! Eres mi héroe. youtu.be/EqWRaAF6_WY
peacetype
8

Existe la versión Swift 3 sin bloquear los toques en las celdas.

En viewDidLoad()método:

let dismissKeyboardGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
dismissKeyboardGesture.cancelsTouchesInView = false
tableView.addGestureRecognizer(dismissKeyboardGesture)

Y se hideKeyboardve así:

func hideKeyboard() {
    view.endEditing(true)
}
Ivan Smetanin
fuente
7

Lo hice así:

Cree un método en su TableViewController para desactivar el primer respondedor (que sería su TextBox en ese momento)

- (BOOL)findAndResignFirstResonder:(UIView *)stView {
    if (stView.isFirstResponder) {
        [stView resignFirstResponder];
        return YES;     
    }

    for (UIView *subView in stView.subviews) {
        if ([self findAndResignFirstResonder:subView]) {
            return YES;
        }
    }
    return NO;
}

En tableView:didSelectRowAtIndexPath:llamar al método anterior:

- (void)tableView:(UITableView *)tableView
                             didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ...
    [self findAndResignFirstResonder: self.view];
    ...
}
sha
fuente
lo está haciendo mal de la manera que lo pide. no pone un botón en la vista le dice a la vista que elimine el teclado como dice esta respuesta
2
Esto funciona maravillosamente si toca dentro de una celda de vista de tabla (y fuera de cualquier UITextField dentro de esa celda de vista de tabla). Sin embargo, si toco el fondo de la vista de tabla (que a menudo es un objetivo más fácil de alcanzar, ¡sí, ley de Fitts!), No tengo tanta suerte. Es cierto, eso es lo esperado, ya que estamos realizando esta operación dentro de tableView: didSelectRowAtIndexPath :. Si esto se puede ajustar de alguna manera para que funcione tocando en cualquier otro lugar de la vista de tabla (que de otro modo no querría el enfoque del teclado), ¡creo que tenemos un ganador aquí!
Joe D'Andrea
Tengo el mismo problema que jdandrea. Eso didSelectRowAtIndexPathno se dispara si toca el TableView en sí.
zekel
Si didSelectRowAtIndexPath no es suficiente, ¡haga lo mismo en touchesBegan también!
Amogh Talpallikar
5

Tuve una UITableViewControllery la implementación touchesBegan:withEvent:no funcionó para mí.

Esto es lo que funcionó:

Rápido:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    view.endEditing(true)
}

C objetivo:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.view endEditing:YES];
}
MontiRabbit
fuente
Buena idea, me gusta.
HotFudgeSunday
4
@interface DismissableUITableView : UITableView {
}
@end

@implementation DismissableUITableView

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

@end

Luego asegúrese de que en su archivo Nib establezca el tipo de su UITableView en DismissableUITableView ..... tal vez podría haber pensado en un mejor nombre para esta clase, pero entiende el punto.

bandejapaisa
fuente
4

Si tiene como objetivo iOS7, puede usar uno de los siguientes:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

El primero animará el teclado fuera de la pantalla cuando se desplace la vista de tabla y el segundo ocultará el teclado como la aplicación de mensajes estándar.

Tenga en cuenta que estos son de UIScrollView, que UITableViewhereda de.

Joe Masilotti
fuente
bonito. Me las arreglé para romperlo deslizando el dedo hacia abajo desde lo alto de la pantalla hasta que el teclado comenzó a moverse hacia abajo, luego volví a deslizarlo hacia arriba hasta que el teclado se movió un poco hacia arriba y luego lo solté. la vista de desplazamiento no vuelve a la parte superior como debería.
Sam
3

Prueba esto:

viewDidLoad(){

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

    tableView.addGestureRecognizer(tap)

}
//Calls this function when the tap is recognized.
@objc func dismissKeyboard() {

    //Causes the view (or one of its embedded text fields) to resign the first responder status.
    view.endEditing(true)

}
Michael Colonna
fuente
2

UITableView es una subclase de UIScrollView.

La forma en que lo hice fue escuchar un evento de desplazamiento por parte del usuario y luego resignFirstResponder. Aquí está el método UIScrollViewDelegate para implementar en su código;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

Al abordar este tipo de problemas, he encontrado que la mejor manera es investigar los protocolos delegados para cada objeto y los de las clases principales (en este caso, UITableViewDelegate, UIScrollViewDelegate. El número de eventos que dispara los objetos NS es bastante grande y completo. también es más fácil implementar un protocolo que subclasificar cualquier cosa.

pschang
fuente
2

Tuve el mismo problema y aquí está mi solución, funciona perfectamente para mí:

En la vista o el controlador de vista que implementó <UITextFieldDelegate>

(En mi caso tengo una costumbre UITableViewCell llamado TextFieldCell),

Declare el UITapGestureRecognizercomo una propiedad:

@interface TextFieldCell : UITableViewCell <UITextFieldDelegate>
{
    UITextField *theTextField;
    UITapGestureRecognizer *gestureRecognizer;
}
@property (nonatomic,retain) UITextField *theTextField;
@property (nonatomic,retain) UITapGestureRecognizer *gestureRecognizer; 

E inicialícelo en su vista / controlador:

self.gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard:)];

En el - (void)textFieldDidBeginEditing:(UITextField *)textFieldmétodo, use superViewpara moverse hasta su tableView y llame addGestureRecognizer:

[self.superview.superview addGestureRecognizer:gestureRecognizer];

Y en el - (void)textFieldDidEndEditing:(UITextField *)textField, simplemente elimine el reconocedor de gestos:

[self.superview.superview removeGestureRecognizer:gestureRecognizer];

Espero eso ayude.

hac.jack
fuente
Esto lo hizo por mí. Gracias hac.jack
gilsaints88
2

Quería que mi celda abriera el teclado cuando se seleccionara cualquier parte de la celda y que la cerrara si hacía clic en cualquier parte fuera de la celda. Para abrir el teclado:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    if (selected)
    {
        [self.textField becomeFirstResponder];
    }
}

(NOTA: he subclasificado la celda, pero puede lograrlo fácilmente en el tableView:didSelectRowAtIndexPath:método delegado deUITableView )

Hacer esto significaba que con las soluciones principales, si hacía clic en la celda dos veces, el teclado temblaría, ya que, primero, el reconocedor de gestos intentó cerrar el teclado y, en segundo lugar, la celda se volvió a seleccionar e intentó abrir el teclado.

La solución es verificar si el clic ocurrió dentro de la celda seleccionada actualmente:

- (void)viewDidLoad
{
    [super viewDidLoad];
    //gesture recognizer to close the keyboard when user taps away
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(dismissKeyboard:)];
    tap.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tap];
}

-(void)dismissKeyboard:(UIGestureRecognizer*)tapGestureRecognizer
{
    if (!CGRectContainsPoint([self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]].frame, [tapGestureRecognizer locationInView:self.tableView]))
    {
        [self.view endEditing:YES];
    }
}
Sam
fuente
2

Encontré una solución que funciona muy bien.

Se necesita para usar UIGestureRecognizerDelegate y el método - gestoRecognizer: shouldReceiveTouch: .

Agregue el reconocedor de gestos a TableView de la siguiente manera:

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
tapGestureRecognizer.cancelsTouchesInView = NO;
tapGestureRecognizer.delegate = self;
[self.suggestedTableView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];

Luego, implemente el método delegado shouldReceiveTouch para rechazar los toques que se realizan en la clase UITableViewCell. El método hideKeyboard solo se llamará cuando el toque se haya realizado fuera de la clase UITableViewCell.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if([touch.view isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    // UITableViewCellContentView => UITableViewCell
    if([touch.view.superview isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    // UITableViewCellContentView => UITableViewCellScrollView => UITableViewCell
    if([touch.view.superview.superview isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    return YES; // handle the touch
}

- (void) hideKeyboard{
    [textField resignFirstResponder];
}
mlabraca
fuente
2

UITableViewtiene una backgroundViewpropiedad útil , con la que logré este comportamiento sin interferir con la selección de celda, como se muestra a continuación en Swift:

let tableBackTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
tableView.backgroundView = UIView()
tableView.backgroundView?.addGestureRecognizer(tableBackTapRecognizer)
Şafak Gezer
fuente
1

Simplemente usando un UITapGestureRecognizer y cancelsTouchesInView = NOsignifica que los toques en las celdas y UITextViews también activan la ocultación. Esto es malo si tiene múltiples UITextViews y toca el siguiente. El teclado comenzará a ocultarse y luego el siguiente textView se convierte en el primer Respondedor y el teclado se vuelve visible nuevamente. Para evitar esto, verifique la ubicación del grifo y solo oculte el teclado si el grifo no está en una celda:

// init
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapTableView:)];
tapRecognizer.cancelsTouchesInView = NO;
[self.tableView addGestureRecognizer:tapRecognizer];


// Hide on tap
- (void)didTapTableView:(UITapGestureRecognizer *)tap
{
    CGPoint point = [tap locationInView:tap.view];
    [self.view endEditing:!CGRectContainsPoint([self.tableView rectForRowAtIndexPath:[self.tableView indexPathForRowAtPoint:point]], point)];
}

Para scrollViewWillBeginDragging:que se active, la scrollEnabledpropiedad tableView debe serYES

// Hide on scroll
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}
Shawn Throop
fuente
Perfecto para mi. Se agregó un cuadro de texto a la celda de vista de tabla; si toco fuera del teclado descartar
Nicola
0

¿Por qué quieres crear una tabla llena de campos de texto? Debería utilizar una vista detallada para cada fila que contiene los campos de texto. Cuando presione su vista detallada, asegúrese de llamar a "[myTextField BecomeFirstResponder]" para que el usuario pueda comenzar a editar con solo un clic de distancia de la lista de la tabla.

Mugunth
fuente
La aplicación Contactos de Apple hace precisamente esto. No diría que está lleno de campos de texto per se, pero los usa con buenos resultados.
Joe D'Andrea
2
Editar texto en línea en una vista de tabla es mucho más rápido e intuitivo que presionar vistas de detalles para cada campo de texto que el usuario desea editar ... solo pregunte a su formulario HTML más cercano, o los campos de texto en los paneles de Preferencias de iPhone, o la aplicación Contactos, o etc etc etc ... es una verdadera lástima que Apple no haya hecho de este un tipo de celda estándar, pero hay mucha información en la web sobre cómo lograrlo.
Glenc
0

Si está dispuesto a subclasificar (¡uf!) La vista de su tabla, algo como esto podría funcionar:

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

   BOOL backgroundTouched = YES;

   for (UITouch *touch in touches) {
      CGPoint location = [touch locationInView:self];
      for (UITableViewCell *cell in self.visibleCells) {
         if (CGRectContainsPoint(cell.frame, location)) {
            backgroundTouched = NO;
            break;
         }
      }
   }

   if (backgroundTouched) {
      for (UITableViewCell *cell in self.visibleCells) {
         // This presumes the first subview is the text field you want to resign.
         [[cell.contentView.subviews objectAtIndex:0] resignFirstResponder];
      }
   }

   [super touchesBegan:touches withEvent:event];
}
Joe D'Andrea
fuente
0

Si desea cerrar el teclado mientras se presiona la tecla de retorno, simplemente puede agregar el siguiente código en el método de retorno de textField, es decir:

- (BOOL)textFieldShouldReturn:(UITextField *)atextField
{
   [textField resignFirstresponder];
}

Algunos campos de texto pueden tener una vista de selector o alguna otra como subvista, por lo que en ese caso el método anterior no funciona, por lo que en ese caso debemos hacer uso de la clase UITapGestureRecognizer, es decir, agregar el siguiente fragmento de código al método viewDidLoad, es decir:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(dismissKeyboard)];

    [self.view addGestureRecognizer:tap];

Ahora simplemente agregue el respondedor de renuncia al método selector, es decir:

-(void)dismissKeyboard 
{
    [textField resignFirstResponder];
}

Espero que ayude, gracias :)

Eshwar Chaitanya
fuente
0

Muchas respuestas interesantes. Me gustaría compilar diferentes enfoques en la solución que pensé que se ajusta mejor a un escenario de UITableView (es el que suelo usar): lo que normalmente queremos es básicamente ocultar el teclado en dos escenarios: al tocar fuera de los elementos de la interfaz de usuario de texto, o al desplazarse hacia abajo o hacia arriba en UITableView. El primer escenario lo podemos agregar fácilmente a través de TapGestureRecognizer, y el segundo a través del método UIScrollViewDelegate scrollViewWillBeginDragging :. Primera orden del día, el método para ocultar el teclado:

   /**
     *  Shortcut for resigning all responders and pull-back the keyboard
     */
    -(void)hideKeyboard
    {
        //this convenience method on UITableView sends a nested message to all subviews, and they resign responders if they have hold of the keyboard
        [self.tableView endEditing:YES];

    }

Este método renuncia a cualquier interfaz de usuario de textField de las subvistas dentro de la jerarquía de vista UITableView, por lo que es más práctico que renunciar a cada elemento de forma independiente.

A continuación, nos encargamos de descartar mediante un gesto Tap externo, con:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setupKeyboardDismissGestures];

}

- (void)setupKeyboardDismissGestures
{

//    Example for a swipe gesture recognizer. it was not set-up since we use scrollViewDelegate for dissmin-on-swiping, but it could be useful to keep in mind for views that do not inherit from UIScrollView
//    UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
//    swipeUpGestureRecognizer.cancelsTouchesInView = NO;
//    swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
//    [self.tableView addGestureRecognizer:swipeUpGestureRecognizer];

    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
    //this prevents the gestureRecognizer to override other Taps, such as Cell Selection
    tapGestureRecognizer.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tapGestureRecognizer];

}

Establecer tapGestureRecognizer.cancelsTouchesInView en NO es para evitar que el gestoRecognizer anule el funcionamiento interno normal de UITableView (por ejemplo, para no interferir con la selección de celda).

Finalmente, para manejar ocultar el teclado al desplazarse hacia arriba / abajo en UITableView, debemos implementar el método scrollViewWillBeginDragging: del protocolo UIScrollViewDelegate, como:

archivo .h

@interface MyViewController : UIViewController <UIScrollViewDelegate>

archivo .m

#pragma mark - UIScrollViewDelegate

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self hideKeyboard];
}

¡Espero que ayude! =)

Robertibiris
fuente
0

Así es como finalmente hice las obras. Combiné sugerencias y códigos de diferentes respuestas. Funciones: descartar el teclado, mover los campos de texto sobre el teclado mientras se edita y se configura el tipo de retorno del teclado "Siguiente" y "Listo". REEMPLAZAR "..." con más campos

static const CGFloat ANIMATION_DURATION = 0.4;
static const CGFloat LITTLE_SPACE = 5;
CGFloat animatedDistance;
CGSize keyboardSize;

@interface ViewController () <UITextFieldDelegate>
 @property (weak, nonatomic) IBOutlet UITextField *firstNameTXT;
  .....// some other text fields
 @property (weak, nonatomic) IBOutlet UITextField *emailTXT;
@end

@implementation ViewController
- (void)viewDidLoad{
.....
// add tap gesture to help in dismissing keyboard
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]
                                       initWithTarget:self
                                       action:@selector(tapScreen:)];// outside textfields

[self.view addGestureRecognizer:tapGesture];

// set text fields return key type to Next, last text field to Done
[self.firstNameTXT setReturnKeyType:UIReturnKeyNext];
.....
[self.emailTXT setReturnKeyType:UIReturnKeyDone];

// set text fields tags
[self.firstNameTXT setTag:0];
....// more text fields
[self.emailTXT setTag:5];

// add keyboard notification
[[NSNotificationCenter defaultCenter] addObserver:self     selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}
[[NSNotificationCenter defaultCenter] addObserver:self      selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
}

// dismiss keyboard when tap outside text fields
- (IBAction)tapScreen:(UITapGestureRecognizer *)sender {
  if([self.firstNameTXT isFirstResponder])[self.firstNameTXT resignFirstResponder];
  ...
  if([self.emailTXT isFirstResponder])[self.emailTXT  resignFirstResponder];

  }
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
   if(textField.returnKeyType==UIReturnKeyNext) {
     // find the text field with next tag
     UIView *next = [[textField superview] viewWithTag:textField.tag+1];
     [next becomeFirstResponder];
   } else if (textField.returnKeyType==UIReturnKeyDone || textField.returnKeyType==UIReturnKeyDefault) {
    [textField resignFirstResponder];
 }
return YES;
}

// Moving current text field above keyboard
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField{
   CGRect viewFrame = self.view.frame;
   CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
   CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
   CGFloat textFieldBottomLine = textFieldRect.origin.y + textFieldRect.size.height + LITTLE_SPACE;//

   CGFloat keyboardHeight = keyboardSize.height;

   BOOL isTextFieldHidden = textFieldBottomLine > (viewRect.size.height - keyboardHeight)? TRUE :FALSE;
  if (isTextFieldHidden) {
    animatedDistance = textFieldBottomLine - (viewRect.size.height - keyboardHeight) ;
    viewFrame.origin.y -= animatedDistance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
  return YES;
}

-(void) restoreViewFrameOrigionYToZero{
  CGRect viewFrame = self.view.frame;
  if (viewFrame.origin.y != 0) {
    viewFrame.origin.y = 0;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
}

-(void)keyboardDidShow:(NSNotification*)aNotification{
   NSDictionary* info = [aNotification userInfo];
   keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
 }

-(void)keyboardDidHide:(NSNotification*)aNotification{
   [self restoreViewFrameOrigionYToZero];// keyboard is dismissed, restore frame view to its  zero origin
}
@end
Kamel
fuente
0

La respuesta de @ mixca es muy útil, pero ¿y si tengo algo diferente de UITextField? Creo que la mejor manera de manejarlo es buscar todas las subvistas de la vista principal con función recursiva, ver el ejemplo a continuación

- (BOOL)findAndResignFirstResponder {
if (self.isFirstResponder) {
    [self resignFirstResponder];
    return YES;
}

    for (UIView *subView in self.subviews) {
        if ([subView findAndResignFirstResponder]) {
            return YES;
        }
    }
    return NO;
}

y también puede poner este método en su clase de utilidad y puede usarlo desde el gesto de toque como la respuesta de @ mixca.

mert
fuente
0

Rápido 4 / 4.2 / 5

También puede cerrar el teclado cuando se toca una celda, antes de hacer cualquier otra cosa.

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    view.endEditing(true)
    // Do something here
    }
N. Der
fuente
0

tableView.keyboardDismissMode = .onDrag // .interactive

K. Mitra
fuente