6

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.

2 Answers 2

14

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!
Sign up to request clarification or add additional context in comments.

2 Comments

wow. man, gotta love SwiftUI voodoo. This is crazy. How in the world did you know this? Where did you learn this? Just curious so I can learn more about this. Thanks! This works.
@zumzum it's just an outlying weird thing that everyone bumps into at some point. More details here: sarunw.com/posts/…
1

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"

7 Comments

I did try this and it does fade out, but, the view is not totally removed. The opacity is just zero. The onDisappear is never called in this case. I wonder why the example I referenced in the link works (at least that is what they show online at swiftui-lab) and my example here does not.
Correct, but the question was how to fade it out as well as in, not to remove it. If you want to remove it adjusting the opacity won't work (however you do it). You need to actually remove it...
I do have that as what I wanted to achieve in the question. ...but then also fade out so that the view is totally removed .... Also, I just run that exact code from swift-lab. Does not work anymore seems like. Apple must updated this behavior.
Sorry - you did. I missed that.
All good. So I just tried that terniary operator approach but it's not fading out.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.