lagoon
lagoon

Reputation: 6537

Close iOS Keyboard by touching anywhere using Swift

I have been looking all over for this but I can't seem to find it. I know how to dismiss the keyboard using Objective-C but I have no idea how to do that using Swift? Does anyone know?

Upvotes: 510

Views: 519665

Answers (30)

IAmNoob
IAmNoob

Reputation: 641

    //Below function hides the keyboard when we click outside the textBox
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true)
        super.touchesBegan(touches, with: event)
    }

You can put this code in your ViewController and it will let you dismiss the keyboard by touching anywhere outside the textfield.

Upvotes: 1

Raimundas Sakalauskas
Raimundas Sakalauskas

Reputation: 2294

I am surprised, that none of the answers cover all edge cases. Possible edge cases in 2023:

  1. User tries to swipe scrollview, tableview or modal view
  2. User wants to exclude certain views from dismissing the keyboard
  3. User taps on navigation bar (it's outside of view bounds so tap gesture wouldn't trigger there)

Why UITapGesture's action is bad for this? UITapGestureRecognizer only calls its action if it triggers and it doesn't trigger if touch moves. So if you have a scrollview, or tableview, or interactive modal view and user tries to scroll/interact with them, the keyboard will fail to be dismissed. Furthermore, if you add gesture recognizer to your view controller, tapping navbar will fail to trigger the action as its outside of view's bounds. Lastly, there edge case where tap gesture doesn't work at all - swipe initiated from the cell that should not dismiss the keyboard (but the scroll should do it).

So we have established that we can't rely on UITapGestureRecognizer action, but what can we use instead? The UIPanGesture and its delegate.

To make the gesture recognizer transparent it needs to be defined with the following properties. This way it won't interfere with any other interactions. Put this code in your ViewController:

class MyViewController: UIViewController {
    lazy var tapOutsideGestureRecognizer: UIPanGestureRecognizer = {
        let control = UIPanGestureRecognizer(target: self, action: #selector(detectSwipe))
        control.cancelsTouchesInView = false
        control.delaysTouchesBegan = false
        control.delaysTouchesEnded = false

        control.delegate = self

        return control
    }()

    // This will be used to handle one edge case
    var viewOrigin: CGPoint?

    ...
}

Then we use the delegate to cancel any touches that begin outside the list of excluded view, but trigger our code instead. Put this anywhere, but its best to keep in your ViewController.swift file.

extension MyViewController: UIGestureRecognizerDelegate {
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        // We capture origin of the view, to detect swipe/scroll anywhere in the display tree
        viewOrigin = view.convert(view.bounds.origin, to: nil)
        return endEditingIfNeeded(touch: touch)
    }

    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

In the code that triggers when user taps anywhere, we want to exclude some views from dismissing the keyboard. Put this code in your ViewController:

extension MyViewController {
    @objc func detectSwipe(sender: UIPanGestureRecognizer) {
        guard sender.state == .changed, let viewOrigin else { return }
        let newOrigin = view.convert(view.bounds.origin, to: nil)

        if abs(newOrigin.y - viewOrigin.y) > 1 || abs(newOrigin.x - viewOrigin.x) > 1 {
            tappedOutside()
        }
    }

    @objc func endEditingIfNeeded(touch: UITouch) -> Bool {
        // Array of views that shouldn't dismiss the keyboard
        let exclude = [view.pickerContainerView, view.inputTextField]
        for target in exclude {
            // If tap origin is within excluded view, don't dismiss the keyboard
            if target.bounds.contains(touch.location(in: target)) {
                return true
            }
        }

        // If tap originates in a view different than exclusion list, dismiss the keyboard or perform some other action
        tappedOutside()
        return false
    }

    func tappedOutside() {
        // This line is optional and only should be used if you decide to add gesture recognizer to navigation controller (see explanation at the bottom of this answer)
        // navigationController?.view.removeGestureRecognizer(tapOutsideGestureRecognizer)
   }

There are two options to add this gesture recognizer:

  1. Add to your view by calling view.addGestureRecognizer(tapOutsideGestureRecognizer). It will work anywhere in the view, but if the view is presented in navigation controller, tapping navbar wouldn't trigger the code.
  2. Add it to navigation view controller (or it could for example be tabbar controller), by calling navigationController?.view.addGestureRecognizer(tapOutsideGestureRecognizer). If you go this route, you must remove gesture recognizer endEditingIfNeeded to prevent it from outliving the view. Last but not least. If you want to cover whole screen, not just the view area,

Upvotes: 0

rollingcodes
rollingcodes

Reputation: 16072

To expand on Esqarrouth's answer, I always use the following to dismiss the keyboard, especially if the class from which I am dismissing the keyboard does not have a view property and/or is not a subclass of UIView.

UIApplication.shared.keyWindow?.endEditing(true)

Or, for convenience,

UIApplication.endEditing(true)

with the following extension to the UIApplication class:

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

}

Upvotes: 14

Chithian
Chithian

Reputation: 349

how to dismiss keyboard when you click anywhere to close it

 //Setup dismiss keyboard gesture
 let tap = UITapGestureRecognizer(target: self, action: #selector(UIInputViewController.dismissKeyboard))

     view.addGestureRecognizer(tap)
 }
 //Calling this function when the tapped
 @objc func dismissKeyboard() {

    view.endEditing(true)
 }

Upvotes: 4

iOS_Mouse
iOS_Mouse

Reputation: 844

I haven't seen it mentioned, but NotificationCenter can tell you when the keyboard opens and closes. For example, this can be used if you want to change cancelsTouchesInView or remove the gesture recognizer all together.

Example:

var dismissKeyboardGestureRecognizer = UITapGestureRecognizer()

override func viewDidLoad() {
    super.viewDidLoad()

    //Setup dismiss keyboard gesture
    self.dismissKeyboardGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))

    //Add Notifications
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name:UIResponder.keyboardDidShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidHide), name:UIResponder.keyboardDidHideNotification, object: nil)
}

@objc func keyboardDidShow() {
    dismissKeyboardGestureRecognizer.cancelsTouchesInView = true
    view.addGestureRecognizer(dismissKeyboardGestureRecognizer)
}

@objc func keyboardDidHide() {
    dismissKeyboardGestureRecognizer.cancelsTouchesInView = false
    view.removeGestureRecognizer(dismissKeyboardGestureRecognizer)
}

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

Upvotes: 1

anusha.V
anusha.V

Reputation: 81

If you want to dissmiss the keyboard, when you want go to the next button action or anyplace.

you can simply add the below line, Replace the textfield name of yours.

billTextField.endEditing(true) or billTextField.resignFirstResponder()

Upvotes: 0

Artem
Artem

Reputation: 411

Just one line of code in viewDidLoad() method:

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

Upvotes: 13

Esqarrouth
Esqarrouth

Reputation: 39201

override func viewDidLoad() {
    super.viewDidLoad()
          
    //Looks for single or multiple taps. 
     let tap = UITapGestureRecognizer(target: self, action: #selector(UIInputViewController.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)
}

Here is another way to do this task if you are going to use this functionality in multiple UIViewControllers:

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

Now in every UIViewController, all you have to do is call this function:

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

This function is included as a standard function in my repo which contains a lot of useful Swift Extensions like this one, check it out: https://github.com/goktugyil/EZSwiftExtensions

Upvotes: 1513

Joshua Dance
Joshua Dance

Reputation: 10532

Here is how to dismiss the keyboard by tapping anywhere else, in 2 lines using Swift 5.

(I hate to add another answer, but since this is the top result on Google I will to help rookies like me.)

In your ViewController.swift, find the viewDidLoad() function.

Add these 2 lines:

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

Upvotes: 3

bernard rayoso
bernard rayoso

Reputation: 153

In swift you can use

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

}

Upvotes: 13

James Bissick
James Bissick

Reputation: 105

A simple way to do this is by selecting the text field and using the method endEditing(true)

e.g

exampleTextField.endEditing(true)

Upvotes: 0

Brandon Erbschloe
Brandon Erbschloe

Reputation: 418

Able to achieve this by adding a global tap gesture recognizer to the window property in the AppDelegate.

This was a very catch all approach and might not be the desired solution for some but it worked for me. Please let me know if there any pitfalls to this solution.

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // Globally dismiss the keyboard when the "background" is tapped.
        window?.addGestureRecognizer(
            UITapGestureRecognizer(
              target: window, 
              action: #selector(UIWindow.endEditing(_:))
            )
        )

        return true
    }
}

Upvotes: 1

Fahim Parkar
Fahim Parkar

Reputation: 31647

Swift 4 working

Create extension as below & call hideKeyboardWhenTappedAround() in your Base view controller.

//
//  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)
    }
}

Most important thing to call in your Base View Controller so that no need to call all time in all view controllers.

Upvotes: 63

Hardik Bar
Hardik Bar

Reputation: 1760

Use IQKeyboardmanager that will help you solve easy.....

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

![ how to disable the keyboard..][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)
  }
}

Upvotes: 9

Viktor Sec
Viktor Sec

Reputation: 3085

Posting as a new answer since my edit of @King-Wizard's answer was rejected.

Make your class a delegate of the UITextField and override 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)
    }

}

Upvotes: 4

William Hu
William Hu

Reputation: 16189

swift 5 just two lines is enough. Add into your viewDidLoad should work.

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

If your tap gesture blocked some other touches, then add this line:

tapGesture.cancelsTouchesInView = false

Upvotes: 34

Sukh
Sukh

Reputation: 1408

I have use IQKeyBoardManagerSwift for keyboard. it is easy to use. just Add pod 'IQKeyboardManagerSwift'

Import IQKeyboardManagerSwift and write code on didFinishLaunchingWithOptions in AppDelegate.

///add this line 
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
IQKeyboardManager.shared.enable = true

Upvotes: 11

Rahul Umap
Rahul Umap

Reputation: 2869

Add this extension to your 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)
  }
}

Upvotes: 9

user3856297
user3856297

Reputation: 283

In Swift 4, add @objc:

In the viewDidLoad:

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

Function:

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

Upvotes: 7

Ramprasath Selvam
Ramprasath Selvam

Reputation: 4466

override func viewDidLoad() {
        super.viewDidLoad()

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

}

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

Try this,It's Working

Upvotes: 2

user3711263
user3711263

Reputation: 69

Swift 3

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

Upvotes: 1

Sandu
Sandu

Reputation: 516

For Swift3

Register an event recogniser in viewDidLoad

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

then we need to add the gesture into the view in same viewDidLoad.

self.view.addGestureRecognizer(tap)

Then we need to initialise the registered method

func hideKeyBoard(sender: UITapGestureRecognizer? = nil){
    view.endEditing(true)
}

Upvotes: 3

Sam
Sam

Reputation: 59

Here's a succinct way of doing it:

let endEditingTapGesture = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:)))
endEditingTapGesture.cancelsTouchesInView = false
view.addGestureRecognizer(endEditingTapGesture)

Upvotes: 2

Atka
Atka

Reputation: 547

I found this simple solution: 1. Add UITapGestureRecognizer to your view Controller 2. Add IBAction to your UITapGestureRecognizer 3. Finally you can resign the first responder

class ViewController: UIViewController
{

@IBOutlet var tap: UITapGestureRecognizer!
@IBOutlet weak var label: UILabel!
@IBOutlet weak var textField: UITextField!
override func viewDidLoad()
{
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}


@IBAction func dismissUsingGesture(_ sender: UITapGestureRecognizer)
{
   self.textField.resignFirstResponder()
    label.text = textField.text!
}
}

Upvotes: 1

JIE WANG
JIE WANG

Reputation: 1934

If you use a scroll view, It could be much simpler.

Just select Dismiss interactively in storyboard.

Upvotes: 8

RedSky
RedSky

Reputation: 71

As a novice programmer it can be confusing when people produce more skilled and unnecessary responses...You do not have to do any of the complicated stuff shown above!...

Here is the simplest option...In the case your keyboard appears in response to the textfield - Inside your touch screen function just add the resignFirstResponder function. As shown below - the keyboard will close because the First Responder is released (exiting the Responder chain)...

override func touchesBegan(_: Set<UITouch>, with: UIEvent?){
    MyTextField.resignFirstResponder()
}

Upvotes: 6

Yerbol
Yerbol

Reputation: 405

for Swift 3 it is very simple

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

if you want to hide keyboard on pressing RETURN key

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

but in second case you will also need to pass delegate from all textFields to the ViewController in the Main.Storyboard

Upvotes: 24

NikaE
NikaE

Reputation: 624

Swift 3: Easiest way to dismiss keyboard:

  //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
    }

Upvotes: 13

David Seek
David Seek

Reputation: 17152

Swift 3:

Extension with Selector as parameter to be able to do additional stuff in the dismiss function and cancelsTouchesInView to prevent distortion with touches on other elements of the view.

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

Usage:

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

func dismissKeyboard() {
    view.endEditing(true)
    // do aditional stuff
}

Upvotes: 10

ph1lb4
ph1lb4

Reputation: 2132

If you have other views that should receive the touch as well you have to set cancelsTouchesInView = false

Like this:

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

Upvotes: 2

Related Questions