Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: save the state of toggle and keep the animation

In SwiftUI, for this code to toggle the display of view:

@State var show = true

Button { withAnimation { show.toggle() }} 
label: { Image(systemName: show ? "chevron.down" : "chevron.right") }

if show { ... }

The animation will be shown if the show is the @State variable.

However, I found that if show is changed to @AppStorage (so to keep the show state), the animation will not be shown.

Is there a way to keep the show state and also preserve the animation?

like image 547
Lim Thye Chean Avatar asked Oct 12 '25 05:10

Lim Thye Chean


1 Answers

You can also replace the withAnimation {} with the .animation(<#T##animation: Animation?##Animation?#>, value: <#T##Equatable#>) modifier and then it seems to work directly with the @AppStorage wrapped variable.

import SwiftUI
    
struct ContentView: View {
    @AppStorage("show") var show: Bool = true
    
    var body: some View {
        VStack {
            Button {
                self.show.toggle()
            }
            label: {
                Rectangle()
                    .fill(Color.red)
                    .frame(width: self.show ? 200 : 400, height: 200)
                    .animation(.easeIn, value: self.show)
            }
            
            Rectangle()
                .fill(Color.red)
                .frame(width: self.show ? 200 : 400, height: 200)
                .animation(.easeIn, value: self.show)
        }
        .padding()
    }
}

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

EDIT: Following the comments, another solution

import SwiftUI
    
struct ContentView: View {
    @State private var show: Bool
    
    init() {
        self.show = UserDefaults.standard.bool(forKey: "show")
        // Or self._show = State(initialValue: UserDefaults.standard.bool(forKey: "show"))
    }
    
    var body: some View {
        VStack {
            Button {
                withAnimation {
                    self.show.toggle()
                }
            }
            label: {
                Text("Toggle")
            }
            
            if show {
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 200 , height: 200)
            }
        }
        .padding()
        .onChange(of: self.show) { newValue in
             UserDefaults.standard.set(newValue, forKey: "show")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
like image 55
Marc Biosca Avatar answered Oct 15 '25 12:10

Marc Biosca