SWIFT – Move to the next UITextField by hitting Return

Next UITextField by hitting Return in Swift

Trying to move to the next UITextField when having multiple text fields is a big frustration. I am saying big because there is no native solution to this issue. If you are familiar with Android development, the EditText component (which is an equivalent to UITextField) contains this feature and makes our lives much easier.

The Solution

However, I have created a solution in Swift 3 that can help you move to the next UITextField in your current and future projects. I will show you explain you now how to move to the UITextField inside a UITableView, but you can adapt it per your needs. I took UITableView as an example, as I think most of the cases will have multiple text fields loaded inside a UITableViewCell.

Keyboard Events

We will start by adding two keyboard events. One would be for detecting when the keyboard has appeared, and the other one for when the keyboard is closed. This will help us to properly adjust the UITableView offset, so the content can stay visible and not hidden below the keyboard.

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func keyboardWillShow(_ notification: NSNotification){
    let userInfo = notification.userInfo ?? [:]
    let keyboardFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    let height = keyboardFrame.height + 20
}

func keyboardWillHide(_ notification: NSNotification){
    
}

We will use keyboardWillShow() function to get the keyboard height. Then, we will adjust the table view bottom inset accordingly.

func keyboardWillShow(_ notification: NSNotification){
    let userInfo = notification.userInfo ?? [:]
    let keyboardFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    let height = keyboardFrame.height + 20
    tableView.keyboardRaised(height: height)
}

 

Also, we need to adjust the table view bottom inset when the keyboard is closed so we can keep the inset balance correct.

func keyboardWillHide(_ notification: NSNotification){
    tableView.keyboardClosed()
}

Probably, you are wondering what are the keyboardRaised() and keyboardClosed() functions. They are extensions that I have created so for easy reuse and to maintain a clean view controller. I am explaining them below.

Assign the tags

The next step will be to assign a unique tag to the text fields located in the cells. Usually, I use the indexPath.row value summed by 100. Doing this in order to avoid any conflicts, if you already have those starting values used (1,2,3,4…).

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "YourCustomCell", for: indexPath) as! YourCustomCell
    cell.setTag(tag: index)
    
    cell.nextTextField = { [weak self] (tag) in
        guard let strongSelf = self else{
            return
        }
        
        strongSelf.formTableView.nextResponder(index: tag)
    }
    return cell
}

As you can see here, we need a closure nextTextField() and a helper function created setTag() inside our custom cell. If you are wondering why I am creating a helper function, it’s because I want to keep the outlet private. Let’s see how that looks like…

import UIKit

class YourCustomCell: UITableViewCell {
    //MARK: Private Properties
    @IBOutlet fileprivate weak var inputTxt: UITextField!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    func setTag(tag: Int){
        inputTxt.tag = 100+tag
    }
}
extension YourCustomCell: UITextFieldDelegate{
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        nextTextField?(textField.tag)
        return textField.resignFirstResponder()
    }
}

Don’t forget to connect the UITextFieldDelegate from your Interface Builder before calling its methods. We are calling the closure inside the textFieldShouldReturn() delegate method, which is called upon pressing the Return button. If you are not clear why I use an extension for the delegate methods read the below post.

Find out more about Extensions.

Extension Functions

import UIKit

extension UITableView {
    
    func nextResponder(index: Int){
        var currIndex = -1
        for i in index+1..<index+100{
            if let view = self.superview?.superview?.viewWithTag(i){
                view.becomeFirstResponder()
                currIndex = i
                break
            }
        }
        
        let ind = IndexPath(row: currIndex - 100, section: 0)
        if let nextCell = self.cellForRow(at: ind){
            self.scrollRectToVisible(nextCell.frame, animated: true)
        }
    }
    
    func keyboardRaised(height: CGFloat){
        self.contentInset.bottom = height
        self.scrollIndicatorInsets.bottom = height
    }
    
    func keyboardClosed(){
        self.contentInset.bottom = 0
        self.scrollIndicatorInsets.bottom = 0
        self.scrollRectToVisible(CGRect.zero, animated: true)
    }
    
}

In the file UITableView+Extensions.swift. you can find both keyboard helper functions that were explained above. We are using them to set the table view bottom insets. And now for the main one…

nextResponder() will help you:

  1. Determine which text field is next to become the first responder;
  2. Scroll to the new text field in focus;
  3. Handles a situation, if you have multiple cells (some without text fields), the index will skip the incrementing order. That’s why we need to make sure that we get the correct tag.

Connected with this post: Multiple UITableViewCells in UITableView (the right way)

Next UITextField Solved!

I hope that this post helped you discover how to handle the next UITextField situation. If you have any questions, please don’t hesitate to comment in the comments section. Also, share to help others and to support. 🙂

Follow me on Medium, for more interesting Swift programming tutorials.

Leave a Reply

Your email address will not be published. Required fields are marked *