简体   繁体   中英

Conditional animation in SwiftUI stops working

I have this code:

Group{
   if self.done{
      Image(systemName: "plus").font(.system(size: 40)).foregroundColor(.gray)
         .padding().overlay(Circle().stroke(Color.gray, lineWidth: 3)).opacity(0.6)
   }
   else{
      Button(action: {self.showSearchTrash = 1}){
         Image(systemName: "plus").font(.system(size: 40)).foregroundColor(green)
            .padding().overlay(Circle().stroke(green, lineWidth: 3).scaleEffect(1+self.animationAmount).animation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)).onAppear {self.animationAmount = 0.1})
      }
   }
}.padding(.bottom, 5)

And the intention is that if self.done is false , the circle on the plus button will expand and contract indefinitely.

This works. However, if I use a toggle to set self.done to be true and then turn it back to false , the animation no longer occurs. I know that the issue is not with the toggle, because it does return to being green.

Also, the lack of . before green is intentional - I defined a specific Color green .

Any idea why the animation stops working/how to fix this?

You can specify Animation in the withAnimation block and create separate functions for starting/stopping the animation.

Here is a possible solution:

struct ContentView: View {
    @State private var done = false
    @State private var animationAmount: CGFloat = 0

    var body: some View {
        VStack {
            Toggle("Done", isOn: $done)
            plusImage
                .opacity(done ? 0.6 : 1)
                .foregroundColor(done ? .gray : .green)
        }
        .onAppear(perform: startAnimation)
        .onChange(of: done) { done in
            if done {
                stopAnimation()
            } else {
                startAnimation()
            }
        }
    }
    
    var plusImage: some View {
        Image(systemName: "plus")
            .font(.system(size: 40))
            .padding()
            .overlay(
                Circle()
                    .stroke(Color.gray, lineWidth: 3)
                    .scaleEffect(1 + animationAmount)
            )
    }
}
private extension ContentView {
    func startAnimation() {
        withAnimation(Animation.easeInOut(duration: 1).repeatForever()) {
            animationAmount = 0.1
        }
    }
    
    func stopAnimation() {
        withAnimation {
            animationAmount = 0
        }
    }
}

Actually works fine as-is with Xcode 12.1 / iOS 14.1, so you might observe either bug of new iOS version or result of some other code.

Anyway, I would added turn-offs scaling on button disappear:

Button(action: {}){
    Image(systemName: "plus").font(.system(size: 40)).foregroundColor(green)
        .padding().overlay(Circle().stroke(green, lineWidth: 3).scaleEffect(1+self.animationAmount).animation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)))
}
.onAppear {self.animationAmount = 0.1}    // << put here !!
.onDisappear {self.animationAmount = 0}   // << add this !!

演示

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM