Search code examples
swiftuiswiftui-animationswiftdataswiftui-charts

SwiftData Swift Charts and SwiftUI Animation


Why the animation only work in the non-SwiftData version?

@State and @Model are equivalent, isn't it?

non-SwiftData:

import SwiftUI
import Charts

struct Entry: Identifiable {
    var id = UUID()
    var time: Double
    var value: Double
}

struct ContentView: View {
    @State var data: [Entry] = [
        .init(time: 0, value: 0),
        .init(time: 1, value: 1)]
    var body: some View {
        VStack{
            Button("+"){
                withAnimation{
                    data.append(.init(time: 2, value: 3))
                }
            }
            Chart(data){entry in
                LineMark(x: .value("time", entry.time),
                         y: .value("value", entry.value))
            }
            .chartXScale(domain: 0...3)
            .chartYScale(domain: 0...3)
            .padding()
        }
    }
}

SwiftData:

import SwiftUI
import SwiftData
import Charts

@Model
class Entry {
    var time: Double
    var value: Double
    init(time: Double, value: Double) {
        self.time = time
        self.value = value
    }
}

struct ContentView: View {
    @Query(sort:\Entry.time) private var data: [Entry]
    @Environment(\.modelContext) private var modelContext
    var body: some View {
        VStack{
            Button("+"){
                withAnimation{
                    modelContext.insert(Entry(time: 2, value: 3))
                }
            }
            Chart(data){entry in
                LineMark(x: .value("date", entry.time),
                         y: .value("value", entry.value))
            }
            .padding()
        }
        .onAppear{
            modelContext.insert(Entry(time:0, value:0))
            modelContext.insert(Entry(time:1, value:1))
        }
    }
}

Solution

  • State and Model are two very different things, one is a Macro and the other is a source of truth. Model types use State as a source of truth.

    You can use

    .animation(.easeIn, value: data)
    

    To trigger an animation