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: @State variable does not update View when its value changes (within same View)

I am very new to SwiftUI. Maybe I am not completely understanding how @State annotated variables work. As far as I know, when you update their values, if they’re within the same View, the screen will get updated too (in this case the background color of the screen). I think I followed exactly the video tutorial (SwiftUI Basics Tutorial) but nonetheless I did not get my code to work. By the way, I’m using Xcode Version 13.2.1, if it’s worth mentioning. In my ContentView.swift this is what I have:

//
//  ContentView.swift
//


import SwiftUI

struct ContentView: View {
     
    @State private var isNight = false //Variable to be changed when pressing the button
    
    var body: some View {
        ZStack {
            //The BackgroundView color should change when pressing the button
            BackgroundView(topColor: isNight ? .black : .blue,
                           bottomColor: isNight ? .gray : Color("lightBlue"))
            VStack{
                CityTextView(cityName: "Cupertino, CA")
                MainWeatherStatusView(imageName: "cloud.sun.rain.fill",
                                      temperature: 72)
                HStack(spacing: 0){
                    WeatherView(dayOfWeek: "TUE",
                                imageName: "cloud.sun.fill",
                                temperature: 74)
                    WeatherView(dayOfWeek: "WED",
                                imageName: "sun.max.fill",
                                temperature: 30)
                    WeatherView(dayOfWeek: "THU",
                                imageName: "wind.snow",
                                temperature: 5)
                    WeatherView(dayOfWeek: "FRI",
                                imageName: "sunset.fill",
                                temperature: 60)
                    WeatherView(dayOfWeek: "SAT",
                                imageName: "snow",
                                temperature: 74)
                }
                Button{
                    isNight.toggle() //Changing this should update my View, right?
                } label: {
                    WeatherButton(title: "Change Day Time",
                                  textColor: .blue,
                                  backgroundColor: .white)
                }
                Spacer()
            }
        }
        
    }
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


struct WeatherView: View {
    
    var dayOfWeek: String
    var imageName: String
    var temperature: Int
    
    var body: some View {
        VStack{
            Text(dayOfWeek)
                .font(.system(size: 15, weight: .medium, design: .default))
                .foregroundColor(.white)
                .padding()
            
            Image(systemName: imageName)
                .renderingMode(.original)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 40, height: 40)
            
            Text("\(temperature)°")
                .font(.system(size: 30, weight: .medium))
                .foregroundColor(.white)
            
            Spacer()
        }
    }
}

struct BackgroundView: View {
    
    var topColor: Color
    var bottomColor: Color
    
    var body: some View {
        LinearGradient(gradient: Gradient(colors: [.blue, Color("lightBlue")]), startPoint: .topLeading, endPoint: .bottomTrailing)
            .edgesIgnoringSafeArea(.all)
    }
}

struct CityTextView: View {
    
    var cityName: String
    
    var body: some View {
        Text(cityName)
            .font(.system(size: 32, weight: .medium, design: .default))
            .foregroundColor(.white)
            .padding()
    }
}

struct MainWeatherStatusView: View {
    
    var imageName: String
    var temperature: Int
    
    
    var body: some View {
        VStack(spacing: 8){
            Image(systemName: imageName)
                .renderingMode(.original)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 180, height: 180)
            Text("\(temperature)°")
                .font(.system(size: 70, weight: .medium))
                .foregroundColor(.white)
        }
    }
}

In case you want to copy paste the code and want to get rid of the icons, here’s the code without them:

    //
    //  ContentView.swift
    //
    
    
    import SwiftUI
    
    struct ContentView: View {
         
        @State private var isNight = false //VARIABLE TO BE CHANGED WHEN PRESSING BUTTON
        
        var body: some View {
            ZStack {
                //The BackgroundView color should change when pressing the button
                BackgroundView(topColor: isNight ? .black : .blue,
                               bottomColor: isNight ? .gray : Color("lightBlue"))
                VStack{
                    CityTextView(cityName: "Cupertino, CA")
                    Button{
                        isNight.toggle() //CHANGING THIS SHOULD UPDATE MY VIEW, RIGHT?
                    } label: {
                        WeatherButton(title: "Change Day Time",
                                      textColor: .blue,
                                      backgroundColor: .white)
                    }
                    Spacer()
                }
            }
            
        }
        
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    
    
    struct WeatherView: View {
        
        var dayOfWeek: String
        var imageName: String
        var temperature: Int
        
        var body: some View {
            VStack{
                Text(dayOfWeek)
                    .font(.system(size: 15, weight: .medium, design: .default))
                    .foregroundColor(.white)
                    .padding()
                
                Image(systemName: imageName)
                    .renderingMode(.original)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 40, height: 40)
                
                Text("\(temperature)°")
                    .font(.system(size: 30, weight: .medium))
                    .foregroundColor(.white)
                
                Spacer()
            }
        }
    }
    
    struct BackgroundView: View {
        
        var topColor: Color
        var bottomColor: Color
        
        var body: some View {
            LinearGradient(gradient: Gradient(colors: [.blue, Color("lightBlue")]), startPoint: .topLeading, endPoint: .bottomTrailing)
                .edgesIgnoringSafeArea(.all)
        }
    }
    
    struct CityTextView: View {
        
        var cityName: String
        
        var body: some View {
            Text(cityName)
                .font(.system(size: 32, weight: .medium, design: .default))
                .foregroundColor(.white)
                .padding()
        }
    }
    
    struct MainWeatherStatusView: View {
        
        var imageName: String
        var temperature: Int
        
        
        var body: some View {
            VStack(spacing: 8){
                Image(systemName: imageName)
                    .renderingMode(.original)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 180, height: 180)
                Text("\(temperature)°")
                    .font(.system(size: 70, weight: .medium))
                    .foregroundColor(.white)
            }
        }
    }

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

>Solution :

In your current BackgroundView code, although you have topColor and bottomColor parameters, you don’t actually use them in your view. You probably want to include them in your gradient:

struct BackgroundView: View {
    
    var topColor: Color
    var bottomColor: Color
    
    var body: some View {
        LinearGradient(gradient: Gradient(colors: [topColor, bottomColor]), startPoint: .topLeading, endPoint: .bottomTrailing)
            .edgesIgnoringSafeArea(.all)
    }
}

Also, make sure you have your custom colors (like Color("lightBlue")) in your asset catalogue.

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