I have an issue with this setup:
ZStack {
ViewOne
if something ? ViewTwo : nil
}
.animation()
The problem is that when the animation starts, ViewTwo flashes on and off. I'm thinking it has something to do with the view re-rendering or something? But I can't quite figure it out. I've tried moving the animation around, using it on each view separately, combining it all in one view, but it always flashes when it's based on a conditional. I'd like BOTH views to animate together.
Here is a piece of reproducible code snippet.
struct ContentView: View {
@State var isAnimating: Bool
var body: some View {
ZStack {
VStack {
ForEach((1...5).reversed(), id: \.self) {_ in
ZStack {
RoundedRectangle(cornerRadius: 5)
.foregroundColor(.blue)
.frame(width: 200, height: 50)
.rotationEffect(.degrees(isAnimating == true ? 5 : 0))
isAnimating
? ButtonImage()
: nil
}
.animation(
.easeInOut(duration: 0.3)
.repeatForever(autoreverses: true)
, value: isAnimating
)
}
Button(action: {
self.isAnimating.toggle()
}, label: {
Text("Animate")
})
}
}
.rotationEffect(.degrees(isAnimating == true ? 5 : 0))
}
}
struct ButtonImage: View {
private let buttonSize: CGSize = CGSize(width: 25, height: 25)
var body: some View {
Button(action: {
// to something
}) {
Image(systemName: "flame")
.resizable()
.renderingMode(.template)
.background(Color.red)
.foregroundColor(Color.yellow)
.frame(width: buttonSize.width, height: buttonSize.height)
}
.frame(width: buttonSize.width, height: buttonSize.height)
.offset(x: -buttonSize.width / 2, y: -buttonSize.height / 2)
}
Any ideas of how to resolve this? Showing a view based on a condition, while also animating it without it flashing?
CodePudding user response:
Figured out a way! Not sure if it's the best approach, but it works.
Add the animation to both views separately, then add an opacity modifier to the second view. Here is the code I used.
struct ContentView: View {
@State var isAnimating: Bool
var body: some View {
ZStack {
VStack {
ForEach((1...5).reversed(), id: \.self) {_ in
ZStack {
RoundedRectangle(cornerRadius: 5)
.foregroundColor(.blue)
.frame(width: 200, height: 50)
.rotationEffect(.degrees(isAnimating == true ? 5 : 0))
.animation(
.easeInOut(duration: 0.3)
.repeatForever(autoreverses: true)
, value: isAnimating
)
ButtonImage(isAnimating: $isAnimating)
.opacity(isAnimating ? 1 : 0)
}
}
Button(action: {
self.isAnimating.toggle()
}, label: {
Text("Animate")
})
}
}
.rotationEffect(.degrees(isAnimating == true ? 5 : 0))
}
}
struct ButtonImage: View {
private let buttonSize: CGSize = CGSize(width: 25, height: 25)
@Binding var isAnimating: Bool
var body: some View {
Button(action: {
// to something
}) {
Image(systemName: "flame")
.resizable()
.renderingMode(.template)
.background(Color.red)
.foregroundColor(Color.yellow)
.frame(width: buttonSize.width, height: buttonSize.height)
}
.frame(width: buttonSize.width, height: buttonSize.height)
.offset(x: -buttonSize.width / 2, y: -buttonSize.height / 2)
.rotationEffect(.degrees(isAnimating == true ? 5 : 0))
.animation(
.easeInOut(duration: 0.3)
.repeatForever(autoreverses: true)
, value: isAnimating
)
}
}