iOS – Ignore o teclado ao tocar fora do UITextField

Eu estou querendo saber como fazer o teclado desaparecer quando o usuário toca fora de um UITextField .

Você precisará adicionar um UITapGestureRecogniser e atribuí-lo à exibição e, em seguida, chamar UITapGestureRecogniser no UITextField em seu seletor.

O código:

In viewDidLoad

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

Em dismissKeyboard:

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

(Onde aTextField é o campo de aTextField responsável pelo teclado)

Swift 3 versão parece que

 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard (_:))) self.view.addGestureRecognizer(tapGesture) 

Para dismissKeyboard

 func dismissKeyboard (_ sender: UITapGestureRecognizer) { aTextField.resignFirstResponder() } 

Eu amassei algumas respostas.

Use um ivar que seja inicializado durante viewDidLoad:

 UIGestureRecognizer *tapper; - (void)viewDidLoad { [super viewDidLoad]; tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; tapper.cancelsTouchesInView = NO; [self.view addGestureRecognizer:tapper]; } 

Dispensar o que estiver editando atualmente:

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

Verifique isso, essa seria a maneira mais fácil de fazer isso,

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [self.view endEditing:YES];// this will do the trick } 

Ou

Esta biblioteca irá lidar com rolagem automática da barra de rolagem, toque no espaço para ocultar o teclado, etc …

https://github.com/michaeltyson/TPKeyboardAvoiding

Eu vejo que algumas pessoas estão tendo problemas usando o método UITapGestureRecognizer . A maneira mais fácil de ter conseguido essa funcionalidade enquanto ainda deixo intacto o comportamento do toque do meu botão existente é adicionar apenas uma linha à resposta do @Jensen2k:

 [tap setCancelsTouchesInView:NO]; 

Isso permitiu que meus botões existentes ainda funcionassem sem usar o método do @Dmitry Sitnikov.

Leia sobre essa property aqui (pesquise por CancelsTouchesInView ): UIGestureRecognizer Class Reference

Eu não tenho certeza de como isso funcionaria com as barras de rolagem, como vejo alguns problemas, mas espero que alguém possa ter o mesmo cenário que eu tive.

É melhor tornar seu UIView uma instância do UIControl (no construtor de interface) e, em seguida, conectar seu evento dismissKeyboard ao método dismissKeyboard . Este método IBAction será parecido com:

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

Versão Swift, isso funciona em combinação com outros elementos (como um UIButton ou outro UITextField ):

 override func viewDidLoad() { super.viewDidLoad() let tapper = UITapGestureRecognizer(target: self, action:#selector(endEditing)) tapper.cancelsTouchesInView = false view.addGestureRecognizer(tapper) } 

Que tal isso: eu sei que este é um post antigo. Pode ajudar alguém 🙂

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSArray *subviews = [self.view subviews]; for (id objects in subviews) { if ([objects isKindOfClass:[UITextField class]]) { UITextField *theTextField = objects; if ([objects isFirstResponder]) { [theTextField resignFirstResponder]; } } } } 

Esta é uma boa solução genérica:

Objetivo-C:

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

Rápido:

 override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { self.view.endEditing(true) } 

Com base na solução @icodebuster: https://stackoverflow.com/a/18756253/417652

Acho que a maneira mais fácil (e melhor) de fazer isso é subclassificar sua visão global e usar o método hitTest:withEvent para ouvir qualquer toque. Toques no teclado não são registrados, então hitTest: withEvent só é chamado quando você toca / desliza / desliza / pinça … em outro lugar, depois chama [self endEditing:YES] .

Isso é melhor do que usar o touchesBegan porque touchesBegan não são chamados se você clicar em um botão na parte superior da exibição. É melhor que o UITapGestureRecognizer que não reconhece um gesto de rolagem, por exemplo. Também é melhor do que usar uma canvas esmaecida, porque em uma interface de usuário dinâmica e complexa, você não pode colocar a canvas ofuscada em todos os lugares. Além disso, ele não bloqueia outras ações, você não precisa tocar duas vezes para selecionar um botão externo (como no caso de um UIPopover ).

Além disso, é melhor do que chamar [textField resignFirstResponder] , porque você pode ter muitos campos de texto na canvas, portanto, isso funciona para todos eles.

Você pode fazer isso usando o Storyboard no XCode 6 e acima:

Crie a ação para esconder o teclado

Adicione isto ao arquivo de header da class usada pelo seu ViewController:

 @interface TimeDelayViewController : UIViewController  - (IBAction)dissmissKeyboardOnTap:(id)sender; @end 

Em seguida, adicione isso ao arquivo de implementação do mesmo ViewController:

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

Agora, essa será uma das “Ações Recebidas” para sua cena de storyboard (por exemplo, ViewController):

insira a descrição da imagem aqui

Conecte a ação ao evento do usuário

Agora você precisa conectar essa ação ao gesto do usuário de tocar o teclado.

Importante – Você precisa converter o ‘UIView’ contido no storyboard em um UIControl para poder receber events. Selecione a vista da sua hierarquia View Controller Scene:

insira a descrição da imagem aqui

… e mude sua class:

insira a descrição da imagem aqui

Agora arraste do pequeno círculo ao lado da ‘ação recebida’ para sua cena, para uma parte ‘vazia’ da sua cena (na verdade, você está arrastando a ‘Ação Recebida’ para o UIControl). Você verá uma seleção de events aos quais você pode conectar sua ação para:

insira a descrição da imagem aqui

Selecione a opção ‘retocar dentro’. Você agora conectou a IBAction que você criou a uma ação do usuário de tocar o teclado. Quando o usuário tocar o teclado, ele ficará oculto.

(NOTA: Para ligar a ação ao evento, você também pode arrastar a ação recebida diretamente para o UIControl na hierarquia de Controladores de exibição. Ela é exibida como ‘Controle’ na hierarquia.)

Essa deve ser a maneira mais fácil de ocultar seu teclado tocando fora:

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

(De como dispensar o teclado quando o usuário toca em outra área fora do campo de texto? )

Swift 4

Configure seu UIViewController com este método de extensão uma vez, por exemplo, em viewDidLoad :

 override func viewDidLoad() { super.viewDidLoad() self.setupHideKeyboardOnTap() } 

e o teclado será dispensado mesmo tocando no NavigationBar .

 import UIKit extension UIViewController { /// Call this once to dismiss open keyboards by tapping anywhere in the view controller func setupHideKeyboardOnTap() { self.view.addGestureRecognizer(self.endEditingRecognizer()) self.navigationController?.navigationBar.addGestureRecognizer(self.endEditingRecognizer()) } /// Dismisses the keyboard from self.view private func endEditingRecognizer() -> UIGestureRecognizer { let tap = UITapGestureRecognizer(target: self.view, action: #selector(self.view.endEditing(_:))) tap.cancelsTouchesInView = false return tap } } 

Se eu te acertei, você quer renunciar ao teclado enquanto toca no lado de fora do campo de texto, mas você não tem referência do seu campo de textfield .

Tente isso;

  • Tome textField global, vamos chamá-lo reftextField
  • Agora, em textFieldDidBeginEditing defina o campo de texto referido como

     - (void) textFieldDidBeginEditing:(UITextField *)textField{ reftextField = textField; } 
  • Agora você pode usar com alegria em qualquer relógio de botão (adicionando um botão transparente na edição inicial recomendada)

     - (void)dismissKeyboard { [reftextField resignFirstResponder]; } 
  • Ou para renunciar botão done tente isso.

     //for resigning on done button - (BOOL) textFieldShouldReturn:(UITextField *)textField{ [textField resignFirstResponder]; return YES; } 

Só para adicionar à lista aqui a minha versão de como dispensar um teclado no toque externo.

viewDidLoad:

 UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; [self.view addGestureRecognizer:singleTap]; 

Qualquer lugar:

 -(void)handleSingleTap:(UITapGestureRecognizer *)sender{ [textFieldName resignFirstResponder]; puts("Dismissed the keyboard"); } 

Muitas ótimas respostas aqui sobre o uso do UITapGestureRecognizer – todos os quais interrompem o botão clear (X) do UITextField . A solução é suprimir o reconhecedor de gestos por meio de seu delegado:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { BOOL touchViewIsButton = [touch.view isKindOfClass:[UIButton class]]; BOOL touchSuperviewIsTextField = [[touch.view superview] isKindOfClass:[UITextField class]]; return !(touchViewIsButton && touchSuperviewIsTextField); } 

Não é a solução mais robusta, mas funciona para mim.

Se a visualização estiver incorporada em um UIScrollView , você poderá usar o seguinte:

 tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive; 

O primeiro animará o teclado para fora da canvas quando a exibição da tabela for rolada e o último ocultará o teclado como o aplicativo de mensagens do Google Stock.

Observe que estes estão disponíveis no iOS 7.0 ou superior.

Você pode criar categoria para o UiView e replace a tabela touchesBegan da seguinte maneira.

Está funcionando bem para mim. E é uma solução centralizada para esse problema.

 #import "UIView+Keyboard.h" @implementation UIView(Keyboard) - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.window endEditing:true]; [super touchesBegan:touches withEvent:event]; } @end 

Versão rápida da resposta do @ Jensen2k:

 let gestureRecognizer : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: "dismissKeyboard") self.view.addGestureRecognizer(gestureRecognizer) func dismissKeyboard() { aTextField.resignFirstResponder() } 

Um forro

 self.view.addTapGesture(UITapGestureRecognizer.init(target: self, action: "endEditing:")) 

Eu usei o exemplo de Barry para meu novo desenvolvimento. Funcionou muito bem! mas eu tive que include uma pequena mudança, necessária para dispensar o teclado apenas para o campo de texto que está sendo editado.

Então, eu adicionei ao exemplo de Barry o seguinte:

 - (void) textFieldDidBeginEditing:(UITextField *)textField { _textBeingEdited = textField; } -(void) textFieldDidEndEditing:(UITextField *)textField { _textBeingEdited = nil; } 

Além disso, mudei o método hideKeyboard da seguinte forma:

 - (IBAction)hideKeyboard:(id)sender { // Just call resignFirstResponder on all UITextFields and UITextViews in this VC // Why? Because it works and checking which one was last active gets messy. //UITextField * tf = (UITextField *) sender; [_textBeingEdited resignFirstResponder]; } 

Uma das formas mais fáceis e curtas é adicionar este código ao seu viewDidLoad

 [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self.view action:@selector(endEditing:)]]; 

Swift 4 oneliner

 view.addGestureRecognizer(UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:)))) 

Envie a mensagem resignFirstResponder para o arquivo de texto que a colocou lá. Por favor, veja este post para mais informações.

Isso funciona

Neste exemplo, aTextField é o único UITextField …. Se houver outros ou UITextViews, há um pouco mais a ser feito.

 // YourViewController.h // ... @interface YourViewController : UIViewController /* some subclass of UIViewController */  // < -- add this protocol // ... @end // YourViewController.m @interface YourViewController () @property (nonatomic, strong, readonly) UITapGestureRecognizer *singleTapRecognizer; @end // ... @implementation @synthesize singleTapRecognizer = _singleTapRecognizer; // ... - (void)viewDidLoad { [super viewDidLoad]; // your other init code here [self.view addGestureRecognizer:self.singleTapRecognizer]; { - (UITapGestureRecognizer *)singleTapRecognizer { if (nil == _singleTapRecognizer) { _singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapToDismissKeyboard:)]; _singleTapRecognizer.cancelsTouchesInView = NO; // absolutely required, otherwise "tap" eats events. } return _singleTapRecognizer; } // Something inside this VC's view was tapped (except the navbar/toolbar) - (void)singleTapToDismissKeyboard:(UITapGestureRecognizer *)sender { NSLog(@"singleTap"); [self hideKeyboard:sender]; } // When the "Return" key is pressed on the on-screen keyboard, hide the keyboard. // for protocol UITextFieldDelegate - (BOOL)textFieldShouldReturn:(UITextField*)textField { NSLog(@"Return pressed"); [self hideKeyboard:textField]; return YES; } - (IBAction)hideKeyboard:(id)sender { // Just call resignFirstResponder on all UITextFields and UITextViews in this VC // Why? Because it works and checking which one was last active gets messy. [aTextField resignFirstResponder]; NSLog(@"keyboard hidden"); } 

Eu tentei muitas das respostas aqui e não tive sorte. Meu reconhecedor de gestos de toque estava sempre fazendo com que meus UIButtons não respondessem quando tocados, mesmo quando eu definia a propriedade cancelsTouchesInView do reconhecedor de gestos como NO.

Isso é o que acabou resolvendo o problema:

Tenha um ivar:

 UITapGestureRecognizer *_keyboardDismissGestureRecognizer; 

Quando um campo de texto começa a editar, defina o reconhecedor de gestos:

 - (void) textFieldDidBeginEditing:(UITextField *)textField { if(_keyboardDismissGestureRecognizer == nil) { _keyboardDismissGestureRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)] autorelease]; _keyboardDismissGestureRecognizer.cancelsTouchesInView = NO; [self.view addGestureRecognizer:_keyboardDismissGestureRecognizer]; } } 

Então o truque está em como você configura o método dismissKeyboard:

 - (void) dismissKeyboard { [self performSelector:@selector(dismissKeyboardSelector) withObject:nil afterDelay:0.01]; } - (void) dismissKeyboardSelector { [self.view endEditing:YES]; [self.view removeGestureRecognizer:_keyboardDismissGestureRecognizer]; _keyboardDismissGestureRecognizer = nil; } 

Eu acho que há apenas algo sobre como obter a execução de dismissKeyboardSelector fora da pilha de execução de manipulação de toque …

 - (void)viewDidLoad { [super viewDidLoad]; UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; [singleTapGestureRecognizer setNumberOfTapsRequired:1]; [singleTapGestureRecognizer requireGestureRecognizerToFail:singleTapGestureRecognizer]; [self.view addGestureRecognizer:singleTapGestureRecognizer]; } - (void)handleSingleTap:(UITapGestureRecognizer *)recognizer { [self.view endEditing:YES]; [textField resignFirstResponder]; [scrollView setContentOffset:CGPointMake(0, -40) animated:YES]; } 

Adicione este código em seu arquivo ViewController.m :

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.view endEditing:YES]; } 
 override func touchesBegan(touches: Set, withEvent event: UIEvent?) { if let touch = touches.first{ view.endEditing(true) } } 

Nesse caso, pode-se usar o ScrollView e adicioná-lo ao TextField no ScrollView e eu quero tocar o ScrollView e o View e depois dispensar o teclado. Eu tentei criar código de exemplo apenas no caso. Como isso,

 import UIKit class ViewController: UIViewController { @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap(_:))) view.addGestureRecognizer(tapGesture) // Do any additional setup after loading the view, typically from a nib. } func tap(gesture: UITapGestureRecognizer) { textField.resignFirstResponder() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

Seu storyboard Olhe para isso como.

insira a descrição da imagem aqui

Você pode usar o método UITapGestureRecongnizer para dispensar o teclado clicando fora do UITextField. Ao usar esse método sempre que o usuário clicar fora do UITextField, o teclado será descartado. Abaixo está o trecho de código para usá-lo.

  UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissk)]; [self.view addGestureRecognizer:tap]; //Method - (void) dismissk { [abctextfield resignFirstResponder]; [deftextfield resignFirstResponder]; } 
  • Definir campos de texto em que o delegate in view foi carregado:

     override func viewDidLoad() { super.viewDidLoad() self.userText.delegate = self } 
  • Adicione esta function:

     func textFieldShouldReturn(userText: UITextField!) -> Bool { userText.resignFirstResponder() return true; }