I have a view modifier which sets the xdomain of a chart. I had this code littered all over the place (multiple charts), so instead tried to consolidate the code.
For some reason it doesn't get called when the chart is rendered when the code is part of the view modifier.
functioning (scattered to each chart) code which updates when chart is updated:
struct MyChart: View {
var body: some View {
Chart {
.... chart stuff...
}
.chartXScale(domain: xdomain())
}
// this will be called time the chart is rendered
func xdomain() -> ClosedRange<Date> {
let now = Date()
let lower = now.addingTimeInterval(-180)
let x = lower...now
return x
}
}
No functioning - The chart domain isn't udpated each time the chart updates - only the first time does it get set
struct DomainModifer: ViewModifier {
func body(content: Content) -> some View {
content.chartXScale(domain: xdomain())
}
}
extension View {
func xdomain() -> some View {
modifier(DomainModifer())
}
}
func xdomain() -> ClosedRange<Date> {
let now = Date()
let lower = now.addingTimeInterval(-180)
let x = lower...now
return x
}
struct MyChart: View {
var body: some View {
Chart {
.... chart stuff...
}
.xdomain() // doesn't update
}
}
As you may know, SwiftUI would run
bodyto find the dependencies (e.g.@State,@Binding,@ObservedObject) of a view. When any of the dependencies change,bodyis run again to find out what has changed and SwiftUI updates the view according to that. The same applies toViewModifiers too, withbody(content:).SwiftUI doesn't treat
Date()as a "dependency". It doesn't make sense for SwiftUI tried to update the view every timeDate()changes, after all. When the chart is updated, SwiftUI sees that none of the dependencies ofDomainModiferhas changed (it literally has no dependencies!), so it doesn't callbody(content:).The first code snippet works because when the chart updates,
MyChart.bodyis executed, and in there you callxdomain(), soxdomain()is called for every update toMyChart.The simplest way to fix this would be to not use a
ViewModifier. Just put all the code in theViewextension:Now
xdomain()will be called whenever you callxDomain(), which you do inbody.You can also keep using the
ViewModifier, but theClosedRange<Date>should be passed from theViewextension.