Feche o teclado do iOS tocando em qualquer lugar usando o Swift

409

Eu tenho procurado por tudo isso, mas não consigo encontrá-lo. Eu sei como descartar o teclado usando, Objective-Cmas não tenho idéia de como fazer isso usando Swift? Alguém sabe?

lagoa
fonte
9
Como você está fazendo isso no Objective-C? Normalmente, é uma conversão de uma sintaxe para outra e raramente é uma questão de diferentes métodos / convenções.
Craig Otis
5
Eu não tenho cavado Swift, mas eu estava sob a impressão de que a API é a mesma ...
coreyward
Você pode querer verificar esta resposta .
Ahmad F

Respostas:

1299
override func viewDidLoad() {
    super.viewDidLoad()

    //Looks for single or multiple taps. 
    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")

    //Uncomment the line below if you want the tap not not interfere and cancel other interactions.
    //tap.cancelsTouchesInView = false 

    view.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)
}

Aqui está outra maneira de executar esta tarefa se você usar esta funcionalidade em vários UIViewControllers:

// Put this piece of code anywhere you like
extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        tap.cancelsTouchesInView = false            
        view.addGestureRecognizer(tap)
    }

    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}

Agora em todos UIViewController, tudo o que você precisa fazer é chamar esta função:

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

Esta função está incluída como uma função padrão no meu repositório, que contém muitas Extensões Swift úteis como esta, confira: https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
fonte
19
Desde Swift 2 na primeira resposta, substituir este line-> vamos torneira: UITapGestureRecognizer = UITapGestureRecognizer (meta: auto, ação: #selector (MyViewController.dismissKeyboard))
Sam Bellerose
2
ele quebra segue de tableviewcell em um tableviewcontroller
Utku Dalmaz
11
Esta é uma das extensões mais úteis que já encontrei! Obrigado! A única cautela que gostaria de estender é que isso pode interferir didSelectRowAtIndexPath.
Clifton Labrum
47
Acabei de descobrir esta questão e implementou esse método. Aquela coisa com "didSelectRow" de tableView / UICollectionView que não estava chamando literalmente me deixou maluca. A solução é: Basta adicionar este a sua extensão: tap.cancelsTouchesInView = false. Isso resolveu isso para mim, pelo menos. Espero que isso ajude alguém
Quantm
10
"Confira meu repo" é o novo "Hears my new mixtape": P
Josh
118

Uma resposta para sua pergunta sobre como descartar o teclado no Xcode 6.1 usando o Swift abaixo:

import UIKit

class ItemViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textFieldItemName: UITextField!

    @IBOutlet var textFieldQt: UITextField!

    @IBOutlet var textFieldMoreInfo: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        textFieldItemName.delegate = self
        textFieldQt.delegate = self
        textFieldMoreInfo.delegate = self
    }

                       ...

    /**
     * Called when 'return' key pressed. return NO to ignore.
     */
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }


   /**
    * Called when the user click on the view (outside the UITextField).
    */
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.view.endEditing(true)
    }

}

( Fonte desta informação ).

O rei da bruxaria
fonte
6
Ótimo pedaço de código, obrigado! touchesBegan foi exatamente o que eu estava procurando :)
Lukasz Czerwinski
4
Isso não funcionou muito para mim. Se eu tocar na visualização do controlador de exibição, ela funcionará. Se eu tocar em um item de controle na exibição, o teclado não será descartado.
user3731622
Esta é a melhor resposta que eu já usei até agora! Esta resposta deve ser marcada como correta. Valeu cara!
wagng
Esta é a melhor solução que eu já vi até agora. Nota pequena: no Swift mais recente, a assinatura de substituição mudou um pouco. Você precisa adicionar _ antes de toques: substituir função touchesBegan (_ toques: Set <UITouch>, com eventoEvent: UIEvent?)
Regis St-Gelais
11
Este provavelmente deve estar marcado como correto. A resposta atual aceita faz com que todos os botões na exibição não respondam quando o teclado está sendo exibido.
Bartek Spitza 07/03/19
39

Swift 4 trabalhando

Crie um ramal como abaixo e ligue hideKeyboardWhenTappedAround()no seu controlador de exibição Base.

//
//  UIViewController+Extension.swift
//  Project Name
//
//  Created by ABC on 2/3/18.
//  Copyright © 2018 ABC. All rights reserved.
//

import UIKit

extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tapGesture = UITapGestureRecognizer(target: self, 
                         action: #selector(hideKeyboard))
        view.addGestureRecognizer(tapGesture)
    }

    @objc func hideKeyboard() {
        view.endEditing(true)
    }
}

O mais importante é chamar o seu Controlador de exibição de base, para que você não precise ligar o tempo todo em todos os controladores de exibição.

Fahim Parkar
fonte
36

Você pode ligar

resignFirstResponder()

em qualquer instância de um UIResponder, como um UITextField. Se você chamá-lo na exibição que atualmente está causando a exibição do teclado, o teclado será descartado.

Traço
fonte
5
Em uma situação em que você não conhece exatamente o primeiro respondedor, resignFirstResponder () pode levar a um monte de problemas. A resposta de Esq abaixo (usando view.doneEditing ()) é muito mais apropriado
shiser
11
Sempre que uso resignFirstResponder no meu textField, o aplicativo trava. Tentei de tudo em que pude pensar e procurei na Web uma solução. Nada me ajuda. Você saberia por que isso acontece?
AugustoQ 23/09
11
Como disse a shiser, essa não é a melhor solução. além disso, não funciona em todas as situações.
Alix
21
//Simple exercise to demonstrate, assuming the view controller has a //Textfield, Button and a Label. And that the label should display the //userinputs when button clicked. And if you want the keyboard to disappear //when clicken anywhere on the screen + upon clicking Return key in the //keyboard. Dont forget to add "UITextFieldDelegate" and 
//"self.userInput.delegate = self" as below

import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

    @IBOutlet weak var userInput: UITextField!
    @IBAction func transferBtn(sender: AnyObject) {
                display.text = userInput.text

    }
    @IBOutlet weak var display: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

//This is important for the textFieldShouldReturn function, conforming to textfieldDelegate and setting it to self
        self.userInput.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

//This is for the keyboard to GO AWAYY !! when user clicks anywhere on the view
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.view.endEditing(true)
    }


//This is for the keyboard to GO AWAYY !! when user clicks "Return" key  on the keyboard

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

}
Naishta
fonte
touchesBegan trabalhou para mim para finalizar a edição do campo de texto e da visualização de texto. Obrigado
Sanju
É isso que eu uso, simples. Remova também os códigos não relacionados para se concentrar na solução.
perfil completo de John Doe
19

para Swift 3 é muito simples

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

se você deseja ocultar o teclado ao pressionar a tecla RETURN

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

mas, no segundo caso, você também precisará passar o delegado de todos os campos de texto para o ViewController no Main.Storyboard

Yerbol
fonte
Eu entendo unrecognized selector sent to instancecom esse código.
Haring10
11

Swift 3: maneira mais fácil de descartar o teclado:

  //Dismiss keyboard method
    func keyboardDismiss() {
        textField.resignFirstResponder()
    }

    //ADD Gesture Recignizer to Dismiss keyboard then view tapped
    @IBAction func viewTapped(_ sender: AnyObject) {
        keyboardDismiss()
    }

    //Dismiss keyboard using Return Key (Done) Button
    //Do not forgot to add protocol UITextFieldDelegate 
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        keyboardDismiss()

        return true
    }
NikaE
fonte
11
Tenho certeza de que a chamada view.endEditing (true) é mais simples, pois não exige que você armazene uma variável ou presuma que você tenha apenas um campo de texto.
Glenn Howes
10

A resposta de Dash é correta e preferida. Uma abordagem mais "abrasadora" é chamar view.endEditing(true). Isso causa viewe todas as suas subvisões para resignFirstResponder. Se você não tem uma referência à visualização que gostaria de descartar, esta é uma solução hacky, mas eficaz.

Observe que, pessoalmente, acho que você deve ter uma referência à exibição que gostaria de renunciar à resposta. .endEditing(force: Bool)é uma abordagem bárbara; por favor não use.

modocache
fonte
10

swift 5 apenas duas linhas é suficiente. Adicionar ao seu viewDidLoaddeve funcionar.

 let tapGesture = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing))
 view.addGestureRecognizer(tapGesture)

Se o seu gesto de toque bloquear outros toques, adicione esta linha:

tapGesture.cancelsTouchesInView = false
William Hu
fonte
Solução muito simples e elegante :), deve ser a resposta aqui.
Joseph Astrahan
9

No storyboard:

  1. selecione o TableView
  2. no lado direito, selecione o inspetor de atributos
  3. na seção do teclado - selecione o modo de dispensa desejado
zevij
fonte
não consegue encontrar esse item, onde está e como ele é? Estou no Inspetor de atributo de um textField
Ethan Parker
Você precisa olhar para o TableView não TextField
zevij
9

Swift 3:

Extensão com Selectorcomo parâmetro para poder fazer coisas adicionais na função de descartar e cancelsTouchesInViewevitar distorções com toques em outros elementos da vista.

extension UIViewController {
    func hideKeyboardOnTap(_ selector: Selector) {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: selector)
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }
}

Uso:

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardOnTap(#selector(self.dismissKeyboard))
}

func dismissKeyboard() {
    view.endEditing(true)
    // do aditional stuff
}
David Seek
fonte
9

Use o IQKeyboardmanager que o ajudará a resolver problemas fáceis .....

///////////////////////////////////////////

! [como desativar o teclado ..] [1]

import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

   @IBOutlet weak var username: UITextField!
   @IBOutlet weak var password: UITextField!

   override func viewDidLoad() {
      super.viewDidLoad() 
      username.delegate = self
      password.delegate = self
      // Do any additional setup after loading the view, typically from a nib.
   }

   override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      // Dispose of any resources that can be recreated.
   }

   func textFieldShouldReturn(textField: UITextField!) -> Bool // called when   'return' key pressed. return NO to ignore.
   {
      textField.resignFirstResponder()
      return true;
   }

   override func touchesBegan(_: Set<UITouch>, with: UIEvent?) {
     username.resignFirstResponder()
     password.resignFirstResponder()
     self.view.endEditing(true)
  }
}
Hardik Bar
fonte
8

Encontrei que a melhor solução incluía a resposta aceita do @Esqarrouth, com alguns ajustes:

extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboardView")
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }

    func dismissKeyboardView() {
        view.endEditing(true)
    }
}

A linha tap.cancelsTouchesInView = falseera crítica: assegura que UITapGestureRecognizernão impeça que outros elementos na exibição recebam interação do usuário.

O método dismissKeyboard()foi alterado para um pouco menos elegante dismissKeyboardView(). Isso ocorre porque na base de código bastante antiga do meu projeto, houve várias vezes em que dismissKeyboard()já foi usada (acho que isso não é incomum), causando problemas no compilador.

Então, como acima, esse comportamento pode ser ativado em Controladores de exibição individuais:

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardWhenTappedAround() 
}
Luke Harries
fonte
7

Se você usar uma exibição de rolagem, poderá ser muito mais simples.

Basta selecionar Dismiss interactivelyno storyboard.

JIE WANG
fonte
7

No Swift 4, adicione @objc:

No viewDidLoad:

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

Função:

@objc func dismissKeyboard() {
  view.endEditing(true)
}
user3856297
fonte
7

Adicione esta extensão ao seu ViewController:

  extension UIViewController {
// Ends editing view when touches to view 
  open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    self.view.endEditing(true)
  }
}
Jarvis The Avenger
fonte
6

Para expandir a resposta de Esqarrouth , eu sempre uso o seguinte para descartar o teclado, especialmente se a classe da qual estou descartando o teclado não possui uma viewpropriedade e / ou não é uma subclasse deUIView .

UIApplication.shared.keyWindow?.endEditing(true)

E, por conveniência, a seguinte extensão da UIApplcationclasse:

extension UIApplication {

    /// Dismisses the keyboard from the key window of the
    /// shared application instance.
    ///
    /// - Parameters:
    ///     - force: specify `true` to force first responder to resign.
    open class func endEditing(_ force: Bool = false) {
        shared.endEditing(force)
    }

    /// Dismisses the keyboard from the key window of this 
    /// application instance.
    ///
    /// - Parameters:
    ///     - force: specify `true` to force first responder to resign.
    open func endEditing(_ force: Bool = false) {
        keyWindow?.endEditing(force)
    }

}
NoodleOfDeath
fonte
5
  import UIKit

  class ItemViewController: UIViewController, UITextFieldDelegate {

  @IBOutlet weak var nameTextField: UITextField!

    override func viewDidLoad() {
           super.viewDidLoad()
           self.nameTextField.delegate = self
     }

    // Called when 'return' key pressed. return NO to ignore.

    func textFieldShouldReturn(textField: UITextField) -> Bool {

            textField.resignFirstResponder()
             return true
     }

 // Called when the user click on the view (outside the UITextField).

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)    {
      self.view.endEditing(true)
  }
}
Prashant chaudhary
fonte
5

Como programador iniciante, pode ser confuso quando as pessoas produzem respostas mais hábeis e desnecessárias ... Você não precisa fazer nada do complicado mostrado acima! ...

Aqui está a opção mais simples ... Caso o teclado apareça em resposta ao campo de texto - Dentro da função da tela de toque, adicione a função resignFirstResponder . Como mostrado abaixo - o teclado será fechado porque o Primeiro Respondente for liberado (saindo da cadeia do Respondente) ...

override func touchesBegan(_: Set<UITouch>, with: UIEvent?){
    MyTextField.resignFirstResponder()
}
Céu vermelho
fonte
5

Eu uso IQKeyBoardManagerSwift para teclado. É fácil de usar. basta adicionar o pod 'IQKeyboardManagerSwift'

Importe IQKeyboardManagerSwift e escreva o código didFinishLaunchingWithOptionsem AppDelegate.

///add this line 
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
IQKeyboardManager.shared.enable = true
Sukhwinder Singh
fonte
4

Este liner renuncia o teclado de todos (qualquer) o UITextField em um UIView

self.view.endEditing(true)
Codetard
fonte
4

Apenas uma linha de código no viewDidLoad()método:

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

Em rápido você pode usar

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

}
Bernard Rayoso
fonte
3

Para Swift3

Registrar um reconhecedor de eventos em viewDidLoad

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

precisamos adicionar o gesto na visualização no mesmo viewDidLoad.

self.view.addGestureRecognizer(tap)

Então precisamos inicializar o método registrado

func hideKeyBoard(sender: UITapGestureRecognizer? = nil){
    view.endEditing(true)
}
Sandu
fonte
11
Obrigado pela resposta completa e com notas. Esta é a única solução que funcionou para mim.
23418 zeeshan
3

A postagem como uma nova resposta desde que minha edição da resposta de @ King-Wizard foi rejeitada.

Faça da sua turma um delegado do UITextField e substitua o touchesBegan.

Swift 4

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        textField.delegate = self
    }

    //Called when 'return' key is pressed. Return false to keep the keyboard visible.
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        return true
    }

    // Called when the user clicks on the view (outside of UITextField).
    override func touchesBegan(touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

}
Viktor Seč
fonte
2

Você também pode adicionar um reconhecedor de gesto de toque para renunciar ao teclado. : D

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let recognizer = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
    backgroundView.addGestureRecognizer(recognizer)
}
    func handleTap(recognizer: UITapGestureRecognizer) {
    textField.resignFirstResponder()
    textFieldtwo.resignFirstResponder()
    textFieldthree.resignFirstResponder()

    println("tappped")
}
Codetard
fonte
2

Outra possibilidade é simplesmente adicionar um botão grande sem conteúdo que esteja abaixo de todas as visualizações que você possa precisar tocar. Dê a ele uma ação chamada:

@IBAction func dismissKeyboardButton(sender: AnyObject) {
    view.endEditing(true)
}

O problema com um reconhecedor de gestos era para mim, que também captou todos os toques que eu queria receber pelo tableViewCells.

Timm Kent
fonte
2

Se você tiver outras visualizações que também receberão o toque, precisará definir cancelsTouchesInView = false

Como isso:

let elsewhereTap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    elsewhereTap.cancelsTouchesInView = false
    self.view.addGestureRecognizer(elsewhereTap)
ph1lb4
fonte
2
override func viewDidLoad() {
        super.viewDidLoad()

self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap)))

}

func tap(sender: UITapGestureRecognizer){
        print("tapped")
        view.endEditing(true)
}

Tente isso, está funcionando

Ramprasath Selvam
fonte
1

Quando houver mais de um campo de texto na exibição

Para seguir a recomendação do @ modocache para evitar chamadasview.endEditing() , você pode acompanhar o campo de texto que se tornou o primeiro respondedor, mas isso é confuso e propenso a erros.

Uma alternativa é chamar resignFirstResponder() todos os campos de texto no controlador de exibição . Aqui está um exemplo de criação de uma coleção de todos os campos de texto (que, no meu caso, eram necessários para o código de validação):

@IBOutlet weak var firstName: UITextField!
@IBOutlet weak var lastName: UITextField!
@IBOutlet weak var email: UITextField!

var allTextFields: Array<UITextField>!  // Forced unwrapping so it must be initialized in viewDidLoad
override func viewDidLoad()
{
    super.viewDidLoad()
    self.allTextFields = [self.firstName, self.lastName, self.email]
}

Com a coleção disponível, é simples iterar por todos eles:

private func dismissKeyboard()
{
    for textField in allTextFields
    {
        textField.resignFirstResponder()
    }
}

Agora você pode chamar dismissKeyboard()seu reconhecedor de gestos (ou onde for apropriado). A desvantagem é que você deve manter a lista de UITextFields ao adicionar ou remover campos.

Comentários bem-vindos. Se houver um problema ao chamar os resignFirstResponder()controles que não são os primeiros a responder, ou se houver uma maneira fácil e garantida, sem bugs, de rastrear o atual primeiro respondedor, eu adoraria ouvir sobre isso!

pedra
fonte