1

I am struggling to create an animation of a changing date value. A simplified example is below. It is intended to update the Text view with changing values as the date is updated from its original value to its new value. Help would be most appreciated!

struct DateAnimationView: View {

    @State var date = Date()

    typealias AnimatableData = Date

    var animatableData: Date{
        get{date}
        set{date = newValue}
    }

    var body: some View {
        VStack{
            Text(date, style: .time)
                .padding()
            
            Button(action:{
                withAnimation(.linear(duration: 3.0)){
                    date.addTimeInterval(60 * 60 * 3)
                }
            }){
                Text("Add 3 hours")
            }
                .padding()
            Spacer()
        }
    }
}

Another attempt which also fails:

struct InnerView: View {
    var date: Date
    var interval: TimeInterval
        
    typealias AnimatableData = TimeInterval
    
    var animatableData: TimeInterval{
        get{interval}
        set{interval = newValue}
    }
    
    var body: some View{
        Text(date.addingTimeInterval(interval), style: .time)
    }
}

struct DateAnimationView: View{
    @State var isOn: Bool = false
    var body: some View{
        VStack{
            InnerView(date: Date(), interval: isOn ? 60*60*3 : 0)
            Button(action:{
                isOn.toggle()
            }){
                Text("Go")
            }
        }
    }
}
Rumbles
  • 806
  • 1
  • 8
  • 15

1 Answers1

1

The essential idea is that you need to specify an id for the component you're animating. SwiftUI uses this id to understand if it's the same component or a new component when doing a redraw. If it is a new component, it will remove the old one and add a new with the animation. The code below achieves the animation.

struct DateAnimationView: View {
    @State var date = Date()

    typealias AnimatableData = Date

    var animatableData: Date{
        get{date}
        set{date = newValue}
    }

    var body: some View {
        VStack{
            Text(date, style: .time)
                .padding()
                .id(String(date.hashValue))
            
            Button(action:{
                withAnimation(.linear(duration: 3.0)){
                    date.addTimeInterval(60 * 60 * 3)
                }
            }){
                Text("Add 3 hours")
            }
                .padding()
            Spacer()
        }
    }
}

A similar issue is solved by the solution posted here.

rohanphadte
  • 978
  • 6
  • 19
  • thanks for the quick response. Unfortunately, adding the id does not seem to work as expected. Now the two date values are simply superimposed. To be clear, I am hoping to see the text "count up" time values as it approaches the new time. (ie: 8:13 -> 8:42 -> 9:15 -> 10:22 -> 11:13) – Rumbles Oct 30 '20 at 13:30