Creating an OTP screen with Swift 5/4.2

Satyenkumar Mourya
3 min readJun 22, 2019

Firstly we see what we are going to build… just so that it may save time for some developers who might have stumbled upon the wrong tutorial 😜

Update: Added suggested .oneTimeCode support (refer end of the article)

That's what we are going to build

So now the basic question arises that how can it be created… Think for some time I’m waiting…

Now if you have given it a thought then you may have arrived on the following:

#. Using single UITextField and then design it. ❌

#. Using multiple UITextFields and then arranging them in a View or ViewContoller (between ❌ and ✅)

  • you’re close to the solution, It can be done this way but still, think some more there is a better way 🙇‍♂️💡… see the below option now.

#. Using multiple UITextFields held by a single UIStackView ✅

  • Now let's see why is it better than the previous one:
  • Firstly, it will be much easier to handle the UI for all the text fields.
  • Second, makes your OTP field more scalable like if you want to switch from 6 fields to 4 or even for that matter 8 or 20( just kidding no user has got the time to do such stupidious task 😂😂)
  • Thirdly, it will make your code much more maintainable

Now that the approach is clear we will proceed with the followings:

1. We need to create our custom UITextFields Class

class OTPTextField: UITextField {  weak var previousTextField: OTPTextField?
weak var nextTextField: OTPTextField?
override public func deleteBackward(){
text = ""
previousTextField?.becomeFirstResponder()
}
}

This step can be removed, but it is there for optimization and better UX. We will have an array of all the text fields in our OTPStackView, for now, this information is important to understand the below points.

Let me explain :

  • If we don't add previousTextField and nextTextField then we would have to iterate every text field in the maintained array and check for it’s previous or next fields for setting them as the firstResponder.
  • The UX element comes here because there is no delegate method to help with moving the firstResponder from right to left i.e if we are pressing backspace in an empty text field, so we override its deleteBackward for achieving our goal.

Note: Remember to make the references of previousTextField and nextTextField as a weak variable to avoid retain cycle.

2. Now we will create our Custom OTPStackView and handle the switching of responders

We need to customize it and add our TextViews after that we handle the switching of responder with help of UITextFieldDelegate methods

Handling the switching of responder

3. Create a Delegate so that we can get our event while using our OTPStackview

We can add other required methods according to our needs, for now, we are just doing it for validation purposes.

protocol OTPDelegate: class {//always triggers when the OTP field is valid
func didChangeValidity(isValid: Bool)
}

4. The Final step- Add it to the ViewController

Finally, we can instantiate our OTPStackView and add it to our ViewController.

override func viewDidLoad() {
let otpStackView = OTPStackView()
self.addSubview(otpStackView)
otpStackView.delegate = self
}
if string.count > 1 {
textField.resignFirstResponder()
autoFillTextField(with: string)
return false
}

Note:

The above-highlighted line to resignFirstResponder is important in case of auto-fill as in the end auto-correct tries to enter a space character which results in override the text value for the selected text field.

For the .oneTimeCode suggested fill code, you can refer to the above github gist code.

--

--