Search code examples
swiftuitextfieldsubtotal

SwiftUI - Subtotal TextField entries across multiple views


I have multiple views created by a ForEACH. Each View has a textfield where a user can enter a number. I would like to subtotal each entry in each view. In other words subtotal the binding in each view.

Is my approach wrong?

ForEach(someArray.allCases, id: \.id) { item in
                    CustomeRowView(name: item.rawValue)
                }
struct CustomeRowView: View {
    
   
    var name: String
    @State private var amount: String = ""
    
    
    var body: some View {
        
        VStack {
            
            HStack {
                Label(name, systemImage: image)
 
                
                VStack {
                    TextField("Amount", text: $amount)
                        .frame(width: UIScreen.main.bounds.width / 7)
        
                    
                }

            }
         
        }
    }
 
}

Any help would be greatly appreciated.


Solution

  • there are many ways to achieve what you ask. I present here a very simple approach, using an ObservableObject to keep the info in one place. It has a function to add to the info dictionary fruits.

    A @StateObject is created in ContentView to keep one single source of truth. It is passed to the CustomeRowView view using @ObservedObject, and used to tally the input of the TextField when the return key is pressed (.onSubmit).

    import SwiftUI
    
    @main
    struct TestApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
        }
    }
    
    class FruitCake: ObservableObject {
        @Published var fruits: [String : Int] = ["apples":0,"oranges":0,"bananas":0]
        
        // adjust for you purpose
        func add(to name: String, amount: Int) {
            if let k = fruits.keys.first(where: {$0 == name}),
               let sum = fruits[k] {
                fruits[k] = sum + amount
            }
        }
    }
        
    struct ContentView: View {
        @StateObject var fruitCake = FruitCake()
        
        var body: some View {
            VStack {
                ForEach(Array(fruitCake.fruits.keys), id: \.self) { item in
                    CustomeRowView(name: item, fruitCake: fruitCake)
                }
            }
        }
    }
    
    struct CustomeRowView: View {
        let name: String
        @ObservedObject var fruitCake: FruitCake
        @State private var amount = 0
        
        var body: some View {
            HStack {
                Label(name, systemImage: "info")
                TextField("Amount", value: $amount, format: .number)
                    .frame(width: UIScreen.main.bounds.width / 7)
                    .border(.red)
                    .onSubmit {
                        fruitCake.add(to: name, amount: amount)
                    }
                // subtotal
                Text("\(fruitCake.fruits[name] ?? 0)")
            }
        }
        
    }