I'm new to SwiftUI and iOS, and I'm trying to create an input field that will only accept numbers.
TextField("Total number of people", text: $numOfPeople)
The TextField
currently allows alphabetic characters, how do I make it so that the user can only input numbers?
Method 1: Changing the Text Field Type from storyboard. Select the text field that you want to restrict to numeric input. Go to its attribute inspector. Select the keyboard type and choose number pad from there.
Although showing a number pad is a good first step, it does not actually prevent bad data from being entered:
TextField
What you really want to do is sanitize the input, like this:
import SwiftUI
import Combine
struct StackOverflowTests: View {
@State private var numOfPeople = "0"
var body: some View {
TextField("Total number of people", text: $numOfPeople)
.keyboardType(.numberPad)
.onReceive(Just(numOfPeople)) { newValue in
let filtered = newValue.filter { "0123456789".contains($0) }
if filtered != newValue {
self.numOfPeople = filtered
}
}
}
}
Whenever numOfPeople
changes, the non-numeric values are filtered out, and the filtered value is compared to see if numOfPeople
should be updated a second time, overwriting the bad input with the filtered input.
Note that the Just
publisher requires that you import Combine
.
EDIT:
To explain the Just
publisher, consider the following conceptual outline of what occurs when you change the value in the TextField
:
TextField
takes a Binding
to a String
when the contents of the field are changed, it also writes that change back to the @State
variable.@State
changes, SwiftUI recomputes the body
property of the view.body
computation, a Just
publisher is created. Combine has a lot of different publishers to emit values over time, but the Just
publisher takes "just" a single value (the new value of numberOfPeople
) and emits it when asked.onReceive
method makes a View
a subscriber to a publisher, in this case, the Just
publisher we just created. Once subscribed, it immediately asks for any available values from the publisher, of which there is only one, the new value of numberOfPeople
.onReceive
subscriber receives a value, it executes the specified closure. Our closure can end in one of two ways. If the text is already numeric only, then it does nothing. If the filtered text is different, it is written to the @State
variable, which begins the loop again, but this time the closure will execute without modifying any properties.Check out Using Combine for more info.
Checkout John M's solution for a much better way.
One way to do it is that you can set the type of keyboard on the TextField
which will limit what people can type on.
TextField("Total number of people", text: $numOfPeople)
.keyboardType(.numberPad)
Apple's documentation can be found here, and you can see a list of all supported keyboard types here.
However, this method is only a first step and is not ideal as the only solution:
You should sanitise the data that is entered and make sure that it is purely numeric.
For a solution that does that checkout John M's solution below. He does a great job explaining how to sanitise the data and how it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With