rayaantaneja
rayaantaneja

Reputation: 1748

How to animate a Path without creating a SubView in SwiftUI

Is it possible to animate a Path without creating a SubView?

Eg.

struct ContentView: View {
    @State private var end = 0.0
        
    var body: some View {
        VStack {
            Button("Press me") {
                withAnimation {
                    end += 100
                }
            }
           
            Path { path in
                path.move(to: .zero)
                path.addLine(to: CGPoint(x: end, y: end))
            }
            .stroke()
        }
    }
}

I know we can extract the Path into a SubView and use the animatableData property to animate it, however, I was wondering if this is achievable without doing that (animating the Path directly).

What I've tried: I thought making ContentView animatable and using the required animatableData property within ContentView itself would help.

Eg.

struct ContentView: View {
    @State private var end = 0.0

    var animatableData: Double {
        get { end }
        set { end = newValue }
    }
        
    var body: some View {
        VStack {
            Button("Press me") {
                withAnimation {
                    end += 100
                }
            }
           
            Path { path in
                path.move(to: .zero)
                path.addLine(to: CGPoint(x: end, y: end))
            }
            .stroke()
        }
    }
}

This didn't work unfortunately. I also tried adding .animation modifiers to Path but that still didn't do the job.

Is it possible to animate this Path without wrapping it in a Shape or a different type of SubView? I wan't to be able to change end and have the change be animated without wrapping the Path in a different view.

Thanks in advance!

Upvotes: 0

Views: 158

Answers (1)

Toseef Khilji
Toseef Khilji

Reputation: 17419

You can use .trim modifier with .animation modifier.

struct PathAnimationView: View {
    @State private var end = 0.0
    @State private var trimStart: CGFloat = 0
    @State private var trimEnd: CGFloat = 0

    var body: some View {
        VStack {
            Button("Press me") {
                withAnimation {
                    trimStart = 0.0
                    end += 100
                    trimEnd = 1
                }
            }
            Path { path in
                path.move(to: .zero)
                path.addLine(to: CGPoint(x: end, y: end))
            }
            .trim(from: trimStart, to: trimEnd)
            .stroke()
            .animation(.easeOut(duration: 1.0), value: 1)
        }
    }
}

Limitation: .trim will animate path from start to end once.

So better user Shape class to do this.

Upvotes: 1

Related Questions