Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

animate path stroke drawing in SwiftUI

Tags:

swift

swiftui

To animate a path in the past I could do something like this:

let pathLayer = CAShapeLayer()
let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathLayer.path = path.cgPath
pathAnimation.duration = 0.3
pathAnimation.fromValue = 0
pathAnimation.toValue = 1
pathLayer.add(pathAnimation, forKey: "strokeEnd")

Using SwiftUI, I don't see a way to use CABasicAnimation. How would I animate the drawing of the following path, using SwiftUI?

struct AnimationView: View {
    var body: some View {
        GeometryReader { geo in
            MyLines(height: geo.size.height, width: geo.size.width)
        }
    }
}

struct MyLines: View {
    var height: CGFloat
    var width: CGFloat
    var body: some View {

        ZStack {
            Path { path in
                path.move(to: CGPoint(x: 0, y: height/2))
                path.addLine(to: CGPoint(x: width/2, y: height))
                path.addLine(to: CGPoint(x: width, y: 0))
            }
            .stroke(Color.black, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))

        }
    }
}
like image 973
DevB2F Avatar asked Dec 03 '22 09:12

DevB2F


1 Answers

Re-tested: Xcode 13.4 / iOS 15.5

enter image description here

It can be used .trim with animatable end, like below with your modified code

struct MyLines: View {
    var height: CGFloat
    var width: CGFloat

    @State private var percentage: CGFloat = .zero
    var body: some View {

        // ZStack {         // as for me, looks better w/o stack which tighten path
            Path { path in
                path.move(to: CGPoint(x: 0, y: height/2))
                path.addLine(to: CGPoint(x: width/2, y: height))
                path.addLine(to: CGPoint(x: width, y: 0))
            }
            .trim(from: 0, to: percentage) // << breaks path by parts, animatable
            .stroke(Color.black, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
            .animation(.easeOut(duration: 2.0), value: percentage) // << animate
            .onAppear {
                self.percentage = 1.0 // << activates animation for 0 to the end
            }

        //}
    }
}
like image 191
Asperi Avatar answered Dec 30 '22 09:12

Asperi