0

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)
}

}

1
  • It is completely non-SwiftUI approach... and State does not work outside of View. See several WWDC sessions about SwiftUI concepts, etc. Commented Apr 12, 2022 at 15:12

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.