Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

colored image for MKMarkerAnnotationView in MapKit

I am building an app for iOS, that allows the user to store images location based. Now I want to use the latest AnnotationView (MKMarkerAnnotationView) in iOS for this, because it provides automated clustering.

My problem is, that this class needs a glyphTintColor if it is not provided it is set to UIColor().red. iOS is using this color to color the whole image with it. After that the image has just this color. I tried setting the glyphTintColor to nil but this will cause the image to be red. I also tried to set it to UIColor(red:1.00, green:1.00, blue:1.00, alpha:0.0) but after that the image is gone and you can only see the marker itself.

I want the marker to show the image in its original colors not single color.

Can anyone help me with this problem?

Here is my full code:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation {
        return nil
    }

    let identifier = "PinAnnotationIdentifier"

    var pinView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)

    pinView?.annotation = annotation
    pinView?.clusteringIdentifier = "clusterId"
    pinView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)


    pinView?.canShowCallout = false
    pinView?.glyphImage = UIImage(named: "image")


    return pinView
}
like image 585
Mojo Avatar asked Oct 27 '25 15:10

Mojo


2 Answers

When you call

pinView?.glyphImage = UIImage(named: "image")

pinView calls

glyphImage?.withRenderingMode(.alwaysTemplate)

This enables an easy approach to the problem: simply override withRenderingMode:

import UIKit

class OriginalUIImage: UIImage {

    convenience init?(named name: String) {
        guard let image = UIImage(named: name),
              nil != image.cgImage else {
                    return nil
        }
        self.init(cgImage: image.cgImage!)
    }

    override func withRenderingMode(_ renderingMode: UIImage.RenderingMode) -> UIImage {
        // both return statements work:
        return self
        // return super.withRenderingMode(.alwaysOriginal)
    }

}

now you can use

pinView?.glyphImage = OriginalUIImage(named: "image")
like image 157
Gerd Castan Avatar answered Oct 29 '25 07:10

Gerd Castan


Yes you can! You just need to play with layers a little bit. When creating a new MKMarkerAnnotationView create UIImageView object and add layer(UIImageView) on last layer.

override var annotation: MKAnnotation? {
    willSet {

        if let cluster = newValue as? MKClusterAnnotation {
            markerTintColor = UIColor(named: "Green")
            glyphText = "\(cluster.memberAnnotations.count)"
        }

        /* Check does received value is a MapMarkerAnnotation.swift object */
        guard let mapMarkerAnnotation = newValue as? MapMarkerAnnotation else { return }

        /* Assign properties */
        markerTintColor = Application.defaultColor
        displayPriority = .required

        /* Assign image */
        if let user = mapMarkerAnnotation.userInfo as? User {
            ImageManager.get(from: user.mainPhoto) { (image) in

                let imageView = UIImageView(image: image)
                imageView.frame = CGRect(x: 2, y: 2, width: 24, height: 24)
                imageView.layer.cornerRadius = 24 / 2
                imageView.clipsToBounds = true
                self.layer.sublayers?[1].addSublayer(imageView.layer)

                /* Assign current image but with clear color tint. */
                self.glyphImage = image
                self.glyphTintColor = .clear
            }
        }
    }
}

After adding image layer. Add image layer on expanded state.

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {

    /* Check does annotation is an **MapMarker.swift** object. */
    if let mapMarkerAnnotationView = view as? MapMarkerAnnotationView {
        if let user = mapMarkerAnnotationView.userInfo as? User {

            /* Assign image */
            ImageManager.get(from: user.mainPhoto) { (image) in

                let imageView = UIImageView(image: image)
                imageView.frame = CGRect(x: 2, y: 2, width: 52, height: 52)
                imageView.layer.cornerRadius = 52 / 2
                imageView.clipsToBounds = true

                /* Assign tag value */
                imageView.layer.setValue(1, forKey: "tag")

                /* check does image layer exist. */
                if mapMarkerAnnotationView.layer.sublayers?[3].sublayers?.filter({($0.value(forKey: "tag") as? Int) == 1}).count == 0 {
                    mapMarkerAnnotationView.layer.sublayers?[3].addSublayer(imageView.layer)
                }
            }
        }
    }

Good luck!

like image 40
Ignelio Avatar answered Oct 29 '25 06:10

Ignelio