I want to make calculations with inputs from 2 different Textfields and put the output in a Text. See code:
@State var input1: String = ""
@State var input2: String = ""
var calculation : Double {
let calculationProduct = Double(input1) * Double(input2)
return calculationProduct
}
var body: some View {
VStack{
TextField("", text: $input1)
TextField("", text: $input1)
Text("\(calculation)")
}
The problem is the code won't compile, i get different compile errors, for example: "Binary operator '*' cannot be applied to two 'Double?' operands".
What goes wrong?
Double(input1) returns String? because it's not guaranteed to work. e.g. Double("1abc")
We can use guard let or if let or even a nil coalescing operator ?? to handle this. But for the following example we will gracefully handle it using guard let.
struct ContentView: View {
@State var input1: String = ""
@State var input2: String = ""
var calculation : Double {
guard let m = Double(input1), let n = Double(input2) else { return 0 }
return m * n
}
var body: some View {
VStack {
TextField("", text: $input1)
TextField("", text: $input2)
Text("\(calculation)")
}
}
}
As per your comments, there are multiple ways to show "Error" on invalid inputs, or the answer upto 2 decimal point.
For this example, lets change the result to a computed String property both these these cases, as such:
struct ContentView: View {
@State var input1: String = ""
@State var input2: String = ""
var calculation: String {
//check if both fields have text else no need for message
guard input1.isEmpty == false, input2.isEmpty == false else { return "" }
//check if both are numbers else we need to print "Error"
guard let m = Double(input1), let n = Double(input2) else { return "Error" }
let product = m * n
return String(format: "%.2f", product)
}
var body: some View {
VStack {
TextField("Enter First Number", text: $input1)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Enter Second Number", text: $input2)
.textFieldStyle(RoundedBorderTextFieldStyle())
Text(calculation)
}
}
}
PS: If you want to ensure only numbers can be typed then you should think about applying the .keyboardType(.decimalPad) modifier on the TextFields.
@Johankornet, you have probably figured this out by now, but the below code will work for decimal entries:
import SwiftUI
struct ContentView: View {
@State var textFieldEntry: Double = 1.0
let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}()
var body: some View {
VStack {
TextField("title", value: $textFieldEntry, formatter: formatter).padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
To see it working, i made an entire app with this main file:
import SwiftUI
@main
struct testTextFieldWithNumericFormattingApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
formatter.decimalstyle = .decimal restricts the TextField input to decimals only. Type in something thats not a decimal, like "abc", hit return and the input is ignored. This input field can accept scientific notation numbers as input, but the TextField will display as a decimal so very small scientific notation inputs, such as 3e-7 will be displayed as zero.
@JohanKornet, you have probably found other more elegant solutions for this problem by now, but if not maybe this will help:)
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