Search code examples
swiftuiswiftui-animation

Basic SwiftUI Animation using `withAnimation` block over a Bool value


I am having a basic SwiftUI view setup. When I tap the Show button, I expect the overlay to appear with a 2-second animation. Similarly, when I tap the close button on the overlay view, I anticipate the overlay to dismiss with a 2-second animation.

Xcode: 14.3.1 iOS Target: 16.4

struct Playground: View {
    
    @State private var showDetailView: Bool = false
    
    var body: some View {
        VStack {
            Button("Show") {
                withAnimation(.easeIn(duration: 2.0)) {
                    showDetailView = true
                }
            }.buttonStyle(.borderedProminent)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .overlay {
            if showDetailView {
                show()
            }
        }
    }
    
    @ViewBuilder
    func show() -> some View {
        VStack {
            Button("Close") {
                withAnimation(.easeIn(duration: 2.0)) {
                    showDetailView = false
                }
            }.buttonStyle(.bordered)
                .offset(y: 100)
        }
        .foregroundColor(.white)
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        .background(.black)
    }
}

The issue I'm facing is that when I run the code on a simulator(iOS 16.4), the first time I tap the Show button, the overlay animates in correctly. Additionally, when I tap the close button, the overlay animates out as expected. However, the problem arises when I tap the Show button for the second time. The animation seems to vanish, and instead of animating in, the overlay instantly appears after a 2-second delay. Strangely, the "close" button continues to animate the fade-out correctly.


Solution

  • Try this one is Working.

    Xcode: 14.3 iOS Target: 16.4

    @State private var showDetailView: Bool = false
    
    var body: some View {
        VStack {
            Button("Show") {
                withAnimation(.linear(duration: 2.0)){
                    showDetailView = true
                }
            }.buttonStyle(.borderedProminent)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .overlay {
            if showDetailView {
                show()
            }
        }
    }
    
    @ViewBuilder
    func show() -> some View {
        VStack {
            Button("Close") {
                withAnimation(.easeIn(duration: 2.0)) {
                    showDetailView = false
                }
            }.buttonStyle(.bordered)
                .offset(y: 100)
        }
        .foregroundColor(.white)
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        .background(.black)
    }