Search code examples
iosswiftswiftuicore-graphics

Updating Path in SwiftUI


I have got a SwiftUI View with a chart which is made using Path and data from entries array.

The code:

struct TodayChartView: View {
    var body: some View {
            GeometryReader { reader in
                    Path { p in
                            for i in 1..<entries.count {
                                p.move(to: CGPoint(x: entries[i-1].x, entries[i-1].y: y))
                                p.addLine(to: CGPoint(entries[i].x: x, entries[i].y: y))
                            }
                        }
                    }.stroke(Color.blue, style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round))
                }
}

When user presses the button in another View, a new entry is added to entries and I want to display it on my Path. So, basically, I need to somehow trigger redrawing it. Is there any way to achieve it?


Solution

  • Pass the entries as a parameter to TodayChartView. With the entries as a @State var in ContentView, the TodayChartView gets redrawn whenever entries changes.

    Here is a complete example (tested in Xcode 11.7):

    struct TodayChartView: View {
        let entries: [CGPoint]
        
        var body: some View {
            // GeometryReader { reader in
                Path { p in
                    for i in 1..<self.entries.count {
                        p.move(to: CGPoint(x: self.entries[i-1].x, y: self.entries[i-1].y))
                        p.addLine(to: CGPoint(x: self.entries[i].x, y: self.entries[i].y))
                    }
                }
                .stroke(Color.blue, style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round))
            // }
        }
    }
    
    struct ContentView: View {
        @State private var entries: [CGPoint] = [CGPoint(x: 150, y: 150)]
        
        var body: some View {
            VStack(spacing: 20) {
                Button("Add Point") {
                    let x = CGFloat.random(in: 0...300)
                    let y = CGFloat.random(in: 0...300)
                    self.entries.append(CGPoint(x: x, y: y))
                }
                TodayChartView(entries: self.entries)
                    .frame(width: 300, height: 300)
            }
        }
    }
    

    Note: Your TodayChartView is not currently using GeometryReader so I've commented it out.