How to make UITextField move up when keyboard is present?

Swift 4 code, It is very simple instead of using many things like NSNotificationCenter, then calculating the height of everything and making conditions makes this more complicated,

The Simple way to do this is coded below, it will work to move up the view.

func textFieldDidBeginEditing(_ textField: UITextField) {
        moveTextField(textfield: textField, moveDistance: -250, up: true)
}

func textFieldDidEndEditing(_ textField: UITextField) {
        moveTextField(textfield: textField, moveDistance: -250, up: false)
}

func moveTextField(textfield: UITextField, moveDistance: Int, up: Bool) {
    let moveDuration = 0.3
    let movement: CGFloat = CGFloat(up ? moveDistance: -moveDistance)
    UIView.beginAnimations("animateTextField", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(moveDuration)
    self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
    UIView.commitAnimations()
}

you can change that -250 value according to the placement of your textfields.


Here is the simple solution in Swift. I translated some Objective-C code that worked for me in the past.

func textFieldDidBeginEditing(textField: UITextField) { // became first responder

    //move textfields up
    let myScreenRect: CGRect = UIScreen.mainScreen().bounds
    let keyboardHeight : CGFloat = 216

    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:NSTimeInterval = 0.35
    var needToMove: CGFloat = 0

    var frame : CGRect = self.view.frame
    if (textField.frame.origin.y + textField.frame.size.height + /*self.navigationController.navigationBar.frame.size.height + */UIApplication.sharedApplication().statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight)) {
    needToMove = (textField.frame.origin.y + textField.frame.size.height + /*self.navigationController.navigationBar.frame.size.height +*/ UIApplication.sharedApplication().statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight);
    }

    frame.origin.y = -needToMove
    self.view.frame = frame
    UIView.commitAnimations()
}

func textFieldDidEndEditing(textField: UITextField) {
        //move textfields back down
        UIView.beginAnimations( "animateView", context: nil)
        var movementDuration:NSTimeInterval = 0.35
        var frame : CGRect = self.view.frame
        frame.origin.y = 0
        self.view.frame = frame
        UIView.commitAnimations()
}

In case you are using a UIScrollView or any of its subclasses, e.g., UITableView, you can also manipulate the contentInset property. That way you do not have to mess with frame, bounds, NSLayoutConstraint or NSLayoutAnchor.

func keyboardWillShow(notification: Notification) {
    let info = notification.userInfo!
    let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    let keyboardHeight: CGFloat = keyboardSize.height
    let duration = info[UIKeyboardAnimationDurationUserInfoKey] as! TimeInterval
    UIView.animate(withDuration: duration, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
        self.tableView?.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0)
    }, completion: nil)
}

func keyboardWillHide(notification: Notification) {
    let info = notification.userInfo!
    let duration = info[UIKeyboardAnimationDurationUserInfoKey] as! TimeInterval
    UIView.animate(withDuration: duration, delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
        self.tableView?.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }, completion: nil)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

I assume this is happening on a UIViewController. If so, you can setup the following two functions to be called when the keyboard will show/hide, and respond appropriately in their blocks.

Setting up the UIViewController:

class ViewController: UIViewController, UITextFieldDelegate... {

    var frameView: UIView!

First, in viewDidLoad():

override func viewDidLoad() {

    self.frameView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height))

    // Keyboard stuff.
    let center: NotificationCenter = NotificationCenter.default
    center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
    center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)

}

Then implement the following two functions to respond to your NotificationCenter functions defined in viewDidLoad() above. I give you an example of moving the entire view, but you can also animate just the UITextFields.

@objc func keyboardWillShow(notification: NSNotification) {
    let info:NSDictionary = notification.userInfo! as NSDictionary
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue

    let keyboardHeight: CGFloat = keyboardSize.height

    let _: CGFloat = info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber as! CGFloat


    UIView.animate(withDuration: 0.25, delay: 0.25, options: .curveEaseInOut, animations: {
        self.frameView.frame = CGRect(x: 0, y: (self.frameView.frame.origin.y - keyboardHeight), width: self.view.bounds.width, height: self.view.bounds.height)
    }, completion: nil)
}

@objc func keyboardWillHide(notification: NSNotification) {
    let info: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue

    let keyboardHeight: CGFloat = keyboardSize.height

    let _: CGFloat = info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber as! CGFloat

    UIView.animate(withDuration: 0.25, delay: 0.25, options: .curveEaseInOut, animations: {
        self.frameView.frame = CGRect(x: 0, y: (self.frameView.frame.origin.y + keyboardHeight), width: self.view.bounds.width, height: self.view.bounds.height)
    }, completion: nil)

}

Don't forget to remove the notifications when leaving your view

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}

Tags:

Ios

Swift