Home > Software engineering >  In SwiftUI how do I animate changes one at a time when they occur in a called method?
In SwiftUI how do I animate changes one at a time when they occur in a called method?

Time:05-23

Although I get an animation when I tap the button, it's not the animation I want. The entire view is being replaced at once, but I want to see each element change in sequence. I tried in both the parent view and in the called method. Neither produces the desired result.

(this is a simplified version of the original code)

import SwiftUI

struct SequencedCell: Identifiable {
   let id = UUID()
   var value: Int

   mutating func addOne() {
      value  = 1
   }

}

struct AQTwo: View {
   @State var cells: [SequencedCell]

   init() {
      _cells = State(initialValue: (0 ..< 12).map { SequencedCell(value: $0) })
   }

   var body: some View {
      VStack {
         Spacer()
         Button(" ") {
            sequencingMethod(items: $cells)
         }
         .font(.largeTitle)
         Spacer()

         HStack {
            ForEach(Array(cells.enumerated()), id: \.1.id) { index, item in
 //              withAnimation(.linear(duration: 4)) {
               Text("\(item.value)").tag(index)
 //              }
            }
         }
         Spacer()
      }
   }

   func sequencingMethod(items: Binding<[SequencedCell]>) {
      for cell in items {
         withAnimation(.linear(duration: 4)) {
            cell.wrappedValue = SequencedCell(value: cell.wrappedValue.value   1)
           // cell.wrappedValue.addOne()
        }
      }
   }
}


struct AQTwoPreview: PreviewProvider {
   static var previews: some View {
      AQTwo()
   }
}

So I want the 0 to turn into a 1, the 1 then turn into a 2, etc.

Screenshot

CodePudding user response:

As mentioned in the comments, the lowest-tech version is probably just using a DisatpchQueue.main.asyncAfter call:

func sequencingMethod(items: Binding<[SequencedCell]>) {
    var wait: TimeInterval = 0.0
    
    for cell in items {
        DispatchQueue.main.asyncAfter(deadline: .now()   wait) {
            withAnimation(.linear(duration: 1)) {
                cell.wrappedValue = SequencedCell(value: cell.wrappedValue.value   1)
            }
        }
        wait  = 1.0
    }
}
  • Related