Apple only provides UITextField for inputs which always returns a string. You can define a keyboard layout (decimal pad in my case) but that is where support for numeric inputs in iOS ends.
Today I’m going to show you how to limit the characters a user can enter and verify we actually have a number. (Hint: Don’t trust the chosen keyboard layout! The user can copy/paste). With the decimal pad keyboard the user can enter strings like
23.13.1. neither of which are legit numbers, let alone monetary.
I’ll show you how to create a text input which only allows valid decimal numbers and limits the amount of decimal places. With locale specific variations in mind:
5.5 in the US is equal to
5,5 in Germany for example, and our app should support both.
I assume you already have a UITextField in your storyboard. Make sure you have the keyboard type set to
Decimal Pad either in the storyboard or in code and connected the outlet to your ViewController. The first thing we have to do now is declare our ViewController as textfield delegate:
Here we add the
UITextFieldDelegate protocol to our class and set the
moneyTextField.delegate to the
Now to the actual validation by implementing the
textField(shouldChangeCharactersIn:) method. This method runs every time the user modifies the text in any way (typing, deleting, pasting) and before the UI reflects the changes.
Here we build what the new string would look like as
replacementText and then use my own
isValidDouble(maximalDecimalPlaces:) to verify the input. I’m using an extension because I have many places where I need to perform this check. If you only accept number inputs in this place and nowhere else feel free to move the code into the method above.
Quick explanation for
shouldChangeCharactersIn:: If you return true then iOS updates the textField value with the changes the user performed. But if you return false the changes get dropped and nothing happens.
Here is the extension implementation performing the actual checks:
First we create a NumberFormatter, a locale aware way to get numbers from Strings and ask it for the decimal separator. We then try to create a number from the string. When that succeeds we check if the number of decimal places is less than or equal to the provided. If everything checks out we return true at which point the UI updates with the modifications to the textField.
Now we have a textField input that only accepts valid numbers, respects locale specific decimal separators and limits the number of decimal places to whatever we want.
The user can never enter a non-valid number, not even by pasting in some garbage and once they’re ready to save you can be sure it is valid. (Of course the textField can still be empty!)