swiftgoogle-maps-markersgoogle-maps-sdk-iosinfowindow

GMSMarker infoWindow - data not updating


What I am trying to accomplish is to refresh the map every X seconds. When doing so, I want to update the content of info window of selected marker. However, the marker data is updated (tried with lat/lng), but the info window data stays the same. How can I update the info window data, without having to recreate it?

If I always recreate the info window (re-select the marker), the info window content changes, but user experience is awful, as info window is blinking.

The code for updating marker data

private func updateMarker(index: Int, markerData: MarkerData, select: Bool) {
    markersOnMap[index].title = markerData.time.description
    
    if markersOnMap[index].hasChangedPosition(markerData: markerData) {
        markersOnMap[index].position = markerData.getPosition()
        
        UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
    }
    
    //Info window is recreated, but the UI is awful
    //if select {
        //mapView?.selectedMarker = nil
        //mapView?.selectedMarker = markersOnMap[index]
    //}
}

Code to create the marker and add it to the map:

private func addMarker(markerData: MarkerData, select: Bool) {
    let marker = GMSMarker()
    marker.map = mapView
    marker.position = markerData.getPosition()
    marker.userData = markerData.tranId
    marker.title = markerData.time.description
    marker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
    if select == true {
        //Where markerInfoWindow is created
        marker.icon = UIImage(named: MyImages.markerIcon)
        marker.tracksInfoWindowChanges = true
        mapView?.selectedMarker = marker
    } else {
        marker.iconView = getMyIconView(posTime: markerData.time)
    }
    
    markersOnMap.append(marker)
}

Info window creation

func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
    let posTime = CLong(marker.title ?? "0") ?? 0

    var rect = CGRect(x: 0, y: 0, width: 150, height: 140)
    
    let hostingController = UIHostingController(rootView: MyInfoView(device: device, posTime: posTime))
    
    hostingController.view.frame = rect
    hostingController.view.backgroundColor = .clear
    return hostingController.view
}

Solution

  • Since it was not possible to accomplish the desired behaviour with marker update, I compromised with the hostingController. I converted it into local variable, which is initialized once the marker info window is created. Every time I want to update the info window data, I use the instance of hosting controller to do so.

    Init the hostingController

    func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
        let posTime = CLong(marker.title ?? "0") ?? 0
        
        hostingController = UIHostingController(rootView: MyInfoView(device: device, posTime: posTime))
        
        hostingController?.view.frame = CGRect(x: 0, y: 0, width: 150, height: 140)
        hostingController?.view.backgroundColor = .clear
        return hostingController?.view
    }
    

    Update info window data (posTime in this case)

    private func updateMarker(index: Int, markerData: MarkerData, select: Bool) {
        markersOnMap[index].title = markerData.time.description
        
        if markersOnMap[index].hasChangedPosition(markerData: markerData) {
            markersOnMap[index].position = markerData.getPosition()
            
            UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
        }
        
        if select {
            hostingController?.rootView.posTime = markerData.time
        }
    }