skip to Main Content

I’m making a simple app to calculate quantities for my bread baking. I have multiple "Button"s to change the variables, however the Labels displaying those values aren’t refreshing when I press them.

Any button should trigger a refresh of almost all labels, because the math will change each one.

Example: Adding 50g of flour will affect the quantity of water, salt, and yeast. Changing a percentage of water would affect only the quantity of water needed.

Thanks,

Here’s my code:

import SwiftUI

var flourPercent = 100
var waterPercent = 70
var saltPercent =  6.0
var yeastPercent = 2.0

var flourQuantity = 1000
var waterQuantity = flourQuantity * waterPercent / 100
var saltQuantity = flourQuantity * Int(saltPercent) / 100
var yeastQuantity = flourQuantity * Int(yeastPercent) / 100

let yeastStr = String(format: "%.2f", ceil(yeastPercent*100)/100)

struct ContentView: View {


var body: some View {
    HStack {
        VStack {
            Label("Subtract", systemImage: "")
            Button(action: {
                flourQuantity -= 50
                print(flourQuantity)
            }) {
                Text("-")
            }
            Button(action: {
                waterPercent -= 1
                print(waterPercent)
            }) {
                Text("-")
            }
            Button(action: {
                saltPercent -= 1
                print(saltPercent)
            }) {
                Text("-")
            }
            Button(action: {
                yeastPercent -= 0.1
                print(yeastPercent)
            }) {
                Text("-")
            }
        }
        VStack {
            Label("Add", systemImage: "")
            Button(action: {
                flourQuantity += 50
                print(flourQuantity)
            }) {
                Text("+")
            }
            Button(action: {
                waterPercent += 1
                print(waterPercent)
            }) {
                Text("+")
            }
            Button(action: {
                saltPercent += 1
                print(saltPercent)
            }) {
                Text("+")
            }
            Button(action: {
                yeastPercent += 0.1
                print(yeastPercent)
                
            }) {
                Text("+")
            }
        }
        VStack {
            Label("Baker's %", systemImage: "")
            Label("(flourPercent)%", systemImage: "")
            Label("(waterPercent)%", systemImage: "")
            Label("(Int(saltPercent))%", systemImage: "")
            Label(yeastStr + "%", systemImage: "")
        }
        VStack {
            Label("Quantity", systemImage: "")
            Label("(flourQuantity)g", systemImage: "")
            Label("(waterQuantity)ml", systemImage: "")
            Label("(saltQuantity)g", systemImage: "")
            Label("(yeastQuantity)g", systemImage: "")
        }
    }
}

}

2

Answers


  1. you can make this work with very few updates to your code. The properties you use to generate the text for your labels, have to be @State properties. This means whenever one of them is modified the view is redrawn:

    import SwiftUI
    
    @State var flourPercent: CGFloat = 100
    @State var waterPercent: CGFloat = 70
    @State var saltPercent: CGFloat =  6.0
    @State var yeastPercent: CGFloat = 2.0
    
    var flourQuantity: CGFloat = 1000
    var waterQuantity: CGFloat = { flourQuantity * waterPercent / 100 }
    var saltQuantity: CGFloat = { flourQuantity * Int(saltPercent) / 100 }
    var yeastQuantity: CGFloat = { flourQuantity * Int(yeastPercent) / 100 }
    
    let yeastStr = String(format: "%.2f", ceil(yeastPercent*100)/100)
    
    struct ContentView: View {
    
    
    var body: some View {
        HStack {
            VStack {
                Label("Subtract", systemImage: "")
                Button(action: {
                    flourQuantity -= 50
                    print(flourQuantity)
                }) {
                    Text("-")
                }
                Button(action: {
                    waterPercent -= 1
                    print(waterPercent)
                }) {
                    Text("-")
                }
                Button(action: {
                    saltPercent -= 1
                    print(saltPercent)
                }) {
                    Text("-")
                }
                Button(action: {
                    yeastPercent -= 0.1
                    print(yeastPercent)
                }) {
                    Text("-")
                }
            }
            VStack {
                Label("Add", systemImage: "")
                Button(action: {
                    flourQuantity += 50
                    print(flourQuantity)
                }) {
                    Text("+")
                }
                Button(action: {
                    waterPercent += 1
                    print(waterPercent)
                }) {
                    Text("+")
                }
                Button(action: {
                    saltPercent += 1
                    print(saltPercent)
                }) {
                    Text("+")
                }
                Button(action: {
                    yeastPercent += 0.1
                    print(yeastPercent)
                    
                }) {
                    Text("+")
                }
            }
            VStack {
                Label("Baker's %", systemImage: "")
                Label("(flourPercent)%", systemImage: "")
                Label("(waterPercent)%", systemImage: "")
                Label("(Int(saltPercent))%", systemImage: "")
                Label(yeastStr + "%", systemImage: "")
            }
            VStack {
                Label("Quantity", systemImage: "")
                Label("(flourQuantity)g", systemImage: "")
                Label("(waterQuantity)ml", systemImage: "")
                Label("(saltQuantity)g", systemImage: "")
                Label("(yeastQuantity)g", systemImage: "")
            }
        }
    }
    

    As you see I just prependes each variable that you change by the property wrapper @State. Read more about it here:

    https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-state-property-wrapper

    Login or Signup to reply.
  2. You can use the @State property wrapper to track changes in real time to your variables. The changes will be reflected on-screen when the buttons are pressed:

    import SwiftUI
    
    var flourPercent = 100
    var waterPercent = 70
    var saltPercent =  6.0
    var yeastPercent = 2.0
    
    let yeastStr = String(format: "%.2f", ceil(yeastPercent*100)/100)
    
    struct ContentView: View {
        
        @State var flourQuantity = 1000
        @State var waterQuantity: Int = 0
        @State var saltQuantity: Int = 0
        @State var yeastQuantity: Int = 0
        
        
        var body: some View {
            HStack {
                VStack {
                    Label("Subtract", systemImage: "")
                    Button(action: {
                        flourQuantity -= 50
                        print(flourQuantity)
                    }) {
                        Text("-")
                    }
                    Button(action: {
                        waterPercent -= 1
                        print(waterPercent)
                    }) {
                        Text("-")
                    }
                    Button(action: {
                        saltPercent -= 1
                        print(saltPercent)
                    }) {
                        Text("-")
                    }
                    Button(action: {
                        yeastPercent -= 0.1
                        print(yeastPercent)
                    }) {
                        Text("-")
                    }
                }
                VStack {
                    Label("Add", systemImage: "")
                    Button(action: {
                        flourQuantity += 50
                        print(flourQuantity)
                    }) {
                        Text("+")
                    }
                    Button(action: {
                        waterPercent += 1
                        print(waterPercent)
                    }) {
                        Text("+")
                    }
                    Button(action: {
                        saltPercent += 1
                        print(saltPercent)
                    }) {
                        Text("+")
                    }
                    Button(action: {
                        yeastPercent += 0.1
                        print(yeastPercent)
                        
                    }) {
                        Text("+")
                    }
                }
                VStack {
                    Label("Baker's %", systemImage: "")
                    Label("(flourPercent)%", systemImage: "")
                    Label("(waterPercent)%", systemImage: "")
                    Label("(Int(saltPercent))%", systemImage: "")
                    Label(yeastStr + "%", systemImage: "")
                }
                VStack {
                    Label("Quantity", systemImage: "")
                    Label("(flourQuantity)g", systemImage: "")
                    Label("(waterQuantity)ml", systemImage: "")
                    Label("(saltQuantity)g", systemImage: "")
                    Label("(yeastQuantity)g", systemImage: "")
                }
            }
            .onAppear(perform: {
                self.waterQuantity = flourQuantity * waterPercent / 100
                self.saltQuantity = flourQuantity * Int(saltPercent) / 100
                self.yeastQuantity = flourQuantity * Int(yeastPercent) / 100
            })
        }
    }
    

    There are some slight changes to your code here.. note the location of the declaration of the @State variable. This is just a quick example to show how it works, you will need to tweak it to do what you want. I set the initial values in the onAppear tag near the bottom…

    Updated answer

    • Answer using Published Var’s – So for what you are trying to, I think it would be better to use Environment Variables as shown below. I only set it up to work on the FlourQty, but from my example, you can see how it works..

    1 – Define an ObservableObject class

    2 – Publish your variables in that class

    3 – IMPORTANT – Add the variable of the Environment to your ContentView Class in the SceneDelegate:

     let myQty = QtyEnv()
    
     let contentView = ContentView()
        .environmentObject(myQty)
    

    Then this new example will work. I have also changed the calculations to change when it detects the FlourQty has changed..

    import SwiftUI
    
    //create the observable object class - dont forget to add to sceneDelegate..
    final class QtyEnv:ObservableObject {
        @Published var flourQty = 0
        @Published var saltQty = 0
        @Published var waterQty = 0
        @Published var yeastQty = 0
    }
    
    
    var flourPercent = 100
    var waterPercent = 70
    var saltPercent =  6.0
    var yeastPercent = 2.0
    
    let yeastStr = String(format: "%.2f", ceil(yeastPercent*100)/100)
    
    struct ContentView: View {
        
        @EnvironmentObject var myQty: QtyEnv
        
        
        
        var body: some View {
            HStack {
                VStack {
                    Label("Subtract", systemImage: "")
                    Button(action: {
                        self.myQty.flourQty -= 50
                        print(myQty.flourQty)
                    }) {
                        Text("-")
                    }
                    Button(action: {
                        waterPercent -= 1
                        print(waterPercent)
                    }) {
                        Text("-")
                    }
                    Button(action: {
                        saltPercent -= 1
                        print(saltPercent)
                    }) {
                        Text("-")
                    }
                    Button(action: {
                        yeastPercent -= 0.1
                        print(yeastPercent)
                    }) {
                        Text("-")
                    }
                }
                VStack {
                    Label("Add", systemImage: "")
                    Button(action: {
                        self.myQty.flourQty += 50
                        print(myQty.flourQty)
                    }) {
                        Text("+")
                    }
                    Button(action: {
                        waterPercent += 1
                        print(waterPercent)
                    }) {
                        Text("+")
                    }
                    Button(action: {
                        saltPercent += 1
                        print(saltPercent)
                    }) {
                        Text("+")
                    }
                    Button(action: {
                        yeastPercent += 0.1
                        print(yeastPercent)
                        
                    }) {
                        Text("+")
                    }
                }
                VStack {
                    Label("Baker's %", systemImage: "")
                    Label("(flourPercent)%", systemImage: "")
                    Label("(waterPercent)%", systemImage: "")
                    Label("(Int(saltPercent))%", systemImage: "")
                    Label(yeastStr + "%", systemImage: "")
                }
                VStack {
                    Label("Quantity", systemImage: "")
                    Label("(self.myQty.flourQty)g", systemImage: "")
                    Label("(self.myQty.waterQty)ml", systemImage: "")
                    Label("(self.myQty.saltQty)g", systemImage: "")
                    Label("(self.myQty.yeastQty)g", systemImage: "")
                }
            }
            
    //adjust published vars when changes of flourQty detected:
            .onReceive(self.myQty.$flourQty, perform: { _ in
                self.myQty.waterQty = self.myQty.flourQty * waterPercent / 100
                self.myQty.saltQty = self.myQty.flourQty * Int(saltPercent) / 100
                self.myQty.yeastQty = self.myQty.flourQty * Int(yeastPercent) / 100
            })
            
        }
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search