Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Toolbar above keyboard doesn't hide when keyboard hides

I've added a toolbar above keyboard to show Done button to dismiss keyboard. I've added it on my login screen. When keyboard is showing and I tap on saved Password icon to select saved password, keyboard hides but toolbar doesn't hide. Toolbar sits at the bottom of screen and then moves up with keyboard when keyboard shows again. It looks bad.

How do I fix it so that Toolbar doesn't show on it's own and shows/hide only with keyboard?

override func viewDidLoad() {
    super.viewDidLoad()
    self.emailTextField.addDoneButton(title: "Done", target: self, selector: #selector(tapDone(sender:)))
    self.passwordTextField.addDoneButton(title: "Done", target: self, selector: #selector(tapDone(sender:)))
}

@objc func tapDone(sender: Any) {
    self.view.endEditing(true)
}

extension UITextField {
    
    // Add done button above keyboard
    func addDoneButton(title: String, target: Any, selector: Selector) {
        let toolBar = UIToolbar(frame: CGRect(origin: .zero, size: CGSize(width: UIScreen.main.bounds.size.width, height: 44.0)))
        
        let flexible = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let barButton = UIBarButtonItem(title: title, style: .plain, target: target, action: selector)
        barButton.setTitleTextAttributes([NSAttributedString.Key.font : UIFont.main, NSAttributedString.Key.foregroundColor : UIColor.red], for: [])
        toolBar.setItems([flexible, barButton], animated: false)
        self.inputAccessoryView = toolBar
    }
}
like image 879
Raymond Avatar asked Nov 15 '22 09:11

Raymond


1 Answers

I personally handle this in a different way as I'm not using any toolbar but custom views above the keyboard. As I want those views to animate and appear/disappear depending on the keyboard position, I first listen to keyboard changes:

NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

And then handle the keyboard current size and position manually here like so:

func keyboardChanged(_ userInfo: Dictionary<AnyHashable, Any>?) {
    if let userInfo = userInfo {
        let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let duration:TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
        if (endFrame?.origin.y)! >= UIScreen.main.bounds.size.height {
            // keyboard is masked, you can mask/move your toolbar here
        } else {
            // update your toolbar visibility and/or position/constraints here using 'endFrame?.size.height'
        }

        // animate your toolbar or any other view here:
        UIView.animate(withDuration: duration,
                delay: TimeInterval(0),
                options: animationCurve,
                animations: {
                     // animate what you need here
                     self.view.layoutIfNeeded()
                },
                completion: nil)
    }
}

So in your case I would create the toolbar first and constraint it to the bottom of the screen. Then I would use the code above to handle its position and visibility.

Then, whenever the keyboard position is updated, you can handle the toolbar (position and visibility) in the keyboard notification handler shown above.

like image 96
mxlhz Avatar answered Dec 06 '22 23:12

mxlhz