EDIT: Look at my comment in the solution to see what I changed in the updateUIView.
I am trying to update a heatmap I have on my map via a button press.
Here is how the screen looks:
GIF of how the screen and interaction look
I have the array that the Map uses set to an @Binding variable and the array itself is initialized as an @State variable. The original preset values (as can be seen in the code below) appear on the map but the modified coordinate does not.
import SwiftUI
import GoogleMaps
import GoogleMapsUtils
struct GoogleMapsViewContainer: View {
@ObservedObject var locationManager = LocationManager()
@State var heatmapWeightedData: [GMUWeightedLatLng] = [
GMUWeightedLatLng(coordinate: CLLocationCoordinate2D(latitude: -33.86, longitude: 151.20), intensity: 1),
GMUWeightedLatLng(coordinate: CLLocationCoordinate2D(latitude: -33.8623, longitude: 151.2003), intensity: 3),
GMUWeightedLatLng(coordinate: CLLocationCoordinate2D(latitude: -33.8635, longitude: 151.2010), intensity: 3),
GMUWeightedLatLng(coordinate: CLLocationCoordinate2D(latitude: -33.8587, longitude: 151.1970), intensity: 3),
GMUWeightedLatLng(coordinate: CLLocationCoordinate2D(latitude: -33.8579, longitude: 151.1987), intensity: 5)
]
@Environment(.dismiss) var dismiss
var body: some View {
VStack {
HStack {
Spacer()
Button("Done") {
dismiss()
}
.padding(.top, 45.0)
}
.padding(.trailing, 30.0)
ZStack {
GoogleMapsView(heatmapWeightedData: $heatmapWeightedData)
VStack {
Spacer()
Button(action: addTrashLocation) {
Text("Mark Trash in My Area")
}
.padding()
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(/@START_MENU_TOKEN@/Color(hue: 0.373, saturation: 0.717, brightness: 0.466)/@END_MENU_TOKEN@/, lineWidth: 2)
)
.background(.white)
.cornerRadius(30)
.padding(.bottom, 50.0)
}
}
}
.padding(.top, -30)
.ignoresSafeArea()
}
func addTrashLocation() {
self.heatmapWeightedData.append(GMUWeightedLatLng(coordinate: CLLocationCoordinate2D(latitude: -33.8606, longitude: 151.2011), intensity: 5))
}
}
This below is the GoogleMapsView function the above is referencing.
import SwiftUI
import GoogleMaps
import GoogleMapsUtils
struct GoogleMapsView: UIViewRepresentable {
@ObservedObject var locationManager = LocationManager()
var marker: GMSMarker = GMSMarker()
@Binding var heatmapWeightedData: [GMUWeightedLatLng]
func makeUIView(context: Context) -> GMSMapView {
let camera = GMSCameraPosition.camera(withLatitude: locationManager.latitude, longitude: locationManager.longitude, zoom: 15)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
let heatmapLayer = GMUHeatmapTileLayer()
heatmapLayer.radius = 150
heatmapLayer.weightedData = heatmapWeightedData
heatmapLayer.map = mapView
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: UIViewRepresentableContext<GoogleMapsView>) {
marker.position = CLLocationCoordinate2D(latitude: locationManager.latitude, longitude: locationManager.longitude)
marker.title = "My location"
marker.map = mapView
let heatmapLayer = GMUHeatmapTileLayer()
heatmapLayer.radius = 150
heatmapLayer.weightedData = heatmapWeightedData
heatmapLayer.map = mapView
mapView.animate(toLocation: CLLocationCoordinate2D(latitude: -33.86, longitude: 151.20))
}
}
In order to be able to use the Google Maps SDK in SwiftUI, I went through a lot of trouble messing around with UIViewRepresentable and an AI since the internet couldn't help me with my answers. This situation has led me to many problems and I would not be surprised if this is somehow not working due to some nuance in the UIViewRepresentable I am unaware of.
How do I get the map to update the location?
You should use @StateObject
to initialize ObservableObject
s
@StateObject var locationManager = LocationManager()
Then use @ObserveObject
or @EnvironmentObject
to pass around.
@ObservedObject var locationManager : LocationManager
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
Every time you call LocationManager()
you are creating a different instance. One does not know about the other.