I am trying to make a simple counter. I have the ContentView, and a separate struct that allows me to configure buttons in the ContentView. Each button calls a function in ContentView (Add 1, Add 2, etc). I feel that these functions should be in the MyButton struct but can't work out how to. Can anyone point me in the right direction please?
If I can suggest an improvement that will save many lines of code
enum Action {
case add(Int)
case reset
}
struct MyButton1: View {
@Binding var score: Int
var name: String
var color: Color
var action: Action
var body: some View {
ZStack {
Button {
switch action {
case .add(let value):
score += value
case .reset:
score = 0
}
} label: {
Text(name)
// styling
}
Capsule()
// styling
}
}
}
(Sidenote: it is best to have Capsule() inside the button label so that the entire area becomes tappable. You can overlay Text and Capsule with ZStack, or .overlay { })
First, if I understand your purpose correctly, the view name Test is misleading. It isn't a test but a UI component you intended to use in your app (let's call it FooView). This is important because it affects how the code should be organzied.
Based on that assumption, I think your current code is OK - FooView has a state score and has several methods to change that state. I don't think it makes sense to move these methods to Buttton.
Alternative approach (this is the one I prefer to): you can define a custom struct for score and move those addXYZ() methods to it. Then you can specify these methods directly when constructing the UI:
Button {
score.addOne()
}
I don't have access to my Mac at the moment, but I think it should work and is the most concise way to do it. No need to use binding. No need to define a custom button. And no need to pass operation parameter to that custom button (I think it's overkilling).