Maneira fácil de descartar o teclado?


377

Eu tenho alguns controles espalhados por muitas células da tabela e fiquei pensando se há uma maneira mais fácil de descartar o teclado sem ter que percorrer todos os meus controles e renunciar a todos como o primeiro respondedor. Eu acho que a pergunta é .. Como eu colocaria o primeiro atendente atual no teclado?


bom complemento para esta pergunta: stackoverflow.com/questions/1490573/…
ericsoco

Uma ressalva para todas as respostas abaixo. Se você executar uma sequência logo após renunciar ao KB, o KB fica órfão e não pode ser descartado. Você deve descartar a KB no método textFieldShouldReturn.
gjpc

26
dispensa de teclado global da maneira certa:[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
Yerk

Achei este vídeo útil pinkstone.co.uk/… . Talvez possa ajudar os outros.
enthusiasticgeek

Respostas:


797

Tentar:

[self.view endEditing:YES];

11
Isso parece funcionar (testado no ios4.1). Embora esteja disponível apenas no iOS 3.2 ou superior. Não tenho certeza se isso realmente funciona ou se é apenas um efeito colateral não garantido de chamar uma API de uma maneira que não esteja documentada para funcionar.
JosephH 14/09/10

3
Isso funcionou perfeitamente para mim e certamente é preferível a algumas das outras respostas a esta pergunta. Os documentos dizem que está disponível no iOS 2.0 e posterior.
Antsyawn

8
Como a documentação diz: "Este método examina a exibição atual e sua hierarquia de subvisões para o campo de texto que atualmente é o primeiro respondedor. Se encontrar um, ele solicitará que o campo de texto renuncie como primeiro respondedor. Se o parâmetro force estiver definido para SIM, o campo de texto nunca é solicitado; ele é forçado a renunciar. " - portanto, esta é a resposta correta à pergunta original da IMO (caso de uso: tenho um formulário com milhões de campos, bem - dez ... mais ou menos, e preciso descartar o teclado).
joshis

14
A resposta não está errada, mas um pouco incorreta, na verdade deveria estar: [self.view endEditing:YES];como os valores BOOL são SIM / NÃO no Objetivo-C.
Chrisben

24
chrisben: Você pode usar SIM / NÃO, VERDADEIRO / FALSO, 0/1.
Michael Superczynski

126

Você pode forçar a exibição de edição atual a renunciar ao status de primeiro respondedor [view endEditing:YES]. Isso oculta o teclado.

Ao contrário -[UIResponder resignFirstResponder], -[UIView endEditing:]procurará nas sub-visualizações para encontrar o primeiro atendedor atual. Assim, você pode enviá-lo para sua visualização de nível superior (por exemplo, self.viewem a UIViewController) e ele fará a coisa certa.

(Essa resposta anteriormente incluía algumas outras soluções, que também funcionavam, mas eram mais complicadas do que o necessário. Eu as removi para evitar confusão.)


Mas isso apenas impedirá o componente de se tornar firstResponder, não removerá o status atual de firstResponder de um elemento.
Kendall Helmstetter Gelner

O que eu quis dizer ao substituir o transformFirstResponder para armazenar o primeiro respondedor em algum lugar, para que ele possa ser acessado (nesse caso, renunciou) mais tarde. O problema básico é que o Cocoa Touch não fornece uma maneira de solicitar uma janela ou exibir qual é o seu primeiro respondedor.
22630 Nicholas Riley

+1 A adição de um problema resolvido do becomeFirstResponder que eu estava tendo com toques em outros UITextFields.
21412 Jason Jason

3
Isso é obsoleto. A [self.view endEditing:YES];resposta é melhor.
ftvs

11
Isso não é obsoleto, esta resposta explica exatamente como [UIView endediting:]funciona. Em um dos aplicativos que desenvolvi, uma caixa de pesquisa foi adicionada no UINavigationViewController; se você chamar [self.view endEditing:YES], como selfseu controlador de exibição, isso não funcionará. Em vez disso, chamei esse método diretamente no escopo da exibição onde a caixa de pesquisa foi adicionada, por exemplo: [self.mySearchBoxView endEditing:YES].
Jan Cássio

92

Você pode enviar uma ação nula direcionada para o aplicativo, ele renunciará ao socorrista a qualquer momento, sem precisar se preocupar com qual visualização atualmente possui o status de socorrista.

Objetivo-C:

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

Swift 3.0:

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

Nenhuma ação direcionada é comum no Mac OS X para comandos de menu, e aqui está um uso para elas no iOS.


14
Melhor solução de toda a página.
precisa

Absolutamente a melhor maneira de se livrar do teclado de qualquer lugar no aplicativo iOS.
Ben Sinclair

Ainda funciona para mim no iOS8. No meu aplicativo, tenho um menu da barra lateral e há momentos em que o controlador de exibição "central" mostra o teclado. E eu quero descartar o teclado se o menu da barra lateral aparecer. Então, eu adicionei esse código no método viewWillAppear do meu menu da barra lateral.
Jenn Eve

11
Ainda funciona no iOS 9. Ótima maneira de renunciar globalmente ao foco de um campo de texto e dispensar o teclado.
bmjohns

E para continuar esta raia de comentar em particular .... ainda funciona no iOS 10. :-)
Travelling Man

56

Para ser sincero, não sou louco por nenhuma das soluções propostas aqui. Encontrei uma boa maneira de usar um TapGestureRecognizer que acho que está no coração do seu problema: quando você clica em qualquer coisa além do teclado, ignore-o.

  1. No viewDidLoad, registre-se para receber notificações do teclado e crie um UITapGestureRecognizer:

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    
    [nc addObserver:self selector:@selector(keyboardWillShow:) name:
    UIKeyboardWillShowNotification object:nil];
    
    [nc addObserver:self selector:@selector(keyboardWillHide:) name:
    UIKeyboardWillHideNotification object:nil];
    
    tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
    action:@selector(didTapAnywhere:)];
  2. Adicione o teclado show / hide responders. Lá você adiciona e remove o TapGestureRecognizer para o UIView que deve descartar o teclado quando tocado. Nota: Você não precisa adicioná-lo a todas as sub-visualizações ou controles.

    -(void) keyboardWillShow:(NSNotification *) note {
        [self.view addGestureRecognizer:tapRecognizer];
    }
    
    -(void) keyboardWillHide:(NSNotification *) note
    {
        [self.view removeGestureRecognizer:tapRecognizer];
    }
  3. O TapGestureRecognizer chamará sua função quando tocar e você poderá descartar o teclado assim:

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

O bom dessa solução é que ela filtra apenas torneiras, não furtos. Portanto, se você tiver rolando o conteúdo acima do teclado, os deslizadores ainda rolam e deixam o teclado exibido. Ao remover o reconhecedor de gestos após o teclado desaparecer, os toques futuros na sua exibição são gerenciados normalmente.


Na minha implementação, adicionei @property (assign) UITapGestureRecognizer * tapRecognizer; e modificou self.tapRecognizer = [[alocação de UITapGestureRecognizer] initWithTarget: ação própria: @selector (didTapAnywhere :)];
Professor Todd

Estou tentando fazer uma coisa semelhante e não estou recebendo o retorno de chamada. Curioso: por que sua propriedade é 'atribuída'?
precisa saber é o seguinte

Mais um e, além disso, esse deve ser o comportamento padrão do iOS. Ou pelo menos adicione uma maneira simples de alternar um botão de descartar.
Shaunti Fondrisi

24

Esta é uma solução para fazer com que o teclado desapareça quando pressionado returnem qualquer campo de texto, adicionando código em um único local (portanto, não é necessário adicionar um manipulador para cada campo de texto):


considere este cenário:

Eu tenho um viewcontrollercom dois campos de texto (nome de usuário e senha). e o protocolo de viewcontrollerimplementosUITextFieldDelegate

eu faço isso em viewDidLoad

- (void)viewDidLoad 
{
    [super viewDidLoad];

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

e o viewcontroller implementa o método opcional como

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

e independentemente do campo de texto em que você está, assim que eu clico returnno teclado, ele é descartado!

No seu caso, o mesmo funcionaria desde que você defina todos os delegados do campo de texto como auto e implementem textFieldShouldReturn


Bem, eu já tenho o problema resolvido, mas, no meu caso, queria descartar o teclado sozinho (em código) e não sabia qual textField tinha o status de primeiro respondedor.
Seventoes 16/07/09

11
Há casos em que você pode querer descartar o teclado sem bater "retorno", por exemplo, quando um menu lateral está prestes a ser exibido
Peter Johnson

Editado para esclarecer que esta resposta é relevante apenas em situações em que pressionar "retornar" é uma solução aceitável. [No meu caso, eu também queria descartar o teclado quando o usuário toca fora do campo que está sendo editado; esta resposta não ajuda com isso.]
ToolmakerSteve 14/03

14

Uma abordagem melhor é fazer com que algo "roube" o status de socorrista.

Como o UIApplication é uma subclasse do UIResponder, você pode tentar:

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

Caso contrário, crie um novo UITextField com um quadro de tamanho zero, adicione-o a uma exibição em algum lugar e faça algo semelhante (torne-se seguido de renúncia).


11
O truque do UIApplication não funciona (ele trava, pelo menos no simulador), mas você não precisa de um UITextField de tamanho zero - basta escolher qualquer campo aleatório e fazer isso com ele. O transformFirstResponder do NSResponder é um método apenas de notificação, mas o UIResponder não é (o design é pior, na verdade).
22610 Nicholas Riley

11
Aha, obrigada! Ele falha ao chamá-lo no UIApplication, mas o tamanho zero do UITextField funciona muito bem, e não preciso recuperar nenhum dos meus campos anteriores.
Seventoes 21/04/09

Por que alguém faria isso se existe um método oficial, perfeitamente bom e documentado para isso?
Maciej Swic

2
Eles não veriam a resposta mais votada para obter a melhor solução. Simplesmente não era bem conhecido na época (minha resposta foi de 2009, a outra resposta veio mais de um ano depois em 2010). mas deixo para a posteridade.
Kendall Helmstetter Gelner

8

Coloque isso em alguma aula de utilidade.

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

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

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

11
era isso que eu estava procurando!
Aslisabanci

Perfeito, exceto que você não precisa do método globalResignFirstResponderRec, basta chamar [view endEditing: YES]. Faz a mesma coisa.
n13 29/09/2015

sim! A solução final! Eu tentei de várias maneiras, apenas esta funciona para mim! Muito obrigado!
douyw 17/05

6

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

Absolutamente brilhante!

Obrigado.

Considerando o seu conselho e o de outras pessoas neste segmento, foi o que eu fiz:

Como fica quando usado:

[[self appDelegate] dismissKeyboard]; (observação: adicionei appDelegate como uma adição ao NSObject para que eu possa usar em qualquer lugar em qualquer coisa)

O que parece sob o capô:

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

EDITAR

Alteração à minha resposta incluída tempTextField.enabled = NO;. A desativação do campo de texto irá impedir UIKeyboardWillShowNotificatione UIKeyboardWillHideNotificationnotificações de teclado sejam enviados você deve confiar sobre estas notificações em todo o seu aplicativo.


não sei se funciona, mas parece uma maneira fácil e inteligente.
demon

5

Dica rápida sobre como descartar o teclado no iOS quando um usuário toca em qualquer lugar da tela fora do UITextField ou teclado. Considerando a quantidade de espaço que o teclado do iOS pode ocupar, faz sentido ter uma maneira fácil e intuitiva para que seus usuários descartem o teclado.

Aqui está um link


Ótimo! adicionar ao AppDelegate faz com que funcione para TODAS as visualizações relacionadas.
Jiulong Zhao

5

Muitas respostas excessivamente complicadas aqui, talvez porque isso não seja fácil de encontrar na documentação do iOS. JosephH tinha logo acima:

[[view window] endEditing:YES];

4

Ainda mais simples que a resposta de Meagar

substituir touchesBegan:withEvent:

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

Isso acontece dismiss the keyboardquando você toca em qualquer lugar do background.


3

Aqui está o que eu uso no meu código. Ele funciona como um encanto!

Em yourviewcontroller.h, adicione:

@property (nonatomic) UITapGestureRecognizer *tapRecognizer;

Agora no arquivo .m, adicione isso à sua função ViewDidLoad:

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

Além disso, adicione esta função no arquivo .m:

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

Obrigado! Mas você deve renomear a função para 'didTapAnywhere' ou o reconhecedor gesto para 'handleSingleTap' ;-)
Matthijs

2

No arquivo de cabeçalho do seu controlador de exibição, inclua <UITextFieldDelegate>na definição da interface do seu controlador, para que esteja em conformidade com o protocolo de delegação UITextField ...

@interface someViewController : UIViewController <UITextFieldDelegate>

... No arquivo de implementação do controlador (.m), adicione o seguinte método, ou o código, se você já tiver um método viewDidLoad ...

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

... Em seguida, vincule yourTextBox ao seu campo de texto real

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

2

Você deve enviar endEditing:para a janela de trabalho sendo a subclasse deUIView

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

Aposto que você quis dizer SIM ao invés)
Matrosov Alexander

2

A melhor maneira de descartar o teclado do UITableView e UIScrollView é:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag

2

No swift 3, você pode fazer o seguinte

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

1

A resposta de Jeremy não estava funcionando muito bem para mim, acho que porque eu tinha uma pilha de navegação em uma visualização de guia com uma caixa de diálogo modal em cima. Estou usando o seguinte agora e está funcionando para mim, mas sua milhagem pode variar.

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

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

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

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

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

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

    [uivc.view  addSubview:tempTextField];

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

}

Hmm - por que o voto negativo? Abordei deficiências específicas do mundo real em outra resposta com código testado. Eu posso entender a falta de votos positivos, mas votar em território negativo é um verdadeiro desânimo. Ainda espero que a resposta acima ajude outra pessoa.
JJ Rohrer

1

Também pode ser necessário substituir o UIViewController disablesAutomaticKeyboardDismissal para que isso funcione em alguns casos. Isso pode ter que ser feito no UINavigationController, se você tiver um.


1

Subclasse seus campos de texto ... e também visualizações de texto

Na subclasse coloque este código ..

-(void)conformsToKeyboardDismissNotification{

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

-(void)deConformsToKeyboardDismissNotification{

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

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

Nos delegados do campo de texto (da mesma forma para delegados do textview)

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


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

Tudo pronto .. Agora basta postar a notificação em qualquer lugar do seu código. Ele renunciará a qualquer teclado.


1

E rapidamente podemos fazer

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

Eu não entendo como funciona o primeiro respondedor .. onde coloco isso? na minha visão controlador ou delegado?
Shayan C

Não importa. Você pode colocá-lo onde quiser. ou seja, ação do botão
Eike

1

Para descartar um teclado depois que ele aparecer, existem 2 casos ,

  1. quando o UITextField estiver dentro de um UIScrollView

  2. quando o UITextField estiver fora de um UIScrollView

2. quando o UITextField estiver fora de um UIScrollView, substitua o método na sua subclasse UIViewController

você também deve adicionar delegado para todos os UITextView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}
  1. Em uma exibição de rolagem, Tocar fora não dispara nenhum evento ; portanto, use um Reconhecedor de gestos de toque , arraste e solte um UITapGesture para a exibição de rolagem e crie uma IBAction para ela .

para criar uma IBAction, pressione ctrl + clique no UITapGesture e arraste-o para o arquivo .h do viewcontroller.

Aqui nomeei tappedEvent como meu nome de ação

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

As informações acima foram obtidas a partir do link a seguir, consulte para obter mais informações ou entre em contato comigo se você não entender os dados acima.

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


0

Detesto que não haja uma maneira "global" de descartar programaticamente o teclado sem usar chamadas de API privadas. Freqüentemente, tenho a necessidade de descartar o teclado programaticamente sem saber qual objeto é o primeiro respondedor. Eu tentei inspecionar o selfuso da API de tempo de execução Objective-C, enumerando todas as suas propriedades, retirando as que são do tipo UITextFielde enviando a resignFirstRespondermensagem.

Não deve ser tão difícil fazer isso ...


0

Não é bonito, mas a maneira como eu renuncio o firstResponder quando não sei o que é esse respondedor:

Crie um UITextField, no IB ou programaticamente. Torná-lo oculto. Vincule-o ao seu código, se você o criou no IB. Então, quando você deseja descartar o teclado, alterne o respondedor para o campo de texto invisível e o renuncie imediatamente:

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

0

Você pode iterar recursivamente por meio de sub-visualizações, armazenar uma matriz de todos os UITextFields e, em seguida, fazer um loop por eles e renunciar a todos.

Não é realmente uma ótima solução, especialmente se você tiver muitas subviews, mas para aplicativos simples, isso deve funcionar.

Resolvi isso de uma maneira muito mais complicada, mas com muito mais desempenho, mas usando um singleton / gerente para o mecanismo de animação do meu aplicativo, e sempre que um campo de texto se tornasse o responsável pela resposta, eu atribuiria uma atribuição a uma estática que obteria varreu (renunciou) com base em outros eventos ... é quase impossível para mim explicar em um parágrafo.

Seja criativo, levei apenas 10 minutos para pensar sobre isso no meu aplicativo depois de encontrar essa pergunta.


Resolvido este mês atrás;) Acabei salvando o campo ativo em foco e usando isso.
Seventoes 13/09/10

0

Um método um pouco mais robusto que eu precisava usar recentemente:

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

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

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

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

Descobri que alguns dos outros métodos "globais" não funcionaram (por exemplo, UIWebViewe WKWebViewrecusamos renunciar).


0

Adicione um reconhecedor de gestos de toque à sua visualização.

seu arquivo .m será como

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

Funcionou para mim


0

Sim, a edição final é a melhor opção. E a partir do iOW 7.0, UIScrollViewpossui um recurso interessante para descartar o teclado ao interagir com a visualização de rolagem. Para conseguir isso, você pode definir a keyboardDismissModepropriedade de UIScrollView.

Defina o modo de desativação do teclado como:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag

Tem alguns outros tipos. Veja este documento da apple .



0

a maneira mais fácil é chamar o método

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

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

Você não precisa do 'if' lá, resignFirstResponder fará tudo de qualquer maneira. Talvez você quis dizer - (BOOL) canResignFirstResponder?
Seventoes

0

Você precisa usar um desses métodos,

[self.view endEditing:YES];

ou

[self.textField resignFirstResponder];
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.