Benjamin Creem
Benjamin Creem

Reputation: 95

Google Maps iOS is not allowing custom map marker image

I am using the Google Maps SDK for iOS - https://developers.google.com/maps/documentation/ios-sdk/marker#use_the_markers_icon_property

Combined with the Maps SDK for iOS Utility Library https://developers.google.com/maps/documentation/ios-sdk/utility/kml-geojson#render-kml-data

I am trying to use the utility library to render a kml file on a map. It mostly works, however the custom icons for the markers are not loading. The markers with their titles, snippets, and locations all load correctly. The only thing that does not work is the custom icon for the marker.

Originally, I thought it was an issue with the utility library, so I spent some time trying to write my own code to go through the kml file and add the custom markers myself. However, before I got too far I noticed that even when I try to add a basic marker with a custom icon, I cannot. This led me to believe it was an issue not with the utility library but with the Maps SDK for iOS. I've tried moving the folder that the image is in, and making sure that the code can see the path to the images, but I cannot get it to work.

This is the code that I have in my project

let path = Bundle.main.path(forResource: testFile, ofType: "kml")
let url = URL(fileURLWithPath: path!)
let kmlParser = GMUKMLParser(url: url)
kmlParser.parse()

let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: long, zoom: zoom)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.mapType = GMSMapViewType.terrain
mapView.isMyLocationEnabled = true
mapView.settings.zoomGestures = true
mapView.settings.myLocationButton = true

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

This also does not work

let position = CLLocationCoordinate2D(latitude: lat, longitude: long)
let marker = GMSMarker(position: position)
marker.title = "Test"
marker.icon = UIImage(named: "icon-1")
marker.map = mapView

Thanks in advance for any help

Upvotes: 1

Views: 1831

Answers (2)

Davender Verma
Davender Verma

Reputation: 573

//call method by passing ;

 if userLocation.coordinate.latitude != 0.0 && userLocation.coordinate.longitude != 0.0
  {
               self.updateCurrentPositionMarker(currentLocation: CLLocation(latitude: userLocation.coordinate.latitude, longitude:userLocation.coordinate.longitude))

  }


//methods


func updateCurrentPositionMarker(currentLocation: CLLocation) {
        self.currentPositionMarker.map = nil
        self.currentPositionMarker = GMSMarker(position: currentLocation.coordinate)

        if self.imageDataUrl != ""
        {

            let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: currentLocation.coordinate.latitude, longitude: currentLocation.coordinate.longitude, zoom: 18.0)
            self.mapView.camera = camera

//self.imageDataUrl  == image to show

            self.currentPositionMarker.iconView = self.drawImageWithProfilePic(urlString:self.imageDataUrl,image: UIImage.init(named: “backgroungImage”)!)

            self.currentPositionMarker.zIndex = 1

        }

        self.currentPositionMarker.map = self.mapView

        self.mapView.reloadInputViews()
    }




    func drawImageWithProfilePic(urlString:String, image: UIImage) -> UIImageView {

        let imgView = UIImageView(image: image)
        imgView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)

        let picImgView = UIImageView()
        picImgView.sd_setImage(with:URL(string: urlString))
        picImgView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
        imgView.addSubview(picImgView)

        picImgView.center.x = imgView.center.x
        picImgView.center.y = imgView.center.y-10
        picImgView.layer.cornerRadius = picImgView.frame.width/2
        picImgView.clipsToBounds = true
        imgView.setNeedsLayout()
        picImgView.setNeedsLayout()

//        let newImage = imageWithView(view: imgView)
//        return newImage

        return imgView
    }

Upvotes: 0

Benjamin Creem
Benjamin Creem

Reputation: 95

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).

Upvotes: 1

Related Questions