Dispensar teclado tocando no fundo de UITableView

105

Eu tenho um UITableViewcom UITextFields como células. Eu gostaria de descartar o teclado quando o fundo do UITableViewfor tocado. Estou tentando fazer isso criando um UIButtontamanho de UITableViewe colocando-o atrás de UITableView. O único problema é UIButtoncapturar todos os toques, mesmo quando o toque está no UITableView. O que estou fazendo de errado?

Obrigado!

Hua-Ying
fonte
Perguntas e respostas repetidas: Q1 , Q2 , Q3 .
Yantao Xie
Esta é a melhor resposta stackoverflow.com/a/12851794/1418457
onmyway133

Respostas:

203

Isso é feito facilmente criando um UITapGestureRecognizer objeto (por padrão, isso detectará um "gesto" em um único toque, então nenhuma personalização adicional é necessária), especificando um alvo / ação para quando o gesto é disparado e, em seguida, anexando o objeto reconhecedor de gesto para a visualização da sua mesa.

Por exemplo, talvez em seu viewDidLoadmétodo:

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

E o hideKeyboardmétodo pode ser assim:

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

Observe que o gesto não é disparado ao tocar dentro de um UITextFieldobjeto. Ele é disparado no plano de UITableViewfundo, visualização de rodapé, visualização de cabeçalho e em UILabelscélulas internas, etc.

mixja
fonte
4
Quando tentei fazer isso, descobri que impedia a tabela de selecionar células :(. Caso contrário, uma solução incrível
Brian
109
Como uma solução abaixo indica, você pode tornar este trabalho muito melhor definindo:gestureRecognizer.cancelsTouchesInView = NO;
Zebs
3
E não se esqueça de liberar o gestoRecognizer depois de anexado ao tableView.
Paul Lynch
39
Para o hideKeyboardmétodo, em vez de se comunicar diretamente com os campos de texto, você pode fazer [self.view endEditing:NO];. Dos documentos da Apple: " Este método analisa a visão atual e sua hierarquia de subvisualização para o campo de texto que é atualmente o primeiro respondente. Se encontrar um, ele pede que esse campo de texto renuncie como primeiro respondente. Se o parâmetro force for definido como SIM, o campo de texto nunca é perguntado; ele é forçado a renunciar. "
Gobot
1
usando desta forma, meu método "didSelectRowAtIndexPath" não está sendo chamado. alguma solução para isso ??
uniruddh
127

A solução UITapGestureRecognizer funciona com a seleção de células da tabela se você definir:

gestureRecognizer.cancelsTouchesInView = NO;
Azbuky
fonte
1
Isso permite tocar na célula, mas o gesto também é reconhecido, talvez devêssemos implementar esses métodos de delegaçãoshouldReceiveTouch
onmyway133
61

Esta é a melhor maneira de fazer isso. Apenas faça isso

[self.view endEditing:YES];

ou

[[self.tableView superView] endEditing:YES];
Saad
fonte
onde devo colocar este código? desculpe, eu sou iniciante. E forneça um código rápido.
João
54

Você também pode fazer isso no Storyboard: insira a descrição da imagem aqui

Ben
fonte
1
O que eu escolher: Dispensar ao arrastar, Dispensar interativamente, quando eu toco a célula da tabela, ela é selecionada. Estou usando o Xcode 8, swift 3. por favor me ajude
John
22

Como UITableViewé uma subclasse de UIScrollView, implementar um método delegado abaixo fornece uma solução extremamente fácil e rápida. Não há necessidade de se envolver, resignFirstResponderjá que a hierarquia de visualização examina e encontra o respondente atual e pede que ele renuncie ao status de respondente.

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

E lembre-se de adicionar UIScrollViewDelegateao arquivo de cabeçalho.

Rajive Jain
fonte
2
Isso pode ser feito por meio deste único liner, conforme apontado por @Joe Masilotti se você tiver como alvo o iOS7 e superior: self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
atulkhatri
O que acontece se você tocar em um campo de texto na parte inferior da tela que deve rolar para cima para mostrar o teclado? - Seu teclado ficará oculto.
Islam Q.
Swift 4 - self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag
RobLabs
13

Em primeiro lugar, escute scrollViewWillBeginDraggingem seu UIViewControlleradicionando UIScrollViewDelegate:

No arquivo .h:

@interface MyViewController : UIViewController <UIScrollViewDelegate> 

No arquivo .m:

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

    [self dismissKeyboard];

}

Em seguida, ouça outras interações:

- (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];

}

Em seguida, implemente dismissKeyboard:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    [yourTextFieldPointer resignFirstResponder];

}

E se, como eu, você quiser dispensar o teclado para um UITextField dentro de uma célula de tabela personalizada:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

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

}

Espero que ajude quem está procurando !!

bbeckford
fonte
12
tableView.keyboardDismissMode = .onDrag
Dom Bryan
fonte
estava procurando por isso: D
Tobias
8

Esta é a versão rápida para seu prazer de codificação:

Ele adiciona um reconhecedor de gestos de toque e, em seguida, descarta o teclado. Nenhuma saída para o TextField é necessária!

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
fonte
1
Isso funciona mesmo com um tableViewCell personalizado! Passei muito tempo tentando descobrir isso. Muito obrigado! Você é meu herói. youtu.be/EqWRaAF6_WY
peacetype
8

Existe a versão Swift 3 sem bloqueio de torneiras nas células.

No viewDidLoad()método:

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

E hideKeyboardfica assim:

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

Eu fiz assim:

Crie um método em seu TableViewController para desativar o primeiro respondente (que seria seu TextBox nesse ponto)

- (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;
}

Na tableView:didSelectRowAtIndexPath:chamada do método anterior:

- (void)tableView:(UITableView *)tableView
                             didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ...
    [self findAndResignFirstResonder: self.view];
    ...
}
sha
fonte
você está fazendo errado da maneira que está pedindo. você não coloca um botão na visualização, diz à visualização para remover o teclado, como esta resposta diz
2
Isso funciona perfeitamente se você tocar em uma célula de exibição de tabela (e fora de qualquer UITextField dentro dessa célula de exibição de tabela). No entanto, se eu tocar no plano de fundo da visualização da mesa (que geralmente é um alvo mais fácil de alcançar - a lei de Fitts!), Não terá essa sorte. Verdade, isso é esperado, já que estamos realizando esta operação em tableView: didSelectRowAtIndexPath :. Se isso puder ser ajustado de alguma forma para funcionar tocando em qualquer outro lugar na visualização da mesa (que de outra forma não exigiria o foco do teclado), acho que temos um vencedor aqui!
Joe D'Andrea
Eu tenho o mesmo problema que jdandrea. Isso didSelectRowAtIndexPathnão dispara se você tocar no próprio TableView.
zekel
se didSelectRowAtIndexPath não for suficiente, faça o mesmo em touchesBegan também!
Amogh Talpallikar
5

Eu tive um UITableViewControllere implementar touchesBegan:withEvent:não funcionou para mim.

Aqui está o que funcionou:

Rápido:

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

Objective-C:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.view endEditing:YES];
}
MontiRabbit
fonte
Boa ideia, gostei.
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

Em seguida, certifique-se de que em seu arquivo Nib você definiu o tipo de seu UITableView como DismissableUITableView ... talvez eu pudesse ter pensado em um nome melhor para esta classe, mas você entendeu.

bandejapaisa
fonte
4

Se você tem como alvo o iOS7, pode usar um dos seguintes:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

O primeiro animará o teclado fora da tela quando a visualização da mesa for rolada e o último ocultará o teclado como o aplicativo de mensagens de estoque.

Observe que estes são de UIScrollView, que UITableViewherda de.

Joe Masilotti
fonte
legais. Consigo quebrá-lo deslizando para baixo do alto da tela até que o teclado comece a se mover para baixo e, em seguida, deslizando de volta para cima até que o teclado suba um pouco e solto. o scrollview não volta ao topo como deveria.
Sam
3

Experimente isto:

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
fonte
2

UITableView é uma subclasse de UIScrollView.

A maneira como fiz isso foi ouvir um evento de rolagem do usuário e, em seguida, resignFirstResponder. Aqui está o método UIScrollViewDelegate para implementar em seu código;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

Ao abordar esses tipos de problemas, descobri que a melhor maneira é pesquisar os protocolos delegados para cada objeto e aqueles das classes pai (neste caso UITableViewDelegate, UIScrollViewDelegate. O número de eventos que os objetos NS disparam é muito grande e abrangente. também é mais fácil implementar um protocolo do que criar qualquer subclasse.

pschang
fonte
2

Tive o mesmo problema e aqui está a minha solução, funciona perfeitamente para mim:

Na visualização ou controlador de visualização que você implementou <UITextFieldDelegate>

(No meu caso, tenho um personalizado UITableViewCellchamado TextFieldCell),

Declare o UITapGestureRecognizercomo uma propriedade:

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

E inicialize-o em sua visualização / controlador:

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

No - (void)textFieldDidBeginEditing:(UITextField *)textFieldmétodo, use superViewpara mover até sua tableView e chame addGestureRecognizer:

[self.superview.superview addGestureRecognizer:gestureRecognizer];

E no - (void)textFieldDidEndEditing:(UITextField *)textField, basta remover o reconhecedor de gestos:

[self.superview.superview removeGestureRecognizer:gestureRecognizer];

Espero que ajude.

hac.jack
fonte
Isso fez isso por mim. Obrigado hac.jack
gilsaints88
2

Eu queria que meu celular abrisse o teclado quando qualquer parte da célula fosse selecionada e fechasse se você clicasse em qualquer lugar fora da célula. Para abrir o teclado:

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

(NOTA: Eu criei uma subclasse da célula, mas você pode facilmente fazer isso no tableView:didSelectRowAtIndexPath:método delegado de UITableView)

Isso significava que, com as soluções principais, se você clicar duas vezes na célula, o teclado irá tremer, pois primeiro o reconhecedor de gestos tenta fechar o teclado e, em seguida, a célula é selecionada novamente e tenta abrir o teclado.

A solução é verificar se o clique ocorreu dentro da célula atualmente selecionada:

- (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
fonte
2

Encontrei uma solução que funciona muito bem.

É necessário usar o UIGestureRecognizerDelegate eo método - GestureRecognizer: shouldReceiveTouch: .

Adicione o reconhecedor de gestos ao TableView da seguinte maneira:

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

Em seguida, implemente o método de delegado shouldReceiveTouch para rejeitar toques que são executados na classe UITableViewCell. O método hideKeyboard só será chamado quando o toque for executado fora da classe 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
fonte
2

UITableViewtem uma backgroundViewpropriedade útil , com a qual consegui esse comportamento sem mexer na seleção de células, conforme mostrado abaixo no Swift:

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

Basta usar um UITapGestureRecognizer e cancelsTouchesInView = NOsignifica que os toques nas células e UITextViews também acionam a ocultação. Isso é ruim se você tiver vários UITextViews e tocar no próximo. O teclado começará a se ocultar e, em seguida, o próximo textView se tornará o firstResponder e o teclado ficará visível novamente. Para evitar isso, verifique o local do toque e só oculte o teclado se o toque não estiver em uma célula:

// 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:ser disparado, a scrollEnabledpropriedade tableView deve serYES

// Hide on scroll
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}
Shawn Throop
fonte
Perfeito para mim. Adicionada uma caixa de texto à célula tableview; se eu tocar fora do teclado dispensar
Nicola
0

Por que você deseja criar uma tabela cheia de campos de texto? Você deve usar uma visão detalhada para cada linha que contém os campos de texto. Quando você empurra sua visão detalhada, certifique-se de chamar "[myTextField se torneFirstResponder]" para que o usuário possa começar a editar com apenas um clique de distância da lista da tabela.

Mugunth
fonte
O aplicativo Contatos da Apple faz exatamente isso. Eu não diria que está cheio de campos de texto por si só, mas os usa com bons resultados.
Joe D'Andrea
2
Editar texto embutido em uma tableview é muito mais rápido e intuitivo do que enviar visualizações de detalhes para cada campo de texto que o usuário deseja editar ... basta perguntar ao formulário HTML mais próximo, ou aos campos de texto nos painéis Preferências do iPhone, ou no aplicativo Contatos, ou etc etc etc ... é uma pena que a Apple não tenha feito isso um tipo de célula padrão, mas há muitas informações na web sobre como fazer isso.
glenc
0

Se você deseja criar uma subclasse (ugh!) De sua visualização de tabela, algo assim pode 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
fonte
0

Se você deseja dispensar o teclado enquanto a tecla return é pressionada, você pode simplesmente adicionar o seguinte código em textField deve retornar o método, isto é:

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

Alguns campos de texto podem ter uma visualização seletora ou outra como uma subvisualização, então, nesse caso, o método acima não funciona, então precisamos fazer uso da classe UITapGestureRecognizer, ou seja, adicionar o seguinte trecho de código ao método viewDidLoad, ou seja:

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

    [self.view addGestureRecognizer:tap];

Agora, basta adicionar o respondente de demissão ao método seletor, ou seja:

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

Espero que ajude, obrigado :)

Eshwar Chaitanya
fonte
0

Muitas respostas interessantes. Eu gostaria de compilar diferentes abordagens para a solução que achei mais adequada a um cenário UITableView (é o que eu costumo usar): O que geralmente queremos é basicamente esconder o teclado em dois cenários: tocando fora dos elementos da IU de texto, ou ao rolar para baixo / cima no UITableView. O primeiro cenário pode ser facilmente adicionado por meio de TapGestureRecognizer, e o segundo por meio do método UIScrollViewDelegate scrollViewWillBeginDragging :. Primeira ordem do dia, o método para ocultar o 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 resigna qualquer interface do usuário textField das subvisualizações dentro da hierarquia de visão UITableView, então é mais prático do que resignar cada elemento individualmente.

Em seguida, cuidamos de dispensar por meio de um gesto de toque externo, com:

- (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];

}

Definir tapGestureRecognizer.cancelsTouchesInView como NO é para evitar que o gestoRecognizer substitua o funcionamento interno normal do UITableView (por exemplo, para não interferir na seleção da célula).

Finalmente, para lidar com a ocultação do teclado na rolagem para cima / para baixo no UITableView, devemos implementar o método scrollViewWillBeginDragging: do protocolo UIScrollViewDelegate, como:

arquivo .h

@interface MyViewController : UIViewController <UIScrollViewDelegate>

arquivo .m

#pragma mark - UIScrollViewDelegate

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

Espero que ajude! =)

Robertibiris
fonte
0

Veja como eu finalmente fiz as coisas. Combinei sugestões e códigos de diferentes respostas. Recursos: dispensar teclado, mover campos de texto acima do teclado enquanto edita e define o tipo de retorno de teclado "Próximo" e "Concluído ".REPLACE" ... "com mais 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
fonte
0

A resposta de @mixca é muito útil, mas e se eu tiver algo diferente de UITextField. Acho que a melhor maneira de lidar com isso pesquisando todas as subvisualizações da visualização principal com função recursiva, veja o exemplo abaixo

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

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

e também você pode colocar este método em sua classe de utilitário e pode usar a partir de um gesto de toque como a resposta de @mixca ..

mert
fonte
0

Swift 4 / 4.2 / 5

Você também pode dispensar o teclado quando uma célula é tocada - antes de fazer qualquer outra coisa.

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

tableView.keyboardDismissMode = .onDrag // .interactive

K. Mitra
fonte