i’ve created a KetupatButton class with 2 method like this:
class KetupatButton {
var condition = false
@State var colorToShow = Color(UIColor(red: 183/255, green: 191/255, blue: 150/255, alpha: 100))
func colorChange() {
if condition == false {
colorToShow = Color(UIColor(red: 183/255, green: 191/255, blue: 150/255, alpha: 100))
} else {
colorToShow = Color(UIColor(red: 19/255, green: 58/255, blue: 27/255, alpha: 100))
}
}
func createButton(size: CGFloat) -> some View {
return AnyView(Button(action: {
self.condition = !self.condition
self.colorChange()
print(self.colorToShow)
print(self.condition)
}, label: {
Rectangle()
.frame(width: size, height: size, alignment: .leading)
.foregroundColor(colorToShow)
}))
}
}
But, when I call that class from my ContentView and tap the button, the button don’t change it’s color. Even though when i print the colorToShow variable, it changed. But the UI color of the button didn’t change…
Here is my ContentView
struct ContentView: View {
var button1 = KetupatButton()
var body: some View {
button1.createButton(size: 200)
}
}
>Solution :
You should follow a more structured approach: separate your view model, which is your class, from the views. Here are some steps to follow:
- Your view model should not contain the view, if you can avoid it. Create a specific view to show the button, separated from the logic. Here’s how your button could look like:
struct ButtonView: View {
// Receive the view model
@ObservedObject var viewModel: KetupatButton
let size: CGFloat
var body: some View {
Button {
// Use this to animate the change
withAnimation {
// The condition will automatically change the color, see the view model code
viewModel.condition.toggle()
}
} label: {
Rectangle()
.frame(width: size, height: size, alignment: .leading)
.foregroundColor(viewModel.colorToShow)
}
}
}
- Your view model should be an Observable Object. Also, the values that trigger a change in the UI should be
@Publishedvariables. In addition, I also made in a way that the color changes automatically when the condition changes, so you can get rid ofcolorChnage().
class KetupatButton: ObservableObject {
// When this variable changes, it will change also the color.
var condition = false {
didSet {
if condition {
colorToShow = Color(UIColor(red: 19/255, green: 58/255, blue: 27/255, alpha: 100))
} else {
colorToShow = Color(UIColor(red: 183/255, green: 191/255, blue: 150/255, alpha: 100))
}
}
}
@Published var colorToShow = Color(UIColor(red: 183/255, green: 191/255, blue: 150/255, alpha: 100))
}
- Finally,
ContentViewshould create an instance of the view model as a@StateObjectto share with subviews, likeButtonViewthat we created above:
struct ContentView: View {
@StateObject var viewModel = KetupatButton()
var body: some View {
ButtonView(viewModel: viewModel, size: 200)
}
}
Now, you can see that the color of the button changes.