Home > Mobile >  SwiftUI: fade out view
SwiftUI: fade out view

Time:11-22

I have the following code:

struct ContentView: View {
    
    @State var show = false
    
    var body: some View {
        
        VStack {
            
            ZStack {
                
                Color.black
                
                if show {
                    RoundedRectangle(cornerRadius: 20)
                        .fill(.brown)
                        .transition(.opacity)
                }
                
            }
            
            Button {
                withAnimation(.easeInOut(duration: 1)) {
                    show.toggle()
                }
            } label: {
                Text("TRIGGER")
            }

        }

    }
    
}

I want the RoundedRectangle to fade in and out. Right now it only fades in. This is a simplified version of a more complex view setup I have. Depending on the state I may have the view I want to fade in or not. So, I am looking for a way to fade in (like it works now) but then also fade out so that the view is totally removed from the hierarchy and not just hidden or something.

How can I have this code also fade OUT the view and not only fade in?

As a reference I followed this approach:

https://swiftui-lab.com/advanced-transitions/

....
if show {
    LabelView()
         .animation(.easeInOut(duration: 1.0))
         .transition(.opacity)
    }
        
    Spacer()
        
    Button("Animate") {
        self.show.toggle()
    }.padding(20)
....

But, in my case it is NOT fading out.

CodePudding user response:

SwiftUI ZStack transitions are finicky. You need to add a zIndex to make sure the hierarchy is preserved, enabling the animation.

RoundedRectangle(cornerRadius: 20)
    .fill(.brown)
    .transition(.opacity)
    .zIndex(1) /// here!

CodePudding user response:

You need to link the opacity directly to the state, so that it is directly animating any changes.

struct ContentView: View {
      @State var show = false
   
   var body: some View {
      VStack {
         ZStack {
            Color.black
            (RoundedRectangle(cornerRadius: 20)
               .fill(.brown)
               .opacity(show ? 1 : 0)
            )
         }
         
         Button {
            withAnimation(.easeInOut(duration: 1)) {
               show.toggle()
            }
         } label: {
            Text("TRIGGER")
         }
      }
   }
}

EDIT: to reflect the comment requiring the view to be removed, not just faded out...

To remove the view (and trigger .onDisappear) you could modify as below:

         ZStack {
            Color.black
            show ? (RoundedRectangle(cornerRadius: 20)
               .fill(.brown)
               .zIndex(1).  //kudos to @aheze for this!

            ).onDisappear{print("gone")}
            : nil
         }

This will fade in/out as above, but will actually remove the view & print "gone"

  • Related