Shape does not redraw itself

Viewed 248

How do I redraw Shape with new data when this data is new "source of truth"? The following shows, that only "Text("...") view gets updated with the ObservedObject. The Shape draws itself only once.

import SwiftUI

struct ContentView: View {
    @ObservedObject var cntrl:Controller=Controller()
    var body: some View {
        VStack {
            subviewone(cntrl: cntrl)
            graph(cntrl: cntrl)
                .stroke()
                .fill(Color.red)
            subviewone(cntrl: cntrl)
        }.padding(.all)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct graph: Shape {
    @ObservedObject var cntrl:Controller
    func path(in rect: CGRect) -> Path {
        print("function beeing called")
        return Path { path in
            path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: CGFloat(100-cntrl.test), startAngle: Angle.init(degrees: 0), endAngle: Angle.init(degrees: 360), clockwise: true)
        }
    }


}

struct subviewone: View {
    @ObservedObject var cntrl:Controller
    var body: some View {
        VStack {
            Text("******")
            Text("\(cntrl.test)")
            Text("******")

        }

    }
}

class Controller:ObservableObject {

    @Published var test=0

    init() {
        _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {_ in
            self.test+=1
        }
    }

}

The code works if i omit .stroke() and .fill(Color.red)


struct ContentView: View {
    @ObservedObject var cntrl:Controller=Controller()
    var body: some View {
        VStack {
            subviewone(cntrl: cntrl)
            graph(cntrl: cntrl)
            subviewone(cntrl: cntrl)
        }.padding(.all)
    }
}

Thank you for any suggestions. Libor

2 Answers

try this - tested with 13.4

struct ContentView: View {

    @EnvironmentObject var controller : Controller

    var body: some View {
        VStack {
            subviewone()
                .environmentObject(controller)
            graph(radius: controller.test)
                .stroke()
                .fill(Color.red)
            subviewone()
            .environmentObject(controller)
        }.padding(.all)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
        .environmentObject(Controller())
    }
}

struct graph: Shape {

    @State var radius : CGFloat

    func path(in rect: CGRect) -> Path {
        print("function beeing called")
        return Path { path in
            path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: CGFloat(100-radius), startAngle: Angle.init(degrees: 0), endAngle: Angle.init(degrees: 360), clockwise: true)
        }
    }


}

struct subviewone: View {
    @EnvironmentObject var controller : Controller
    var body: some View {
        VStack {
            Text("******")
            Text("\(controller.test)")
            Text("******")

        }

    }
}

class Controller:ObservableObject {

    @Published var test : CGFloat = 0

    init() {
        _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {_ in
            self.test+=1
        }
    }

}

On Shape, you can never call stroke and fill in one go, because the first calling stroke or fill return a View, no long a Shape.

Related