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
}
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")
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With