Why state change causes jumpy animation?

I've posted this issue originally at ( https://stackoverflow.com/questions/61830571/whats-causing-swiftui-nested-view-items-jumpy-animation-after-the-initial-drawi ), where I describe an issue that I've encountered why developing a list of progress state animations for audio players.


You can find the issue by following the steps:

- Add player
- Add player
- Add player
- Stop All (*the animations played well this far)
- Play All (*same issue as previously documented)
- Add player (*the tail player animation works fine)



// SwiftUIPlayground
import SwiftUI

struct PlayerLoopView: View {
    @ObservedObject var player: MyPlayer

    var body: some View {
        ZStack {
            Circle()
                .stroke(style: StrokeStyle(lineWidth: 10.0))
                .foregroundColor(Color.purple)
                .opacity(0.3)
                .overlay(
                    Circle()
                        .trim(
                            from: 0,
                            to: player.isPlaying ? 1.0 : 0.0
                        )
                        .stroke(
                            style: StrokeStyle(lineWidth: 10.0, lineCap: .round, lineJoin: .round)
                        )
                        .animation(
                            player.isPlaying ?
                                Animation
                                .linear(duration: player.duration)
                                .repeatForever(autoreverses: false) :
                                .none
                        )
                        .rotationEffect(Angle(degrees: -90))
                        .foregroundColor(Color.purple)
                )
        }
        .frame(width: 100, height: 100)
        .padding()
    }
}

struct PlayersProgressView: View {
    @ObservedObject var engine = Engine()

    var body: some View {
        NavigationView {
            VStack {
                ForEach(self.engine.players) { player in
                    HStack {
                        Text("Player")
                        PlayerLoopView(player: player)
                    }
                }
            }
            .navigationBarItems(trailing:
                VStack {
                    Button("Add Player") {
                        self.engine.addPlayer()
                    }
                    Button("Play All") {
                        self.engine.playAll()
                    }
                    Button("Stop All") {
                        self.engine.stopAll()
                    }
                }.padding()
            )
        }
    }
}

class MyPlayer: ObservableObject, Identifiable {
    var id = UUID()
    @Published var isPlaying: Bool = false
    var duration: Double = 1
    func play() {
        self.isPlaying = true
    }
    func stop() {
        self.isPlaying = false
    }
}

class Engine: ObservableObject {
    @Published var players = [MyPlayer]()

    func addPlayer() {
        let player = MyPlayer()
        players.append(player)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
            player.isPlaying = true
        }
    }
   
    func stopAll() {
        self.players.forEach { $0.stop() }
    }
   
    func playAll() {
        self.players.forEach { $0.play() }
    }
}

struct PlayersProgressView_Previews: PreviewProvider {
    static var previews: some View {
        PlayersProgressView()
    }
}