How to cluster custom icons markers in GoogleMaps for iOS

I’m developing an app on which I want to show a lot of event on the map. The user can click on an event and see a lot of information about it.
I customized the marker icon of each event with a custom image and now I want to cluster each custom markers.
I’m able to cluster the default icon of GoogleMaps API but if I want to cluster my own marker icon I’m not able to do it.

Here’s my current code :

  • How to make both header and footer in collection view with swift
  • JSON requests in iOS - use Grand Central Dispatch or NSURLConnection
  • Play YouTube videos with MPMoviePlayerController instead of UIWebView
  • Xamarin.Forms IOS Breakpoints Not Hit
  • How to pass the touch event to superview when userInteractionEnabled = YES?
  • Xamarin iOS memory leaks everywhere
  • var mapView: GMSMapView!
    var clusterManager: GMUClusterManager!
    let isClustering: Bool = true
    let isCustom: Bool = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        mapView = GMSMapView(frame: view.frame)
        mapView.camera = GMSCameraPosition.camera(withLatitude: 13.756331, longitude: 100.501765, zoom: 12.0)
        mapView.mapType = .normal
        mapView.delegate = self
        view.addSubview(mapView)
    
        if isClustering {
            var iconGenerator: GMUDefaultClusterIconGenerator!
            if isCustom { // Here's my image if the event are clustered
                var images: [UIImage] = [UIImage(named: "m1.png")!, UIImage(named: "m2.png")!, UIImage(named: "m3.png")!, UIImage(named: "m4.png")!, UIImage(named: "m5.png")!]
                iconGenerator = GMUDefaultClusterIconGenerator(buckets: [5, 10, 15, 20, 25], backgroundImages: images)
            } else {
                iconGenerator = GMUDefaultClusterIconGenerator()
            }
    
            let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
            let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
    
            clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
            clusterManager.cluster()
            clusterManager.setDelegate(self, mapDelegate: self)
        } else {
        }
    
        // Here's my personal marker icon (for one location)
        let firstLocation = CLLocationCoordinate2DMake(48.898902, 2.282664)
        let marker = GMSMarker(position: firstLocation)
        marker.icon = UIImage(named: "pointeurx1") //Apply custom marker
        marker.map = mapView
    
        let secondLocation = CLLocationCoordinate2DMake(48.924572, 2.360207)
        let secondMarker = GMSMarker(position: secondLocation)
        secondMarker.icon = UIImage(named: "pointeurx1")
        secondMarker.map = mapView
    
        let threeLocation = CLLocationCoordinate2DMake(48.841619, 2.253113)
        let threeMarker = GMSMarker(position: threeLocation)
        threeMarker.icon = UIImage(named: "pointeurx1")
        threeMarker.map = mapView
    
        let fourLocation = CLLocationCoordinate2DMake(48.858575, 2.294556)
        let fourMarker = GMSMarker(position: fourLocation)
        fourMarker.icon = UIImage(named: "pointeurx1")
        fourMarker.map = mapView
    
        let fiveLocation = CLLocationCoordinate2DMake(48.873819, 2.295200)
        let fiveMarker = GMSMarker(position: fiveLocation)
        fiveMarker.icon = UIImage(named: "pointeurx1")
        fiveMarker.map = mapView
    }
    
    /// Point of Interest Item which implements the GMUClusterItem protocol.
    class POIItem: NSObject, GMUClusterItem {
        var position: CLLocationCoordinate2D
        var name: String!
    
        init(position: CLLocationCoordinate2D, name: String) {
            self.position = position
            self.name = name
        }
    }
    
    func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) {
        let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: mapView.camera.zoom + 1)
        let update = GMSCameraUpdate.setCamera(newCamera)
        mapView.moveCamera(update)
    }
    }
    

    How can I do it?

    Look at these screenshots of my app then maybe you could understand better my issue.

    First one there are the red default markers icons of the Google Maps, you can see in blue the cluster icon I was added in my project. Then you understand I added some locations on the viewDidLoad(), then the red markers are that. You can also see two others differents markers, the google one is orange and another one is my personal marker icon that I want to use for each marker icon of a location. But you can also see the issue, the issue is the blue cluster icon don’t add the markers icons I added on the map (it shows 4 inside the blue cluster icon, it’s the 4 icons around it but when the blue cluster icon appears the markers icons around it don’t disappear.

    Second image, if I make a zoom, the blue cluster icon disappears but you can also see another issue, the locations I was added have another red default markers icons of the Google Maps appears above them (you can see it at less because of my personal orange marker icon

    Solutions Collect From Internet About “How to cluster custom icons markers in GoogleMaps for iOS”

    You are actually clustering first then adding markers thats why this is happening.

    What you should actually do is

    class MarkerModel: NSObject, GMUClusterItem {
    var position: CLLocationCoordinate2D
    var name: String
    
    init(position: CLLocationCoordinate2D, name: String) {
        self.position = position
        self.name = name
    }
    }
    
    
    override func viewDidLoad() {
    super.viewDidLoad()
    
    mapView = GMSMapView(frame: view.frame)
    mapView.camera = GMSCameraPosition.camera(withLatitude: 13.756331, longitude: 100.501765, zoom: 12.0)
    mapView.mapType = .normal
    mapView.delegate = self
    view.addSubview(mapView)
    
    if isClustering {
        var iconGenerator: GMUDefaultClusterIconGenerator!
        if isCustom { // Here's my image if the event are clustered
            var images: [UIImage] = [UIImage(named: "m1.png")!, UIImage(named: "m2.png")!, UIImage(named: "m3.png")!, UIImage(named: "m4.png")!, UIImage(named: "m5.png")!]
            iconGenerator = GMUDefaultClusterIconGenerator(buckets: [5, 10, 15, 20, 25], backgroundImages: images)
        } else {
            iconGenerator = GMUDefaultClusterIconGenerator()
        }
    
        let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
        let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
    
        clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
    
    } else {
    }
    }
    
    func addMarkers(cameraLatitude : Float, cameraLongitude : Float) {
        let extent = 0.01
        for index in 1...clusterItemCount {
            let lat = cameraLatitude + extent * randomScale()
            let lng = cameraLongitude + extent * randomScale()
            let name = "Item \(index)"
    
            let position = CLLocationCoordinate2DMake(lat, lng)
    
            let item = MarkerModel(position: position, name: name)
            item.icon = #imageLiteral(resourceName: "marker")
            clusterManager.add(item)
        }
         clusterManager.cluster()
            clusterManager.setDelegate(self, mapDelegate: self)
    }
    
    func randomScale() -> Double {
        return Double(arc4random()) / Double(UINT32_MAX) * 2.0 - 1.0
    }
    
    func renderer(_ renderer: GMUClusterRenderer, markerFor object: Any) -> GMSMarker? {
    
        let marker = GMSMarker()
        if let model = object as? MarkerModel {
             // set image view for gmsmarker
        }
    
        return marker
    }
    
    func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
        let newCamera = GMSCameraPosition.camera(withTarget: cluster.position, zoom: mapView.camera.zoom + 1)
        let update = GMSCameraUpdate.setCamera(newCamera)
        mapView.moveCamera(update)
        return false
    }