Delay SwiftUI combined transitions

Viewed 571

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?

1 Answers

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)
            }
        }
    }
}

Related