Numeric Textfield in SwiftUI
In this SwiftUI tutorial, we will learn to create something that we use a lot in our iOS applications. So we will create a numeric text field that only accepts numbers as input.
What this blog will cover:
- create numeric textfield using keyboardType modifier
- create numeric textfield using onChange method
- create only number-type textfield, which will accept only a limited set of characters
Numeric textfield using the keyboardType modifier:
So the first and simple method of achieving our goal would be the keyboard type modifier, which you might have already guessed.
We use this modifier and give the keyboard its type, which would be number type, so the keyboard will only show numbers and the user will be restricted to only entering numbers in the text field.
Let’s see how we can do this:
struct ContentView: View { @State private var numberText: String = "" var body: some View { VStack { VStack { Text("Number TextField") .fontDesign(.rounded) .fontWeight(.bold) Text("---------") .padding(.bottom, 100) } TextField("Enter number", text: $numberText) .keyboardType(.numberPad) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() } } }
As this is a pretty good and easy way of doing this, there are some issues with this method. let’s see what’s that:
So when the number pad doesn’t allow us to enter any other character other than integers, we can still copy-paste other elements in the text field in SwiftUI. Also, we can use external keyboards, and the number-type keyboard is also not available on the iPad.
Let’s see how we’ll solve this issue.
Numeric textfield using the onChange method to prevent copy paste character issue:
Now, to handle this issue, we’ll use the onChange method of textfield along with the keyboardType
modifier.
struct ContentView: View { @State private var numberText: String = "" var body: some View { VStack { VStack { Text("Number TextField") .fontDesign(.rounded) .fontWeight(.bold) Text("---------") .padding(.bottom, 100) } TextField("Enter number", text: $numberText) .keyboardType(.numberPad) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() // This closure is deprecated in iOS 17.0 .onChange(of: numberText) { newValue in let filtered = newValue.filter { $0.isNumber } if numberText != filtered { numberText = filtered } } } }
- onChange: This method gets called whenever the text inside the text field gets changed.
isNumber: It’s a Swift built-in function that takes in characters and returns true if it’s an integer and false if it’s not.
The onChange method checks the content of the textfield and only allows integers to be typed into the textfield.
So apparently, this function looks okay. And it will work perfectly fine, but when you test it thoroughly, you will see that this function accepts some symbols. symbols that actually represent an integer value. So this inNumber
function will also consider those symbols as integers and let you enter them in the text field. So this isn’t actually what we want.
Only number-type textfield SwiftUI:
We will now restrict our text field a little more to accept only allowed digits, which are: 0,9,8,7,6,5,4,3,3,2,1. To do this, we’ll just have to slightly change the onChange method.
struct ContentView: View { @State private var numberText: String = "" var body: some View { VStack { VStack { Text("Number TextField") .fontDesign(.rounded) .fontWeight(.bold) Text("---------") .padding(.bottom, 100) } TextField("Enter number", text: $numberText) .keyboardType(.numberPad) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() // this closure is deprecated in iOS 17.0 .onChange(of: numberText) { newValue in // this will work, but it will allow some unexpected characters as well // let filtered = newValue.filter { $0.isNumber } // if numberText != filtered { // numberText = filtered // } let allowedCharacters = "0987654321" let filtered = newValue.filter { allowedCharacters.contains($0) } if numberText != filtered { numberText = filtered } } } } }
Here, we have just created a new string, allowedCharacters, that contains digits. and we’re filtering the textfield’s text with this newly created string. The onChange method will only allow characters to be entered in the textfield that we have already specified in the allowedCharacters string.
onChange method syntax in iOS 17.0 and later:
// new closure onChange(of: numberText) { oldState, newState in // set the allowed characters let allowedCharacters = "0987654321" let filtered2 = newState.filter { allowedCharacters.contains($0)} if numberText != filtered2 { numberText = filtered2 } }
Complete code:
import SwiftUI struct ContentView: View { @State private var numberText: String = "" var body: some View { VStack { VStack { Text("Number TextField") .fontDesign(.rounded) .fontWeight(.bold) Text("---------") .padding(.bottom, 100) } TextField("Enter number", text: $numberText) .keyboardType(.numberPad) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() // this closure is deprecated in iOS 17 // .onChange(of: numberText) { newValue in // this will work, but it will allow some unexpected characters as well // let filtered = newValue.filter { $0.isNumber } // if numberText != filtered { // numberText = filtered // } // let allowedCharacters = "0987654321" // let filtered = newValue.filter { allowedCharacters.contains($0) } // if numberText != filtered { // numberText = filtered // } // } // closure in iOS 17.0 and later .onChange(of: numberText) { oldState, newState in // set the allowed characters let allowedCharacters = "0987654321" let filtered2 = newState.filter { allowedCharacters.contains($0)} if numberText != filtered2 { numberText = filtered2 } } Text("Entered number : \(numberText)") .padding() } .padding() } }
Leave a Reply