Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transition animation not working in SwiftUI

I'm trying to create a really simple transition animation that shows/hides a message in the center of the screen by tapping on a button:

struct ContentView: View {     @State private var showMessage = false      var body: some View {         ZStack {             Color.yellow              VStack {                 Spacer()                 Button(action: {                     withAnimation(.easeOut(duration: 3)) {                         self.showMessage.toggle()                     }                 }) {                     Text("SHOW MESSAGE")                 }             }              if showMessage {                 Text("HELLO WORLD!")                     .transition(.opacity)             }         }     } } 

According to the documentation of the .transition(.opacity) animation

A transition from transparent to opaque on insertion, and from opaque to transparent on removal.

the message should fade in when the showMessage state property becomes true and fade out when it becomes false. This is not true in my case. The message shows up with a fade animation, but it hides with no animation at all. Any ideas?

EDIT: See the result in the gif below taken from the simulator.

enter image description here

like image 331
matteopuc Avatar asked Aug 30 '19 16:08

matteopuc


People also ask

How do I add animations to SwiftUI?

SwiftUI has built-in support for animations with its animation() modifier. To use this modifier, place it after any other modifiers for your views, tell it what kind of animation you want, and also make sure you attach it to a particular value so the animation triggers only when that specific value changes.

How do I animate a view in SwiftUI?

If you want a SwiftUI view to start animating as soon as it appears, you should use the onAppear() modifier to attach an animation.

What is the default animation SwiftUI?

default is a basic animation with 0.35 seconds duration and an ease-in-ease-out timing curve.

What is withAnimation SwiftUI?

withAnimation() takes a parameter specifying the kind of animation you want, so you could create a three-second linear animation like this: withAnimation(.linear(duration: 3)) Explicit animations are often helpful because they cause every affected view to animate, not just those that have implicit animations attached.


2 Answers

The problem is that when views come and go in a ZStack, their "zIndex" doesn't stay the same. What is happening is that the when "showMessage" goes from true to false, the VStack with the "Hello World" text is put at the bottom of the stack and the yellow color is immediately drawn over top of it. It is actually fading out but it's doing so behind the yellow color so you can't see it.

To fix it you need to explicitly specify the "zIndex" for each view in the stack so they always stay the same - like so:

struct ContentView: View { @State private var showMessage = false  var body: some View {     ZStack {         Color.yellow.zIndex(0)          VStack {             Spacer()             Button(action: {                 withAnimation(.easeOut(duration: 3)) {                     self.showMessage.toggle()                 }             }) {                 Text("SHOW MESSAGE")             }         }.zIndex(1)          if showMessage {             Text("HELLO WORLD!")                 .transition(.opacity)                 .zIndex(2)         }     } } 

}

like image 185
Scott Gribben Avatar answered Sep 20 '22 01:09

Scott Gribben


My findings are that opacity transitions don't always work. (yet a slide in combination with an .animation will work..)

.transition(.opacity) //does not always work 

If I write it as a custom animation it does work:

.transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.2)))  .zIndex(1) 
like image 35
Pbk Avatar answered Sep 23 '22 01:09

Pbk