Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

SwiftUI Can't Change Color Button from Class Method

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…

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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:

  1. 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)
        }
    }
}
  1. Your view model should be an Observable Object. Also, the values that trigger a change in the UI should be @Published variables. In addition, I also made in a way that the color changes automatically when the condition changes, so you can get rid of colorChnage().
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))
}
  1. Finally, ContentView should create an instance of the view model as a @StateObject to share with subviews, like ButtonView that 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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading