Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read and make calculations with textfield input SwiftUI

Tags:

ios

swift

swiftui

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?

like image 778
Johan Kornet Avatar asked Dec 18 '25 19:12

Johan Kornet


2 Answers

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)")
        }
    }
}

EDIT

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.

like image 191
staticVoidMan Avatar answered Dec 20 '25 10:12

staticVoidMan


@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:)

like image 33
gary Avatar answered Dec 20 '25 11:12

gary



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!