How do I animate changes one at a time in SwiftUI on a button tap?

I have a loop where I update a value that changes the view.
In this example I want the updates to happen one at a time so you see it ripple across the row, but they all happen at once.

struct AnimationQuestion: View {
   @State var colors = "🟪🟨🟧🟦🟥🟫⬛️🟩⬜️".map { String($0) }
   @State var reversedColors = "⬜️🟩⬛️🟫🟥🟦🟧🟨🟪".map { String($0) }

   var body: some View {
      VStack {
         Spacer()
         Button("Tap") {
            let temp = colors
            for i in 0 ..< colors.count {
               withAnimation(.linear(duration: 4.0)) {
                  colors[i] = reversedColors[i]
               }
            }
            reversedColors = temp
            
         }
         Spacer()

         HStack {
            ForEach(Array(colors.enumerated()), id: \.0) { index, color in
               Text(color).tag(index)
            }
         }
         Spacer()
      }
   }
}

struct QuestionPreview: PreviewProvider {
   static var previews: some View {
      AnimationQuestion()
   }
}

I expected these lines to perform the animation sequentially (visibly):

    withAnimation(.linear(duration: 4.0)) {
         colors[i] = reversedColors[i]
    }

>Solution :

You identify by index \.0, but indices do not change after reversing, so refresh is instant, instead you need to identify by color value \.1 (in this case they are unique).

Here is a fix

enter image description here

ForEach(Array(colors.enumerated()), id: \.1) { index, color in
   Text(color).tag(index)
}

Tested with Xcode 13.3 / iOS 15.4

Leave a Reply