How to move View with Keyboard in iOS using Swift

Last updated on: May 27, 2023

In today’s tutorial, we will learn how to make a view animate when the keyboard appears or disappears.

It can be any kind of view: a UITextField, a UIButton; it doesn’t matter.

Creating the UI

In this example, we have a login screen with a UITextField for the username and password.

At the bottom, we have a UIButton that we want to move up/down when the keyboard appears/disappears.

A login screen with a login button at the bottom to show how to move it when the keyboard appears

To do that, we set an IBOutlet of the bottom constraint of this UIButton

The bottom constraint of the login button

We select the bottom constraint in our storyboard and then we ctrl + drag n drop that constraint over to our Swift file and give it the name loginButtonBottomConstraint and press Connect

Setting the IBOutlet of the bottom constraint of the login button

Making View move with the Keyboard

To detect when the keyboard starts to appear or disappear, we add two notifications to our view.

class ViewController: UIViewController {
    @IBOutlet var usernameTextField: UITextField!
    @IBOutlet var passwordTextField: UITextField!
    @IBOutlet var loginButton: UIButton!
    @IBOutlet var loginButtonBottomConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Notifications for when the keyboard opens/closes
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.keyboardWillShow),
            name: UIResponder.keyboardWillShowNotification,
            object: nil)

        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.keyboardWillHide),
            name: UIResponder.keyboardWillHideNotification,
            object: nil)
    }
    
    @objc func keyboardWillShow(_ notification: NSNotification) {
         // Add code later...
    }
    
    @objc func keyboardWillHide(_ notification: NSNotification) {
         // Add code later...
    }
}Code language: Swift (swift)

We then create a new method called moveViewWithKeyboard, which takes a NSNotification parameter and the bottom constraint of the view we want to change. We also pass in a Boolean value to know if we have to move the view up or down.

func moveViewWithKeyboard(notification: NSNotification, viewBottomConstraint: NSLayoutConstraint, keyboardWillShow: Bool) {
    // Add code later...
}Code language: Swift (swift)

Inside this method, we get the keyboard height so that we can move the view above the keyboard when it appears.

func moveViewWithKeyboard(notification: NSNotification, viewBottomConstraint: NSLayoutConstraint, keyboardWillShow: Bool) {
    // Keyboard's size
    guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
    let keyboardHeight = keyboardSize.height
     
    // ...
}Code language: Swift (swift)

Next, we get the keyboard’s duration and curve animation.

This will make the view move the same way as the keyboard, creating a nice smooth synchronized animation.

func moveViewWithKeyboard(notification: NSNotification, viewBottomConstraint: NSLayoutConstraint, keyboardWillShow: Bool) {

    // ...
    
    // Keyboard's animation duration
    let keyboardDuration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double
    
    // Keyboard's animation curve
    let keyboardCurve = UIView.AnimationCurve(rawValue: notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! Int)!
    
    // ...
}Code language: Swift (swift)

Then, we set the bottom constraint. If the keyboard is going to appear, we use the keyboard height + 20 (the bottom constraint). When the keyboard is going to disappears, we set the constraint back to 20.

We also check if the safe area exists. If the safeAresInsets bottom equals 0, the device doesn’t have safe areas (devices without the notch, like iPhone 8).

This allows us to set the correct bottom constraint of the view we’re moving.

func moveViewWithKeyboard(notification: NSNotification, viewBottomConstraint: NSLayoutConstraint, keyboardWillShow: Bool) {

    // ...
    
    // Change the constant
    if keyboardWillShow {
        let safeAreaExists = (self.view?.window?.safeAreaInsets.bottom != 0) // Check if safe area exists
        let bottomConstant: CGFloat = 20
        viewBottomConstraint.constant = keyboardHeight + (safeAreaExists ? 0 : bottomConstant)
    }else {
        viewBottomConstraint.constant = 20
    }
    
    // ...
}Code language: Swift (swift)

Finally, using the duration and the curve of the keyboard, we create a UIViewPropertyAnimator to update the view’s bottom constraint with animation.

func moveViewWithKeyboard(notification: NSNotification, viewBottomConstraint: NSLayoutConstraint, keyboardWillShow: Bool) {

    // ...
    
    // Animate the view the same way the keyboard animates
    let animator = UIViewPropertyAnimator(duration: keyboardDuration, curve: keyboardCurve) { [weak self] in
        // Update Constraints
        self?.view.layoutIfNeeded()
    }
    
    // Perform the animation
    animator.startAnimation()
}Code language: Swift (swift)

Now, we go back to the keyboardWillShow method we created before, and we call the moveViewWithKeyboard method only when the usernameTextField or passwordTextField is edited.

This prevents moving the view when another view sits on top of this UIViewController.

For instance, if you have a “Lost your password?” screen that shows a popup window with a text field for users to enter their email address to reset their password, you don’t want to see the “Login” button move when the keyboard appears/disappears for the email text field.

@objc func keyboardWillShow(_ notification: NSNotification) {
    // Move the view only when the usernameTextField or the passwordTextField are being edited
    if usernameTextField.isEditing || passwordTextField.isEditing {
        moveViewWithKeyboard(notification: notification, viewBottomConstraint: self.loginButtonBottomConstraint, keyboardWillShow: true)
    }
}Code language: Swift (swift)

We do the same in the keyboardWillHide and we set the parameter keyboardWillShow to false.

@objc func keyboardWillHide(_ notification: NSNotification) {
    moveViewWithKeyboard(notification: notification, viewBottomConstraint: self.loginButtonBottomConstraint, keyboardWillShow: false)
}Code language: Swift (swift)

So, in the end, will look like this:

class ViewController: UIViewController {
    @IBOutlet var usernameTextField: UITextField!
    @IBOutlet var passwordTextField: UITextField!
    @IBOutlet var loginButton: UIButton!
    @IBOutlet var loginButtonBottomConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Notifications for when the keyboard opens/closes
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.keyboardWillShow),
            name: UIResponder.keyboardWillShowNotification,
            object: nil)

        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.keyboardWillHide),
            name: UIResponder.keyboardWillHideNotification,
            object: nil)
    }
    
    @objc func keyboardWillShow(_ notification: NSNotification) {
        // Move the view only when the usernameTextField or the passwordTextField are being edited
        if usernameTextField.isEditing || passwordTextField.isEditing {
            moveViewWithKeyboard(notification: notification, viewBottomConstraint: self.loginButtonBottomConstraint, keyboardWillShow: true)
        }
    }
    
    @objc func keyboardWillHide(_ notification: NSNotification) {
        moveViewWithKeyboard(notification: notification, viewBottomConstraint: self.loginButtonBottomConstraint, keyboardWillShow: false)
    }
    
    func moveViewWithKeyboard(notification: NSNotification, viewBottomConstraint: NSLayoutConstraint, keyboardWillShow: Bool) {
        // Keyboard's size
        guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
        let keyboardHeight = keyboardSize.height
        
        // Keyboard's animation duration
        let keyboardDuration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double
        
        // Keyboard's animation curve
        let keyboardCurve = UIView.AnimationCurve(rawValue: notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! Int)!
        
        // Change the constant
        if keyboardWillShow {
            let safeAreaExists = (self.view?.window?.safeAreaInsets.bottom != 0) // Check if safe area exists
            let bottomConstant: CGFloat = 20
            viewBottomConstraint.constant = keyboardHeight + (safeAreaExists ? 0 : bottomConstant)
        }else {
            viewBottomConstraint.constant = 20
        }
        
        // Animate the view the same way the keyboard animates
        let animator = UIViewPropertyAnimator(duration: keyboardDuration, curve: keyboardCurve) { [weak self] in
            // Update Constraints
            self?.view.layoutIfNeeded()
        }
        
        // Perform the animation
        animator.startAnimation()
    }
}Code language: Swift (swift)
You can find the final project here

If you have any questionsplease feel free to leave a comment below

Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments