Search code examples
swiftswiftuiswiftui-animation

Delay SwiftUI combined transitions


With the following code, the intention is to have the transition fading in (opacity) and shifting downwards (offset) at the same time but with a delay of .3 seconds.

With this one only the opacity transition is visible after 0.3 seconds:

.transition(.offset(x: 0, y: -20)
.combined(with: .opacity)
.animation(.easeOut.delay(0.3)))

I thought maybe the animation has to be set on both transitions, the initial AND the combined one like so (spoiler: same results as before):

.transition(.offset(x: 0, y: -20)
.combined(with:.opacity.animation(.easeOut.delay(0.5)))
.animation(.easeOut.delay(0.5)))

Changing the order doesn't change the outcome either:

.transition(.offset(x: 0, y: -20)
.animation(.easeOut.delay(0.5))
.combined(with: .opacity.animation(.easeOut.delay(0.5))))

So what am I doing wrong here? How can I have a combined transition delayed?


Solution

  • Try this

    extension AnyTransition {
        static var delayAndFade: AnyTransition {
            return AnyTransition.identity
                  .combined(with: .opacity)
                  .animation(.default.delay(3))
        }
    }
    

    If you want to move a view, you should animate its offset using the withAnimation function.

             Text("Move and fade.")
                 .offset(y: offset)
                 .transition(.delayAndFade)
    
    
    struct ContentView: View {
        @State private var showDetails = false
        @State var offset:CGFloat = 0
    
        var body: some View {
            VStack {
                Button("Press to show details") {
                    showDetails.toggle()
                    withAnimation(.default.delay(3)) {
                        self.offset = -20
                    }
                }
    
            
                if showDetails {
                    Text("Move and fade.")
                        .offset(y: offset)
                        .transition(.delayAndFade)
                }
            }
        }
    }
    
    

    Update

    extension AnyTransition {
        static var moveAndFade: AnyTransition {
            return AnyTransition.move(edge: .top)
                  .combined(with: .opacity)
        }
    }
    
    

    Try this

    HStack {
         Text("Move and fade.")
    }
    .animation(Animation.default.delay(2))
    .transition(.moveAndFade)
    

    It works with all kind of views except Text.

    struct ContentView: View {
        @State private var showDetails = false
        @State var offset:CGFloat = 0
    
        var body: some View {
            VStack {
                Button("Press to show details") {
                    showDetails.toggle()
    
                }
    
            
                if showDetails {
                    
                    // Works!
                    HStack {
                        Text("Move and fade.")
                    }
                    .animation(Animation.default.delay(2))
                    .transition(.moveAndFade)
                    
                    Button("Move and fade.") {}
                    .animation(Animation.default.delay(2))
                    .transition(.moveAndFade)
                    
                    // Does not work
                    Text("Move and fade.")
                    .animation(Animation.default.delay(2))
                    .transition(.moveAndFade)
                }
            }
        }
    }