5

I have two images, ImageA and ImageB, and my goal is to animate a transition between them in the following manner:

  1. ImageA is loaded
  2. Pause for 1 second
  3. ImageA transitions to ImageB, with a duration of 1.5 seconds

With regular Swift, it would be using an UIView.animate closure with an animation duration and a pause.

Here is my attempt with SwiftUI, which is not showing a smooth transition, but a hard image change instead:

VStack(alignment: .leading, spacing: 0) {
            Image(images.randomElement()!)
                    .resizable()
                    .scaledToFill()
                    .onAppear {
                        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                        withAnimation() { //added
                            self.shouldTransition.toggle()
                        }
                    }
                    
            if shouldTransition {
                Image(images.randomElement()!)
                        .resizable()
                        .animation(.easeInOut(duration: 1.5))
                        .scaledToFill()
            }
            
        }

What is missing in my implementation to animate the image transition?

Edit: the entire codebase can be found here: TestWidget Github

2 Answers 2

3

You don't specify which kind of transition do you want, by default SwiftUI uses opacity...

Try the following

VStack(alignment: .leading, spacing: 0) {
    if !shouldTransition {
        Image(images.randomElement()!)
            .resizable()
            .scaledToFill()
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                    self.shouldTransition.toggle()
                }
            }
            //.transition(.move(edge: .top))      // uncomment to modify transition
    }

    if shouldTransition {
        Image(images.randomElement()!)
            .resizable()
            .scaledToFill()
            //.transition(.move(edge: .top))      // uncomment to modify transition
    }
    
}.animation(.easeInOut(duration: 1.5), value: shouldTransition)
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for sharing this. This definitely seemed promising but unfortunately the same result: no animation between image changes (I uncommented the two .transition()s per comments in the code). I have uploaded the entire codebase and updated the question body
I missed that this is widget... it will not work in widget - it is statically rendered.
I see - that explains it. Thanks for sharing your insight
Amazing solution @Asperi, highly appreciated!
1

You have to add withAnimation() { ... } wrapper around observed changes, which you want to be animated.

Change your code to

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                                withAnimation(){
                                self.shouldTransition.toggle()
                                }
                            }

1 Comment

Thanks for suggesting this. I added withAnimation() but the image transition still does not show an animation but a sudden image change. I also updated the code in the body of the question.

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.