Bob Stone
Bob Stone

Reputation: 100

How to exit keyboard on tap outside of uitextfield or button

I need to be able to tap out of the keyboard when not tapping in uitextfield or when not tapping show/hide password button.

I was previously using this code to do that:

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

But the problem with that was that it clicks out of the keyboard even when clicking the show/hide password eye icon. The code I'm using for the show/hide icon is this:

extension UITextField {
    func showhidepasswordbutton(image: UIImage = UIImage(systemName: "eye.slash")!) {
        let button = UIButton(type: .custom)
        button.setImage(image, for: .normal)
        button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -16, bottom: 0, right: 0)
        button.frame = CGRect(x: CGFloat(self.frame.size.width - 25), y: CGFloat(5), width: CGFloat(25), height: CGFloat(25))
        button.addTarget(self, action: #selector(self.refreshforshowhide), for: .touchUpInside)
        button.tintColor = .darkGray
        self.rightView = button
        self.rightViewMode = .always
        
        
    }
    
    @IBAction func refreshforshowhide(_ sender: Any) {
        print("ok")
        
        if self.isSecureTextEntry == true {
            self.togglePasswordVisibility()
            showhidepasswordbutton(image: UIImage(systemName: "eye")!)
            
        } else if self.isSecureTextEntry == false {
            self.togglePasswordVisibility()
            showhidepasswordbutton(image: UIImage(systemName: "eye.slash")!)
            
        }
        
    }
    func togglePasswordVisibility() {
        let temptext = self.text
        isSecureTextEntry.toggle()
        self.text = ""
        self.text = temptext
        
    }
    
}

Sorry for the messy code, just wrote the show/hide password code up.

Upvotes: 0

Views: 102

Answers (1)

Frankenstein
Frankenstein

Reputation: 16341

You could exclude the taps on subviews using gestureRecognizer(_:, shouldReceive:) method in UIGestureRecognizerDelegate.

extension UIViewController: UIGestureRecognizerDelegate {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        tap.cancelsTouchesInView = false
        tap.delegate = self
        view.addGestureRecognizer(tap)
    }

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

    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        touch.view?.isDescendant(of: view) == false // will return false if touch was received by a subview
    }
}

Update: You could use touch.view == view instead of touch.view?.isDescendant(of: view) == false.

Upvotes: 1

Related Questions