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