I'm struggling with a simple task, to restrict TextField input with integers only. From the description - dounds easy. However, I can't find a way to do it with SwiftUI. I have an app macOS app with AppKit and want to re-write to SwiftUI. In my original code I use Combine and check NSTextField input in: textViewDidChangeSelection
Than -> I inform my viewModel
about what about to be typed - do the validation and assign the value if it's a correct one.
Unfortunately, I can't do the same with SwiftUI for some reasons. The problem is: I'm still allowed to type anything in TextField -> but as soon as I "leave it"/change focus -> it does filter to what I need. However, my goal is to NOT allow anything to be typed in TextField, apart from integers.
I've tried everything: ChatGPT suggestions, simple solutions like this: It still does not work and allow me to type eveyrthing, until I change focus from TextField to something else -> only than in gets filtered.
Am I missing something? Any help will be appreciated.
Code is below:
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject var viewModel: TestViewModel
var body: some View {
VStack {
InputTextFieldSwiftUIView(
label: "Ints only field",
text: Binding<String> {
return viewModel.text.intOnlyText
} set: { newText in
viewModel.validateText(newText)
},
onTextChanged: { newValue in
// What should I do here?
}
)
}
}
}
struct MyTestText {
var intOnlyText: String
}
class TestViewModel: ObservableObject {
@Published var text = MyTestText(intOnlyText: "")
func validateText(_ textValue: String) {
if textValue.isInt() || textValue.isEmpty {
text.intOnlyText = textValue
} else {
text.intOnlyText = text.intOnlyText
}
}
}
private extension String {
func isInt() -> Bool {
if let intValue = Int(self) {
if intValue > 0 {
return true
}
}
return false
}
}
struct InputTextFieldSwiftUIView: View {
var label: String
@Binding var text: String
let onTextChanged: (String) -> Void
var body: some View {
HStack {
Text(label)
.font(.headline)
.frame(width: 100, alignment: .leading)
TextField("", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width: 100)
.padding()
.onChange(of: text) { newValue in
onTextChanged(newValue)
}
}
}
}