Home > Software design >  SwiftUI: Binded property does not change the views
SwiftUI: Binded property does not change the views

Time:04-03

I tried to bind the property to as isFavorite, somehow its value is changing on change but the view is not changing though.

    @EnvironmentObject var modelData: ModelData
    var landmark:Landmark

    var landmarkIndex: Int {
        modelData.landmarks.firstIndex(where: { $0.id == landmark.id })!
    }
    
    var body: some View {
        ScrollView{
            MapPreview(coordinate: landmark.locationCoordinate)
                .ignoresSafeArea(edges: .top)
                .frame(height: 300)

            MapProfileImage(image: landmark.image)
                .offset(y: -130)
                .padding(.bottom, -130)
            
            VStack(alignment: .leading){
                HStack{
                    Text(landmark.name)
                        .font(.largeTitle)
                    FavoriteButton(isSet: $modelData.landmarks[landmarkIndex].isFavorite)
                }
                
                HStack{
                    Text(landmark.park)
                    Spacer()
                    Text(landmark.state)
                }

and its binded to a property isSet

struct FavoriteButton: View {
    @Binding var isSet: Bool
    
    var body: some View {
        Button(action: {
            print("isSet \(String(isSet))")
            isSet.toggle()
            
        }){
            
            Image(systemName:isSet ? "star.fill" : "star")
                .foregroundColor(.black)
        }
    }
}

Im new to SwitftUI, care to explain whats wrong pls

CodePudding user response:

Usually @Binding is used when you want to bind a @State property in the parent view with another property in the child view.

In your case, you already have your view model in the environment, so just need to read the the environment again in the child view and change the variable directly there.

Here is how you could implement FavoriteButton:

struct FavoriteButton: View {

    // Read the environment to get the view model
    @EnvironmentObject var modelData: ModelData

    // You will need to pass the index from the parent view
    let index: Int
    
    var body: some View {
        Button(action: {
            print("index \(index), isSet \(String(modelData.landmarks[index].isFavorite))")

            // Change the view model directly
            modelData.landmarks[index].isFavorite.toggle()
            
        }){
            
            Image(systemName: modelData.landmarks[index].isFavorite ? "star.fill" : "star")
                .foregroundColor(.black)
        }
    }
}

In the parent view, call it passing the index:

FavoriteButton(index: landmarkIndex)

Needless to say, ModelData needs to be a class that conforms to ObservableObject and must already be in the environment when you call the parent view.

  • Related