MKPinAnnotationView doesn't set custom image - ios

I have to set custom image for different pins. With my code I'm able to set custom color for each of them but when I try to set custom image instead of colors, it doesn't work.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(MyAnnotation *)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyAnnotation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.myMap dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
NSString *stringType = [NSString stringWithFormat:#"%#", [(MyAnnotation *)annotationView.annotation stringType]];
if ([stringType isEqualToString:#"0"]) {
annotationView.image = [UIImage imageNamed:#"IconUserCerco.png"];
//annotationView.pinColor = MKPinAnnotationColorGreen;
} else if ([stringType isEqualToString:#"1"]) {
annotationView.image = [UIImage imageNamed:#"IconUserDefault.png"];
//annotationView.pinColor = MKPinAnnotationColorPurple;
} else if ([stringType isEqualToString:#"2"]) {
annotationView.image = [UIImage imageNamed:#"PinUniversity.png"];
//annotationView.pinColor = MKPinAnnotationColorRed;
}
return annotationView;
}
return nil;
}
Any help will be much appreciated. Thanks in advance.

Instead of MKPinAnnotationView can you use MKAnnotationView? You'll have to use following instead of MKPinAnnotationView
MKAnnotationView *annotationView = [self.myMap dequeueReusableAnnotationViewWithIdentifier:identifier];
iOS 9.0 onwards its recommended to use MKAnnotationView. That should solve your problem.

This is what it looks like in iOS 11.x Swift 4, note this won't work if you make the same mistake as me using MKPinAnnotationView. This will make a pin and you won't be able to change the image behind it.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pav:MKAnnotationView?
if (pav == nil)
{
pav = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pav?.isDraggable = true
pav?.canShowCallout = true
pav?.image = UIImage(named: "WIP.png")
pav?.calloutOffset = CGPoint(x: -8, y: 0)
pav?.autoresizesSubviews = true
// pav?.rightCalloutAccessoryView = UIButton(type: .roundedRect)
pav?.leftCalloutAccessoryView = UIButton(type: .contactAdd)
}
else
{
pav?.annotation = annotation;
}
return pav;
}

Related

Update mapView pin colour based on boolean property

I'm trying to update the colour of the mapView pins based on whether the hotspot has been visited or not.
See my code below. Below is the hotspot class that subscribes to the MKAnnotation delegate. The property that determines pin colour is the visited Bool.
init(title: String, hotspotName: String,coordinate: CLLocationCoordinate2D, ARType:String, hotspotId:String)
{
//assing values to properties
self.hotspotTitle = title
self.hotspotName = hotspotName
self.ARType = ARType
self.coordinate = coordinate
self.hotspotId = hotspotId
super.init()
}
var visited: Bool {
return self.completed
}
var title: String?
{
return hotspotTitle
}
var subtitle: String?
{
return hotspotName
}
Below is the mapKit delegate method I'm using to try and update pin colour.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// check if annotation is of type Hotspot, as we dont want to alter other types of annotations
guard annotation is Hotspot else {
return nil
}
let identifier = "Hotspot"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
let pinView = MKPinAnnotationView(annotation:annotation,reuseIdentifier: identifier)
if annotationView == nil
{
if let hotspot = annotationView?.annotation as? Hotspot {
if !hotspot.visited
{
pinView.pinTintColor = UIColor(red:0.32, green:0.82, blue:0.4, alpha:1)
pinView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
else
{
pinView.pinTintColor = UIColor(red:0.0, green:0.0, blue:0.90, alpha:1)
pinView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
}
pinView.frame = mapView.frame
pinView.isEnabled = true
pinView.canShowCallout = true
pinView.animatesDrop = true
let rightButton = UIButton(type: .detailDisclosure)
rightButton.addTarget(self,action: #selector(getDirections),for: .touchUpInside)
pinView.rightCalloutAccessoryView = rightButton
annotationView = pinView
}
if let annotationView = annotationView
{
annotationView.annotation = annotation
// 5
let button = annotationView.rightCalloutAccessoryView as! UIButton
if let index = trail.hotspots.index(of: annotation as! Hotspot)
{
button.tag = index
}
}
return annotationView
}
Update mapView pin colour out of if annotationView == nil statement.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// check if annotation is of type Hotspot, as we dont want to alter other types of annotations
guard annotation is Hotspot else {
return nil
}
let identifier = "Hotspot"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
let pinView = MKPinAnnotationView(annotation:annotation,reuseIdentifier: identifier)
if annotationView == nil
{
pinView.frame = mapView.frame
pinView.isEnabled = true
pinView.canShowCallout = true
pinView.animatesDrop = true
let rightButton = UIButton(type: .detailDisclosure)
rightButton.addTarget(self,action: #selector(getDirections),for: .touchUpInside)
pinView.rightCalloutAccessoryView = rightButton
annotationView = pinView
}
if let hotspot = annotationView?.annotation as? Hotspot {
if !hotspot.visited
{
annotationView.pinTintColor = UIColor(red:0.32, green:0.82, blue:0.4, alpha:1)
annotationView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
else
{
annotationView.pinTintColor = UIColor(red:0.0, green:0.0, blue:0.90, alpha:1)
annotationView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
}
if let annotationView = annotationView
{
annotationView.annotation = annotation
// 5
let button = annotationView.rightCalloutAccessoryView as! UIButton
if let index = trail.hotspots.index(of: annotation as! Hotspot)
{
button.tag = index
}
}
return annotationView
}

Changing MKMapView User Location Annotation

I'm attempting to change the user default location annotation on the MKMapView from the blue to a custom image named geo. It's hitting the line to set it to geo when I set breakpoints, but both points (the user default, and Passenger point are default red pinpoint annotations) Am I setting this wrong, or is there certain image stipulations?
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isKindOfClass(PassengerLocation) == false {
//User location
let userIdentifier = "UserLocation"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(userIdentifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:userIdentifier)
}
annotationView!.annotation = annotation
annotationView!.canShowCallout = true
// THIS IS NOT WORKING, DEFAULT RED PIN POINT STILL SHOWING
annotationView!.image = UIImage(named: "geo")
return annotationView
}
let identifier = "PassengerLocation"
if let annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) {
annotationView.annotation = annotation
return annotationView
} else {
let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:identifier)
annotationView.enabled = true
annotationView.canShowCallout = true
let btn = UIButton(type: .DetailDisclosure)
annotationView.rightCalloutAccessoryView = btn
return annotationView
}
}
This works:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isEqual(mapView.userLocation) {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "userLocation")
annotationView.image = UIImage(named: "geo")
return annotationView
}
}
its working for me
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
// want to show a custom image if the annotation is the user's location.
guard !annotation.isKindOfClass(MKUserLocation) else {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "userLocation")
annotationView.image = UIImage(named: "icon_coordinates_self")
return annotationView
//return nil
}
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else {
let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
av.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
annotationView = av
}
if let annotationView = annotationView {
// Configure your annotation view here
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "Annotation_map")
}
return annotationView
}
Use a regular MKAnnotationView if you want to customize the image. With a pin, all you can do is change the color.
guard !annotation.isKind(of: MKUserLocation.self) else {
return nil
}
That works perfectly

change image pin maps

What should I write in order to put a personal picture instead of the traditional red pin?
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let annView : MKPinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "currentloc")
annView.pinTintColor = UIColor.redColor()
annView.animatesDrop = true
annView.canShowCallout = true
annView.calloutOffset = CGPointMake(-8, 0)
annView.autoresizesSubviews = true
annView.rightCalloutAccessoryView = UIButton(type: UIButtonType.DetailDisclosure) as UIView
return annView
}
Use MKAnnotationView instead of MKPinAnnotationView, and then set its image property. I'd also suggest implementing the dequeue logic so that annotations can be reused:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let annotationIdentifier = "SomeCustomIdentifier" // use something unique that functionally identifies the type of pin
var annotationView: MKAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier)
if annotationView != nil {
annotationView.annotation = annotation
} else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView.image = UIImage(named: "annotation.png")
annotationView.canShowCallout = true
annotationView.calloutOffset = CGPointMake(-8, 0)
annotationView.autoresizesSubviews = true
annotationView.rightCalloutAccessoryView = UIButton(type: UIButtonType.DetailDisclosure) as UIView
}
return annotationView
}

mapkit select all annotations

I'm building an app using swift and MapKit. It has several custom point annotations. I would like to display the title above all annotations at any time, by default. Hence they would be all selected. Therefore I could get inspiration from this post and use:
[mapView selectAnnotation:pinView animated:YES]
But I still need to be able to select a pin by clicking on it and get a new mapScope based on this annotation. How could I do it?
If the first solution is not possible, I would use a specific label on each annotation. But then is there a way to hide the annotation title forever?
EDIT:
Here is the code for the custom point annotation:
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
println("viewForAnnotation")
if !(annotation is MKPointAnnotation) {
return nil
}
var seleccion:Bool
let cpa = annotation as! CustomPointAnnotation
let reuseId = cpa.nickName as String
var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView.canShowCallout = true
// create and add UILabel only when actually creating MKAnnotationView
var nameLbl: UILabel! = UILabel(frame: CGRectMake(-24, 40, 100, 30))
nameLbl.tag = 42
nameLbl.textColor = UIColor.blackColor()
nameLbl.font = UIFont(name: "Atari Classic Extrasmooth", size: 10)
nameLbl.textAlignment = NSTextAlignment.Center
anView.addSubview(nameLbl)
}
else {
anView.annotation = annotation
}
anView.image = cpa.image
if cpa.toBeTriggered == true {
anView.selected = true
}
if let nameLbl = anView.viewWithTag(42) as? UILabel {
nameLbl.text = cpa.nickName
}
return anView
}
As you are using custom annotation views this code will be helpful to you.
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation //thammu
{
static NSString *reuseId = #"StandardPin";
MKAnnotationView *aView;
//MKAnnotationView *aView = (MKAnnotationView *)[Mapsview dequeueReusableAnnotationViewWithIdentifier:reuseId];
aView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:reuseId];
aView.enabled = YES;
aView.canShowCallout = YES;
aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
UIImageView *img=[[UIImageView alloc]initWithFrame:CGRectMake(-41,-22,121,25)];
img.image=[UIImage imageNamed:#"annotation-bg#2x.png"]; //This is the Details image view
UILabel *lblPlaceholder1=[[UILabel alloc]init];
lblPlaceholder1 = [[UILabel alloc]initWithFrame:CGRectMake(4,2,117, 21)];
lblPlaceholder1.backgroundColor=[UIColor clearColor];
lblPlaceholder1.numberOfLines=1;
[lblPlaceholder1 setTextColor:[UIColor redColor]];
lblPlaceholder1.textAlignment=NSTextAlignmentCenter;
lblPlaceholder1.text=annotation.title;
[lblPlaceholder1 setTextColor:[UIColor darkGrayColor]];
[lblPlaceholder1 setFont:[UIFont fontWithName:#"Roboto-Regular" size:12.0f]];
NSString *subTitleStr = annotation.subtitle;
[img addSubview:lblPlaceholder1];
[aView addSubview:img];
[img setUserInteractionEnabled:YES];
aView.image = [UIImage imageNamed:#"tracker.png"];//This is marker image view
aView.annotation = annotation;
return aView;
}
Here all the annotations in map are by default visible.

MKMapView: Instead of Annotation Pin, a custom view

I want to display an image in my MKMapView instead of little rock pin.
Can someone please put some helpful code here, or tell the way how to do it?
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:
(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil ) pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinView.pinColor = MKPinAnnotationColorGreen;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
pinView.image = [UIImage imageNamed:#"pinks.jpg"]; //as suggested by Squatch
}
else {
[mapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
I am expecting my image pinks.jpg to be on the map, pinning the location instead of default pin view (rock pin shaped). But still I am getting the default image of the pin.
When you want to use your own image for an annotation view, you should create an MKAnnotationView instead of an MKPinAnnotationView.
MKPinAnnotationView is a subclass of MKAnnotationView so it has an image property but it generally overrides that and draws a pin image (that's what it's for).
So change the code to:
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID];
//pinView.pinColor = MKPinAnnotationColorGreen;
pinView.canShowCallout = YES;
//pinView.animatesDrop = YES;
pinView.image = [UIImage imageNamed:#"pinks.jpg"]; //as suggested by Squatch
}
else {
[mapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
Notice that animatesDrop is also commented out since that property only exists in MKPinAnnotationView.
If you still want your image annotations to drop, you'll have to do the animation yourself. You can search Stack Overflow for "animatesdrop mkannotationview" and you'll find several answers. Here are the first two:
Is it possible to call animatesDrop in a MKAnnotationView rather than MKPinAnnotationView?
How can I create a custom "pin-drop" animation using MKAnnotationView?
Here's an answer on Swift 3. It dequeues annotation view if possible or creates a new one if not:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// Don't want to show a custom image if the annotation is the user's location.
guard !(annotation is MKUserLocation) else {
return nil
}
// Better to make this class property
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
if let annotationView = annotationView {
// Configure your annotation view here
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "yourImage")
}
return annotationView
}
Swift 2.2:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
// Don't want to show a custom image if the annotation is the user's location.
guard !annotation.isKindOfClass(MKUserLocation) else {
return nil
}
// Better to make this class property
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else {
let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
av.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
annotationView = av
}
if let annotationView = annotationView {
// Configure your annotation view here
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "yourImage")
}
return annotationView
}
I agree with with answer of the Anna and i like to show how will look that in swift3.This answer it's with many other options.Like a resize the image, get a list of images from array and ect.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? PetrolStation {
let identifier = "pinAnnotation"
var view: MKAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
as? MKPinAnnotationView { // 2
dequeuedView.annotation = annotation
view = dequeuedView
} else {
// 3
view = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
//here We put a coordinates where we like to show bubble with text information up on the pin image
view.calloutOffset = CGPoint(x: -7, y: 7)
//Here this is a array of images
let pinImage = PetrolItem[activePlace].imgPetrol?[activePlace]
//Here we set the resize of the image
let size = CGSize(width: 30, height: 30)
UIGraphicsBeginImageContext(size)
pinImage?.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let resizeImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
view.image = resizeImage
//Here we like to put into bubble window a singe for detail Informations
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure) as UIView
//Here we make change of standard pin image with our image
view.image = resizeImage
}
return view
}
return nil
}

Resources