Home > Mobile >  SwiftUI transition with opacity not showing
SwiftUI transition with opacity not showing

Time:05-25

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

CodePudding user response:

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)

CodePudding user response:

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]
                }
                
            }
            
        }
        
    }
}
  • Related