Google Maps iOS Sdk: Custom Icons to Be Used as Markers

google maps iOS SDK: custom icons to be used as markers

Here is what I have done

let marker = GMSMarker()

// I have taken a pin image which is a custom image
let markerImage = UIImage(named: "mapMarker")!.withRenderingMode(.alwaysTemplate)

//creating a marker view
let markerView = UIImageView(image: markerImage)

//changing the tint color of the image
markerView.tintColor = UIColor.red

marker.position = CLLocationCoordinate2D(latitude: 28.7041, longitude: 77.1025)

marker.iconView = markerView
marker.title = "New Delhi"
marker.snippet = "India"
marker.map = mapView

//comment this line if you don't wish to put a callout bubble
mapView.selectedMarker = marker

The output is

Sample Image

And my marker image was

Sample Image

You can change your color as per your need. Also if you want something in rectange, you can just create a simple small rectangular image and use it like I did above and change the color of your need.

Or if you want a rectangle with text within it, you can just create a small UIView with some label and then convert that UIView in UIImage and can do the same thing.

//function to convert the given UIView into a UIImage
func imageWithView(view:UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}

Hope it helps!!

Custom Google Maps Marker View

It is turned out that I have to use the Icon property only.
And in order to accomplish my goal a have to render two images into one using Graphics Context.

Google Maps iOS is not allowing custom map marker image

I haven't figured out why the utils library wasn't working, but I did come up with my own fix. It's horrible, but I can come back and make it better later after we've finished adding all the other necessary features to the app and can focus on cleaning up the code .

First, I made a new array of placemarks that had everything except the map markers. I then used this array of placemarks instead of kmlParser.placemarks, so that everything else could be added by the utility library.

//Removing markers without icons
var myIndex = 0
var removed = [GMUGeometryContainer]()
for mark in kmlParser.placemarks{
if(mark.geometry.type != "Point"){
removed.append(kmlParser.placemarks[myIndex])
}
myIndex += 1
}

let renderer = GMUGeometryRenderer(map: mapView, geometries: removed, styles: kmlParser.styles, styleMaps: kmlParser.styleMaps)
renderer.render()

After that, I made my own horrible horrible method that reads the kml file again, and only picks out the placemarks and styles for them and returns an array of Markers.

func addMarkers(fileName:String) -> [GMSMarker]{
var markers = [GMSMarker]()
if let path = Bundle.main.path(forResource: fileName, ofType: "kml"){
do{
let data = try String(contentsOfFile: path, encoding: .utf8)
let myStrings = data.components(separatedBy: .newlines)
var styleToIcon = [String: String]()

var lineNum = 0
for line in myStrings{
//Detecting new style that will be used in placemarks
if line.contains("Style id") && line.contains("normal") && !line.contains("line-"){
let newKey = String(line.split(separator: "\"")[1])
let newValue = String(myStrings[lineNum+4].split(separator: ">")[1].split(separator: "/")[1].split(separator: "<")[0])
styleToIcon[newKey] = newValue
}

//Detecting new placemark on map
else if(line.contains("<Placemark>") && !myStrings[lineNum+2].contains("#line")){
//Get name
var name = myStrings[lineNum+1].split(separator: ">")[1].split(separator: "<")[0]
//Sometimes name has weird CDATA field in it that needs to be removed
if(name.contains("![CDATA")){
name = name.split(separator: "[")[2].split(separator: "]")[0]
}

//Get snippet (description)
var snippet = myStrings[lineNum+2].split(separator: ">")[1].split(separator: "<")[0]
//Sometimes snippet has weird CDATA field in it that needs to be removed
if(snippet.contains("![CDATA")){
snippet = snippet.split(separator: "[")[2].split(separator: "]")[0]
}

//Get style
let style = String(myStrings[lineNum+3].split(separator: ">")[1].split(separator: "#")[0].split(separator: "<")[0] + "-normal")

//Get Coordinates
let coordStringSplit = myStrings[lineNum+6].split(separator: ",")
var lat = 0.0
var long = 0.0
if(coordStringSplit[0].contains("-")){
long = Double(coordStringSplit[0].split(separator: "-")[1])! * -1.0
}else{
long = Double(coordStringSplit[0])!
}
if(coordStringSplit[1].contains("-")){
lat = Double(coordStringSplit[1].split(separator: "-")[1])! * -1.0
}else{
lat = Double(coordStringSplit[1])!
}

//Create marker and add to list of markers
let position = CLLocationCoordinate2D(latitude: lat, longitude: long)
let marker = GMSMarker(position: position)
marker.title = String(name)
marker.snippet = String(snippet)
marker.icon = UIImage(named: styleToIcon[style]!)
markers.append(marker)
}
lineNum += 1
}
}catch{
print(error)
}
}
return markers
}

This is so heavily related to how my kml files look that I doubt it will help anyone else, but I thought I should post it just in case.

Now that we have that method, all we need to do is go back to where we were rendering all of the kml data and render those markers on the map

//Adding markers with icons
let newMarkers = addMarkers(fileName: courseName)
for mark in newMarkers{
mark.map = mapView
}

I also had to go through my kml files manually and fix some of the image names, but that wasn't a big deal. Even if the utility library worked I would need to do that because the utility library only does kml files and not kmz, so each kml file references the same folder for images and uses the same names for images. It's fine, only takes a few minutes per file. Would be nice if there was a kmz library but oh well.

Hopefully this helps someone else, and hopefully I can find the real solution soon (unless its a problem with the utility library in which case hopefully it's fixed soon).

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
}


Related Topics



Leave a reply



Submit