How to implement GMUClusterRenderer in Swift

I am using the Google Maps API for iOS and want to use the marker clustering utility. I figured out how to show cluster tokens, but I would like to set up tokens. Can someone explain how to set / change the icon and name of each marker or cluster marker? Sample code will be very helpful.

class POIItem: NSObject, GMUClusterItem {
    var position: CLLocationCoordinate2D
    var name: String!

    init(position: CLLocationCoordinate2D, name: String) {
        self.position = position
        self.name = name
    }
}

class MyRenderer: NSObject, GMUClusterRenderer {
    var mapView: GMSMapView
    var clusterIconGenerator: GMUClusterIconGenerator
    var clusterManager: GMUClusterManager

    init(mapView: GMSMapView, clusterIconGenerator: GMUClusterIconGenerator, clusterManager: GMUClusterManager) {
        self.mapView = mapView
        self.clusterIconGenerator = clusterIconGenerator
        self.clusterManager = clusterManager
    }

    func renderClusters(clusters: [GMUCluster]) {

    }

    func update() {

    }
}

This is what I still have. I do not know what to do with renderClusters and update functions.

+6
source share
5 answers

If you included the source files of Google-Maps-iOS-Utils in your project, there is one “dirty” way to change the marker icon.

, , .

Google Map Utils/Clustering/View/GMUDefaultClusterRenderer.m

 - (void)renderCluster:(id<GMUCluster>)cluster animated:(BOOL)animated {
 ...

      GMSMarker *marker = [self markerWithPosition:item.position
                                              from:fromPosition
                                          userData:item
                                       clusterIcon:[UIImage imageNamed:@"YOUR_CUSTOM_ICON"]
                                          animated:shouldAnimate];
 ...

}

(Swift)

 private func setupClusterManager() {
        let iconGenerator = GMUDefaultClusterIconGenerator()
        let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
        let renderer = GMUDefaultClusterRenderer(mapView: mapView,
                                                 clusterIconGenerator: iconGenerator)


        clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm,
                                           renderer: renderer)

}
+1

Swift 4, :

class MapClusterIconGenerator: GMUDefaultClusterIconGenerator {

    override func icon(forSize size: UInt) -> UIImage {
        let image = textToImage(drawText: String(size) as NSString,
                                inImage: UIImage(named: "cluster")!,
                                font: UIFont.systemFont(ofSize: 12))
        return image
    }

    private func textToImage(drawText text: NSString, inImage image: UIImage, font: UIFont) -> UIImage {

        UIGraphicsBeginImageContext(image.size)
        image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))

        let textStyle = NSMutableParagraphStyle()
        textStyle.alignment = NSTextAlignment.center
        let textColor = UIColor.black
        let attributes=[
            NSAttributedStringKey.font: font,
            NSAttributedStringKey.paragraphStyle: textStyle,
            NSAttributedStringKey.foregroundColor: textColor]

        // vertically center (depending on font)
        let textH = font.lineHeight
        let textY = (image.size.height-textH)/2
        let textRect = CGRect(x: 0, y: textY, width: image.size.width, height: textH)
        text.draw(in: textRect.integral, withAttributes: attributes)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result!
    }

}

:

private func setupClustering() {
    guard let mapView = self.mapView else { return }

    let iconGenerator = MapClusterIconGenerator()
    let renderer = MapClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
}

MapClusterRenderer.

+7

"" , . !

1) .h "MarkerManager"

    #import <Foundation/Foundation.h>
@import CoreLocation;
#import "GMUClusterItem.h"
#import <GoogleMaps/GoogleMaps.h>


@interface MarkerManager: NSObject

@property (nonatomic) CLLocationCoordinate2D location;
@property (nonatomic, strong) GMSMarker *marker;

@end

2) GMUDefaultClusterRenderer Google-Maps-iOS-Utils, MarkerManager.h :

// Returns a marker at final position of |position| with attached |userData|.
// If animated is YES, animates from the closest point from |points|.
- (GMSMarker *)markerWithPosition:(CLLocationCoordinate2D)position
                             from:(CLLocationCoordinate2D)from
                         userData:(id)userData
                      clusterIcon:(UIImage *)clusterIcon
                         animated:(BOOL)animated {
  GMSMarker *marker = [self markerForObject:userData];
  CLLocationCoordinate2D initialPosition = animated ? from : position;
  marker.position = initialPosition;
  marker.userData = userData;
  if (clusterIcon != nil) {
    marker.icon = clusterIcon;
    marker.groundAnchor = CGPointMake(0.5, 0.5);
  }
  //added
  else {
      MarkerManager *data = userData;
      if(data != nil) {
          marker.icon = data.marker.icon;
      }
  }
  //ends here

  marker.zIndex = _zIndex;

  if ([_delegate respondsToSelector:@selector(renderer:willRenderMarker:)]) {
    [_delegate renderer:self willRenderMarker:marker];
  }
  marker.map = _mapView;

  if (animated) {
    [CATransaction begin];
    [CATransaction setAnimationDuration:kGMUAnimationDuration];
    marker.layer.latitude = position.latitude;
    marker.layer.longitude = position.longitude;
    [CATransaction commit];
  }

  if ([_delegate respondsToSelector:@selector(renderer:didRenderMarker:)]) {
    [_delegate renderer:self didRenderMarker:marker];
  }
  return marker;
}

3) swift, POIItem:

class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
@objc var marker: GMSMarker!


init(position: CLLocationCoordinate2D, marker: GMSMarker) {
    self.position = position
    self.marker = marker
}
}

4) GMUDefaultClusterRenderer markerWithPosition:

import Foundation
import UIKit

class CustomMarkers: GMUDefaultClusterRenderer {
    var mapView:GMSMapView?
    let kGMUAnimationDuration: Double = 0.5

    override init(mapView: GMSMapView, clusterIconGenerator iconGenerator: GMUClusterIconGenerator) {

        super.init(mapView: mapView, clusterIconGenerator: iconGenerator)
    }

    func markerWithPosition(position: CLLocationCoordinate2D, from: CLLocationCoordinate2D, userData: AnyObject, clusterIcon: UIImage, animated: Bool) -> GMSMarker {
        let initialPosition = animated ? from : position
        let marker = GMSMarker(position: initialPosition)
        marker.userData! = userData
        if clusterIcon.cgImage != nil {
            marker.icon = clusterIcon
        }
        else {
            marker.icon = self.getCustomTitleItem(userData: userData)

        }
        marker.map = mapView
        if animated
        {
            CATransaction.begin()
            CAAnimation.init().duration = kGMUAnimationDuration
            marker.layer.latitude = position.latitude
            marker.layer.longitude = position.longitude
            CATransaction.commit()
        }
        return marker
    }

    func getCustomTitleItem(userData: AnyObject) -> UIImage {
        let item = userData as! POIItem
        return item.marker.icon!
    }
}

5) MapViewController init POIItem generateClusterItems:

private func generateClusterItems() {

        for object in DataManager.sharedInstance.mapItemsArray {

            let doubleLat = Double(object.latitude)
            let doubleLong = Double(object.longitude)
            let latitude = CLLocationDegrees(doubleLat!)
            let longitude = CLLocationDegrees(doubleLong!)
            let position = CLLocationCoordinate2DMake(latitude, longitude)
            let marker = GMSMarker(position: position)
            let item = POIItem(position: position, marker: marker)
            self.clusterManager.add(item)                
            item.mapItem = object

        }
    }

for :

marker.icon = UIImage(named:"YOUR_IMAGE_NAME")

, .

+6

Swift 4.2 :

GMUClusterRendererDelegate:

, GMUClusterRendererDelegate:

willRenderMarker , ( clusterItemMarker, if). ..,

extension YourController: GMUClusterRendererDelegate {
    func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
        // if your marker is pointy you can change groundAnchor
        marker.groundAnchor = CGPoint(x: 0.5, y: 1)
        if  let markerData = (marker.userData as? PersonMarker) {
           let icon = markerData.imageURL
           marker.iconView = CustomMarkerView(forUrl: url)
        }
    }
}

PersonMarker - , NSObject GMUClusterItem: ( GMUClusterItem, , )

class PersonMarker: NSObject, GMUClusterItem {

  var position: CLLocationCoordinate2D
  var imageURL : String?
  var name: String?
  var userdId: String?
  var lastSeen: String?

  init(position: CLLocationCoordinate2D, url: String?, name: String?, userId: String?, lastSeen: String?) {
      self.position = position
      self.imageURL = url
      self.name = name
      self.userdId = userId
      self.lastSeen = lastSeen
  }

}

PersonMarker GMUClusterManager :

 let position = CLLocationCoordinate2D(latitude: item.latitude!, longitude: item.longitute!)
 let person = PersonMarker(position: position, url: item.user?.avaterUrl, name: item.user?.name, userId: item.user?.userId, lastSeen: item.lastUpdate)
 clusterManager.add(person)
+2

, .

1)

class HFDashBordVC: UIViewController,GMUClusterManagerDelegate,GMSMapViewDelegate{

  private var clusterManager: GMUClusterManager!

 var cameraPosition = GMSCameraPosition()
var markerPin = GMSMarker()
var currentLocationCircle = GMSCircle()
var locationManager = CLLocationManager()
var currentLocation: CLLocation?
var zoomLevel: Float = 18.0

@IBOutlet var mapView: GMSMapView!

override func viewDidLoad() {
    super.viewDidLoad()

    setupClustering()
}

 func setupClustering() {
    let iconGenerator = CustomClusterIconGenerator()
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    let renderer = CustomRendererMarkers(mapView: mapView,
                                         clusterIconGenerator: iconGenerator)
    clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm,
                                       renderer: renderer)
    clusterManager.cluster()
    clusterManager.setDelegate(self, mapDelegate: self)
}

private func setClusterParkingPin() {

    clusterManager.clearItems()
    for object in AppUtilites.sharedInstance.safeParkingArray {

        let model = object as! AMParkModel
        let lat = Double(model.latitude)!
        let lng = Double(model.longitude)!
        let position = CLLocationCoordinate2DMake(lat, lng)
        let marker = GMSMarker(position: position)
        marker.icon = HFAsset.ic_p_pin_orange.image 
        let userData = model
        let item = POIItem(position: position, marker: marker, userData: userData)
        self.clusterManager.add(item)
        self.setCurrentPin(zoomLevel: 14.0)

    }
}

2)

 class POIItem: NSObject, GMUClusterItem {
        var position: CLLocationCoordinate2D
       var userData: AnyObject!
       @objc var marker: GMSMarker!


  init(position: CLLocationCoordinate2D, marker: GMSMarker, userData: AnyObject) {
    self.position = position
    self.marker = marker
    self.userData = userData
   }
 }

3)

  class CustomRendererMarkers: GMUDefaultClusterRenderer {
var mapView:GMSMapView?
let kGMUAnimationDuration: Double = 0.5

override init(mapView: GMSMapView, clusterIconGenerator iconGenerator: GMUClusterIconGenerator) {

    super.init(mapView: mapView, clusterIconGenerator: iconGenerator)
}

func markerWithPosition(position: CLLocationCoordinate2D, from: CLLocationCoordinate2D, userData: AnyObject, clusterIcon: UIImage, animated: Bool) -> GMSMarker {
    let initialPosition = animated ? from : position
    let marker = GMSMarker(position: initialPosition)
    marker.userData! = userData
    if clusterIcon.cgImage != nil {
        marker.icon = clusterIcon
    }
    else {
        marker.icon = self.getCustomTitleItem(userData: userData)

    }
    marker.map = mapView
    if animated
    {
        CATransaction.begin()
        CAAnimation.init().duration = kGMUAnimationDuration
        marker.layer.latitude = position.latitude
        marker.layer.longitude = position.longitude
        CATransaction.commit()
    }
    return marker
}

func getCustomTitleItem(userData: AnyObject) -> UIImage {
    let item = userData as! POIItem
    return item.marker.icon!
 }
}

4)

class CustomClusterIconGenerator: GMUDefaultClusterIconGenerator {

override func icon(forSize size: UInt) -> UIImage {
    let image = textToImage(drawText: (String(size) as NSString) as String,
                            inImage: HFAsset.ic_parking_clustering.image,
                            font: UIFont.init(name: "Montserrat-Medium", size: 12.0)!)
    return image
}

private func textToImage(drawText text: String, inImage image: UIImage, font: UIFont) -> UIImage {
    var pinCount = text
    if Int(text)! > 9999 {
        pinCount = "+9999"
    }

    UIGraphicsBeginImageContext(image.size)
    image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))

    let textStyle = NSMutableParagraphStyle()
    textStyle.alignment = NSTextAlignment.center
    let textColor = UIColor.white
    let attributes=[
        NSAttributedStringKey.font: font,
        NSAttributedStringKey.paragraphStyle: textStyle,
        NSAttributedStringKey.foregroundColor: textColor,
        NSAttributedStringKey.backgroundColor: appThemeColor]

    // vertically center (depending on font)
    let textH = font.lineHeight
    let textY = (image.size.height-textH)/3
    let textRect = CGRect(x: 0, y: textY, width: image.size.width, height: textH)
    pinCount.draw(in: textRect.integral, withAttributes: attributes)
    let result = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return result!
  }

 }

6)

    func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    if markerPin == marker {
        return true
    }

    if ((marker.userData as? GMUStaticCluster) != nil) {   // Cluster Pin tap
        UIView.animate(withDuration: 0.5, delay: 0.2, options: [.curveEaseOut],
                       animations: {
                        let newCamera = GMSCameraPosition.camera(withTarget: marker.position,
                                                                 zoom: self.mapView.camera.zoom + 0.8)
                        let update = GMSCameraUpdate.setCamera(newCamera)
                        self.mapView.animate(with: update)
        }, completion: {
            finished in
        })
    }

    if let poiItem = marker.userData as? POIItem {   // Cluster Parking Pin tap
        let Detail = self.storyboard?.instantiateViewController(withIdentifier: "HFParkingFullDetailsVC")as! HFParkingFullDetailsVC
        Detail.parkModel = (poiItem.userData as? AMParkModel)!
        self.navigationController?.pushViewController(Detail, animated: true)
    }
0

Source: https://habr.com/ru/post/1648900/


All Articles