Gallaugher
Gallaugher

Reputation: 1971

SwiftUI transition with opacity not showing

I'm still new to SwiftUI. I'm trying to get each change of an image to start out at opacity 0.0 (fully transparent), then increase to opacity 1.0 (fully opaque) I expected I could achieve this using the .opacity transition. .opacity is described as a "transition from transparent to opaque on insertion", so my assumption is that by stating "withAnimation" in my Button action, I'd trigger the Image to be re-rendered, and the transition would occur beginning from faded to transparent. Instead I see the same instant appear of the new shape & slow morphing to a new size, no apparent change in .opacity. Code and .gif showing current result, below. I've used UIKit & know I'd set alpha to zero, then UIView.animate to alpha 1.0 over a duration of 1.0, but am unsure how to get the same effect in SwiftUI. Thanks!

enter image description here

struct ContentView: View {
    @State var imageName = ""
    var imageNames = ["applelogo", "peacesign", "heart", "lightbulb"]
    @State var currentImage = -1
    
    var body: some View {
        VStack {
            
            Spacer()

            Image(systemName: imageName)
                .resizable()
                .scaledToFit()
                .padding()
                .transition(.opacity)
            
            Spacer()
            
            Button("Press Me") {
                currentImage = (currentImage == imageNames.count - 1 ? 0 : currentImage + 1)
                withAnimation(.linear(duration: 1.0)) {
                    imageName = imageNames[currentImage]
                }
            }
            
        }
    }
}

Upvotes: 1

Views: 4336

Answers (2)

swiftPunk
swiftPunk

Reputation: 1

Here is the correct approach for this kind of issue:

We should not forgot how transition works!!! Transition modifier simply transmit a view to nothing or nothing to a view (This should be written with golden ink)! in your code there is no transition happening instead update happing.

struct ContentView: View {
    
    @State var imageName1: String? = nil
    @State var imageName2: String? = nil
    
    var imageNames: [String] = ["applelogo", "peacesign", "heart", "lightbulb"]
    @State var currentImage = -1
    
    var body: some View {
        VStack {
            
            Spacer()
            
            ZStack {
                
                if let unwrappedImageName: String = imageName1 {
                    
                    Image(systemName: unwrappedImageName)
                        .resizable()
                        .transition(AnyTransition.opacity)
                        .animation(nil, value: unwrappedImageName)
                        .scaledToFit()
                    
                }
                
                if let unwrappedImageName: String = imageName2 {
                    
                    Image(systemName: unwrappedImageName)
                        .resizable()
                        .transition(AnyTransition.opacity)
                        .animation(nil, value: unwrappedImageName)
                        .scaledToFit()
                    
                }
                
            }
            .padding()
            .animation(.linear, value: [imageName1, imageName2])
            
            Spacer()
            
            Button("Press Me") {
                currentImage = (currentImage == imageNames.count - 1 ? 0 : currentImage + 1)
                
                if imageName1 == nil {
                    imageName2 = nil; imageName1 = imageNames[currentImage]
                }
                else {
                    imageName1 = nil; imageName2 = imageNames[currentImage]
                }
                
            }
            
        }
        
    }
}

Upvotes: 1

Yrb
Yrb

Reputation: 9685

The reason you are not getting the opacity transition is that you are keeping the same view. Even though it is drawing a different image each time, SwiftUI sees Image as the same. the fix is simple: add .id(). For example:

        Image(systemName: imageName)
            .resizable()
            .scaledToFit()
            .padding()
            .transition(.opacity)
            // Add the id here
            .id(imageName)

Upvotes: 4

Related Questions