How can I add different images instead of pins in MKMapView? - ios

I've been working on an app that has an MKMapView and I want to customize the pins with different images. I've already did that but with one image only, now I need to make a pin show an image and the other pin show another image. How can I do this? If helps, here's my code:
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation{
MKAnnotationView *pinView = nil;
if(annotation != _mapView.userLocation)
{
static NSString *defaultPinID;
pinView = (MKAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"image1.jpg"];
}
else {
[_mapView.userLocation setTitle:#"Your Location"];
}
return pinView; }
I need the second and the third to show the same image but the first a different one
It follows like this:
- (void)viewWillAppear:(BOOL)animated {CLLocationCoordinate2D First; First.latitude = -12.098970; First.longitude = -77.034531; MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init]; annotationPoint.coordinate = First; annotationPoint.title = #"First"; annotationPoint.subtitle = #"Subtitle1"; [_mapView addAnnotation:annotationPoint];
CLLocationCoordinate2D Second; Second.latitude = -12.098299; Second.longitude = -77.068364; MKPointAnnotation *annotationPoint2 = [[MKPointAnnotation alloc] init]; annotationPoint2.coordinate = Second; annotationPoint2.title = #"Second"; annotationPoint2.subtitle = #"Subtitle2"; [_mapView addAnnotation:annotationPoint2];
CLLocationCoordinate2D Third; Third.latitude = -12.125888; Third.longitude = -77.023346; MKPointAnnotation *annotationPoint3 = [[MKPointAnnotation alloc] init]; annotationPoint3.coordinate = Third; annotationPoint3.title = #"Third"; annotationPoint3.subtitle = #"Subtitle3"; [_mapView addAnnotation:annotationPoint3];}

Make sure you have MapKit.framework and CoreLocation.framework in your project.
My custom pin images are 39 high by 32 wide. Have not tried other sizes but feel free to experiment. My 2 pin images are called pin1.png and pin2.png
Make sure you have your images named correctly to match what is in your code.
In my example I am not using current location but rather a static custom location (thought The Bahamas would be nice for this example). In your project you would of course you the Location Manager to get a user's current location.
I have tested my example and have successfully dropped 2 pins on the map with each pin having its own custom image.
It's not the cleanest code but I only had limited time to write it.
Here is the code for ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate>
#end
Here is the code for ViewController.h
#import "ViewController.h"
#import "MyAnnotation.h"
#import <MapKit/MapKit.h>
#interface ViewController ()
#property (strong, nonatomic) IBOutlet MKMapView *myMapView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// setup the map view, delegate and current location
[self.myMapView setDelegate:self];
self.myMapView.mapType = MKMapTypeStandard;
CLLocationCoordinate2D myLocation = CLLocationCoordinate2DMake(25.085130,-77.331428);
[self.myMapView setCenterCoordinate:myLocation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(myLocation, 2000, 2000);
region.center = self.myMapView.centerCoordinate;
self.myMapView.showsUserLocation = YES;
[self.myMapView setRegion:region animated:YES];
[self dropPins];
}
-(void)dropPins {
NSMutableArray *annotationArray = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(25.085130, -77.331428);
MyAnnotation *annotation1 = [[MyAnnotation alloc] initWithCoordinates:location1 image:#"pin1.png"];
[annotationArray addObject:annotation1];
[self.myMapView addAnnotations:annotationArray];
[annotationArray removeAllObjects];
CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(25.085130, -77.336428);
MyAnnotation *annotation2 = [[MyAnnotation alloc] initWithCoordinates:location2 image:#"pin2.png"];
[annotationArray addObject:annotation2];
[self.myMapView addAnnotations:annotationArray];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyAnnotation class]])
{
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else
{
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:#"pin1.png"])
annotationView.image = [UIImage imageNamed:#"pin1.png"];
if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:#"pin2.png"])
annotationView.image = [UIImage imageNamed:#"pin2.png"];
return annotationView;
}
return nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Here is the code for MyAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation>
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy, readonly) NSString *image;
-(id)initWithCoordinates:(CLLocationCoordinate2D) paramCoordinates
image:(NSString *) paramImage;
#end
Here is the code for MyAnnotation.m
#import "MyAnnotation.h"
#implementation MyAnnotation
-(id)initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
image:(NSString *)paramImage
{
self = [super init];
if(self != nil)
{
_coordinate = paramCoordinates;
_image = paramImage;
}
return (self);
}
#end

Related

MKMapView: Issue with changing pin image

I am trying to change the standard pin to my own image but I keep failing after several attempts.
I have tried different codes and guides that I have found here in this forum but none of them seems to work. I belive I am pasting the code in to my project wrongly. Any ideas how to replace the regular pin with my own image?
//.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
- (id)initWithLocation:(CLLocationCoordinate2D)coord;
#end
//.m
#import <Foundation/Foundation.h>
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate,title,subtitle;
- (id)initWithLocation:(CLLocationCoordinate2D)coord{
self = [super init];
if (self) {
coordinate = coord;
}
return self;
}
#end
//Viewcontroller.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface FirstViewController : UIViewController <UIAlertViewDelegate, UIWebViewDelegate> {
MKMapView *mapview;
}
- (IBAction)information;
#property (strong, nonatomic) IBOutlet UIScrollView *ScrollView;
#property (strong, nonatomic) IBOutlet UIImageView *image;
#property (retain, nonatomic) IBOutlet MKMapView *mapview;
- (IBAction)showMenu;
- (IBAction)setMap:(id)sender;
- (IBAction)GetLocation:(id)sender;
#end
//Viewcontroller.m
#import "FirstViewController.h"
#import "MapPin.h"
#implementation FirstViewController
#synthesize ScrollView, image;
#synthesize mapview;
- (void)viewDidLoad{
MKCoordinateRegion region = { {0.0, 0.0}, {0.0,0.0}};
region.center.latitude = 55.709900;
region.center.longitude = 13.201207;
region.span.longitudeDelta = 0.032f;
region.span.latitudeDelta = 0.032f;
[mapview setRegion:region animated:YES];
MapPin *ann = [[MapPin alloc] init];
ann.title = #"test Town";
ann.subtitle = #"test Nation";
ann.coordinate = region.center;
ann.coordinate = region.center;
[mapview addAnnotation:ann];
MKCoordinateRegion region2 = { {0.0, 0.0}, {0.0,0.0}};
region2.center.latitude = 55.703904;
region2.center.longitude = 13.201207;
region2.span.longitudeDelta = 0.032f;
region2.span.latitudeDelta = 0.032f;
[mapview setRegion:region2 animated:YES];
MapPin *ann2 = [[MapPin alloc] init];
ann2.title = #"test Town";
ann2.subtitle = #"test Nation";
ann2.coordinate = region2.center;
ann2.coordinate = region2.center;
[mapview addAnnotation:ann2];
ScrollView.scrollEnabled = YES;
[ScrollView setContentSize:CGSizeMake(320, 515)];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor= MKPinAnnotationColorGreen;
pinView.enabled = YES;
pinView.canShowCallout = YES;
pinView.image=[UIImage imageNamed:#"test.png"]; //here I am giving the image
return pinView;
}
See my other answer for working implementation.
Setting an IBOutlet delegate:
Since you're using an IBOutlet for your MKMapView you should control-drag from your MKMapView in your storyboard/xib file to the ViewController/"File's Owner" and select "delegate" from the popup.
Here a SO answer that covers creating custom pins: Custom pins
Also,
pinView.image=[UIImage imageNamed:#"test.png"];
should be
pinView.image=[UIImage imageNamed:#"test"];
Reference: Image from imageNamed:
The following worked for me:
Make sure MapKit.framework has been added to your project.
Make sure test.png is in your project (preferably in Images.xcassets)
Control-drag from your mapView in your storyboard to the ViewController and connect "delegate".
Then...
#import "MapPin.h"
#import <MapKit/MapKit.h>
#interface ViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapview;
#end
#implementation ViewController
- (void)viewDidLoad
{
MKCoordinateRegion region = { {0.0, 0.0}, {0.0,0.0}};
region.center.latitude = 55.709900;
region.center.longitude = 13.201207;
region.span.longitudeDelta = 0.032f;
region.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region animated:YES];
MapPin *ann = [[MapPin alloc] init];
ann.title = #"test Town";
ann.subtitle = #"test Nation";
ann.coordinate = region.center;
ann.coordinate = region.center;
[self.mapview addAnnotation:ann];
MKCoordinateRegion region2 = { {0.0, 0.0}, {0.0,0.0}};
region2.center.latitude = 55.703904;
region2.center.longitude = 13.201207;
region2.span.longitudeDelta = 0.032f;
region2.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region2 animated:YES];
MapPin *ann2 = [[MapPin alloc] init];
ann2.title = #"test Town";
ann2.subtitle = #"test Nation";
ann2.coordinate = region2.center;
ann2.coordinate = region2.center;
[self.mapview addAnnotation:ann2];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if(annotationView) {
return annotationView;
} else {
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:AnnotationIdentifier];
annotationView.image = [UIImage imageNamed:#"test"];
return annotationView;
}
}
#end
So I have followed the guidelines above, added the line of code and step3. Control-drag from your mapView in your storyboard to the ViewController and connect "delegate". which I named "pin".
But my image wont appear...I'll paste the new code again..there must be something wrong in it.
//Viewcontroller.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface FirstViewController : UIViewController <UIAlertViewDelegate, UIWebViewDelegate, MKMapViewDelegate> {
MKMapView *mapview;
}
- (IBAction)information;
#property (strong, nonatomic) IBOutlet UIScrollView *ScrollView;
#property (strong, nonatomic) IBOutlet UIImageView *image;
#property (retain, nonatomic) IBOutlet MKMapView *mapview;
#property (strong, nonatomic) IBOutlet MKMapView *pin;
- (IBAction)showMenu;
- (IBAction)setMap:(id)sender;
- (IBAction)GetLocation:(id)sender;
#end
//Viewcontroller.m
#import "FirstViewController.h"
#import "MapPin.h"
#implementation FirstViewController
#synthesize ScrollView, image;
#synthesize mapview;
#synthesize pin;
- (void)viewDidLoad{
MKCoordinateRegion region = { {0.0, 0.0}, {0.0,0.0}};
region.center.latitude = 55.709900;
region.center.longitude = 13.201207;
region.span.longitudeDelta = 0.032f;
region.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region animated:YES];
MapPin *ann = [[MapPin alloc] init];
ann.title = #"test Town";
ann.subtitle = #"test Nation";
ann.coordinate = region.center;
ann.coordinate = region.center;
[self.mapview addAnnotation:ann];
MKCoordinateRegion region2 = { {0.0, 0.0}, {0.0,0.0}};
region2.center.latitude = 55.703904;
region2.center.longitude = 13.201207;
region2.span.longitudeDelta = 0.032f;
region2.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region2 animated:YES];
MapPin *ann2 = [[MapPin alloc] init];
ann2.title = #"test Town";
ann2.subtitle = #"test Nation";
ann2.coordinate = region2.center;
ann2.coordinate = region2.center;
[self.mapview addAnnotation:ann2];
ScrollView.scrollEnabled = YES;
[ScrollView setContentSize:CGSizeMake(320, 515)];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if(annotationView) {
return annotationView;
} else {
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:AnnotationIdentifier];
annotationView.image = [UIImage imageNamed:#"test"];
return annotationView;
}
}
#end

Callout opening wrong view after zoom in iOS7

Everything is working fine in my app except for one thing: after zooming in and zooming back out, to see the whole map, some callouts open the wrong detailview.
I don't know if I'm missing some code or else.
Using Xcode 5.1.1 for iOS7.
This is what I've got at the moment:
Annotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Annotation: NSObject <MKAnnotation>
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
Annotation.m
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate,title,subtitle;
#end
MapView.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface Nameofthemap : UIViewController <MKMapViewDelegate>
#property (strong, nonatomic) IBOutlet MKMapView *Nameofthemap;
#end
MapView.m
#import "MapView.h"
#import "Annotation.h"
#import "InfoViewController.h"
#import "InfoTwoViewController.h"
#interface MapView ()
#property (nonatomic, strong) IBOutlet InfoViewController *InfoViewController;
#property (nonatomic, strong) IBOutlet InfoTwoViewController *InfoTwoViewController;
#end
#define PLACE1_LATITUDE 43.777130;
#define PLACE2_LONGITUDE 10.790018;
#define PLACE2_LATITUDE 43.81471237;
#define PLACE2_LONGITUDE 10.67472765;
#implementation MapView
- (IBAction)changeMapType:(id)sender {
if (_MapView.mapType == MKMapTypeHybrid)
_MapView.mapType = MKMapTypeStandard;
else
_MapView.mapType = MKMapTypeHybrid;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self gotoLocation];
_MapView.showsUserLocation = YES;
}
- (void)gotoLocation
{
MKCoordinateRegion newRegion;
newRegion.center.latitude = PLACE1_LATITUDE;
newRegion.center.longitude = PLACE2_LONGITUDE;
newRegion.span.latitudeDelta = 0.25f;
newRegion.span.longitudeDelta = 0.25f;
[self.MapView setRegion:newRegion animated:YES];
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
Annotation *myAnn;
Annotation *myAnn2;
//Place1 annotation
myAnn = [[Annotation alloc] init];
location.latitude = PLACE1_LATITUDE;
location.longitude = PLACE1_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = #"Name of the place";
myAnn.subtitle = #"Details";
[locations addObject:myAnn];
//Place2 annotation
myAnn2 = [[Annotation alloc] init];
location.latitude = PLACE2_LATITUDE;
location.longitude = PLACE2_LONGITUDE;
myAnn2.coordinate = location;
myAnn2.title = #"Name of place two";
myAnn2.subtitle = #"Details";
[locations addObject:myAnn2];
[self->_MapView addAnnotations:locations];
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)myAnn).title = #"Your position";
return nil;
}
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pinView"];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:#"pinView"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([[myAnn title] isEqualToString:#"Name of the place"]){
[rightButton addTarget:self action:#selector(myAnnClicked:)forControlEvents:UIControlEventTouchUpInside];
}
if ([[myAnn title] isEqualToString:#"Name of place two"]){
[rightButton addTarget:self action:#selector(myAnn2Clicked:)forControlEvents:UIControlEventTouchUpInside];
}
pinView.rightCalloutAccessoryView = rightButton;
}
return pinView;
}
-(IBAction)myAnnClicked:(id)sender
{
InfoViewController *info = [[InfoViewController alloc]init];
[self.navigationController pushViewController:info animated:YES];
}
-(IBAction)myAnn2Clicked:(id)sender
{
InfoTwoController *info2 = [[InfoTwoController alloc]init];
[self.navigationController pushViewController:info2 animated:YES];
}
#end
It's an annotation view re-use issue.
In viewForAnnotation, the button targets are only being set when creating a view (if dequeueReusableAnnotationViewWithIdentifier returns nil).
But if dequeueReusableAnnotationViewWithIdentifier returns a previously-used view, the button target is still whatever was set for the annotation that used the view before.
That previous annotation may not be the same as the current annotation.
So it's possible for annotation "two" to re-use a view that was originally created for annotation "one" and tapping on the already-created button shows the info for "one" instead of "two".
To fix this, two things should be done:
If dequeueReusableAnnotationViewWithIdentifier returns a view (if pinView is not nil), the code must update the view's annotation property to the current annotation.
The button target must be set whether a new view is being created or a dequeued view is being re-used. The easiest way to do this is to move the button creation/setting after the main if and just before the return.
The updated viewForAnnotation would look like this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)myAnn).title = #"Your position";
return nil;
}
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pinView"];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:#"pinView"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
}
else
{
//1. Re-using a view, update which annotation it's being used for now
pinView.annotation = myAnn;
}
//2. Now pinView is either a new view or re-used view.
//Set its button target based on current annotation...
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([[myAnn title] isEqualToString:#"Name of the place"]){
[rightButton addTarget:self action:#selector(myAnnClicked:)forControlEvents:UIControlEventTouchUpInside];
}
if ([[myAnn title] isEqualToString:#"Name of place two"]){
[rightButton addTarget:self action:#selector(myAnn2Clicked:)forControlEvents:UIControlEventTouchUpInside];
}
pinView.rightCalloutAccessoryView = rightButton;
return pinView;
}
By the way, instead of creating separate methods for each annotation (which can get tedious), use the map view's calloutAccessoryControlTapped delegate method instead.
In fact, right now, the map view is calling both your custom methods and the calloutAccessoryControlTapped delegate method (in which there's no code currently).
In the delegate method, the annotation tapped is accessible via view.annotation.
So in viewForAnnotation, you would just do this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)myAnn).title = #"Your position";
return nil;
}
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pinView"];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:#"pinView"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
pinView.annotation = myAnn;
}
return pinView;
}
Then in the calloutAccessoryControlTapped delegate method, you can do something like this:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
if ([view.annotation isKindOfClass:[Annotation class]])
{
Annotation *myAnn = (Annotation *)view.annotation;
id vcToPush = nil;
if ([[myAnn title] isEqualToString:#"Name of the place"]) {
vcToPush = [[InfoViewController alloc]init];
}
else if ([[myAnn title] isEqualToString:#"Name of place two"]) {
vcToPush = [[InfoTwoController alloc]init];
}
[self.navigationController pushViewController:vcToPush animated:YES];
}
}
Then remove the myAnnClicked and myAnn2Clicked methods.
You would also be much better off creating a generic "Info" view controller instead of a separate one for each annotation.
Some other unrelated things:
Don't put a semi-colon at the end of the #define lines
You've defined PLACE2_LONGITUDE twice
newRegion.center is using PLACE2_LONGITUDE instead of PLACE1_LONGITUDE

didSelectAnnotationView method creates an error

In my app, I have a mapView and few other components.
I have changed the view of annotation into my own icons, the icons gets displayed in the specific location of the the latitude and longitude.
But, when I click and hold the icons, it automatically gets converted into the anotations.
Please help me.
This is my map while loading
It becomes as such When I click and hold the annotations
didUpdateUserLocation
{
CLLocationCoordinate2D first;
first.latitude=13.040202;
first.longitude=80.24298;
myAnnotation.coordinate=first;
[locations addObject:myAnnotation];
[self.mapView addAnnotations:locations];
}
viewForAnnotation:
{
static NSString *identifier = #"Wifintech";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if ( pinView == nil )
pinView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:identifier];
pinView.image = [UIImage imageNamed:#"car-side.png"];
pinView.canShowCallout = YES;
}
didSelectAnnotationView
{
float latitude = [[view annotation ] coordinate].latitude;
float longitude = [[view annotation ] coordinate].longitude;
title_value=[[view annotation] title];
NSString * subtitle_val =[[view annotation] subtitle];
title_para.text=[NSString stringWithFormat:#"%#, %#",title_value,subtitle_val];
latitude_value.text=[NSString stringWithFormat:#"%f",latitude];
longitude_value.text=[NSString stringWithFormat:#"%f",longitude];
}
When using your own images, you need to create an MKAnnotationView not an MKPinAnnotationView. Please try searching on SO for answers before posting questions (it will save everyone including you a lot of time) .
MKAnnotationView ClassReference
Try returning a MKAnnotationView instead of MKPinAnnotationView from
-mapView:viewForAnnotation:
Most likely the subclass overrides some method that are tracking the selected-state of the view and adjusting the image. I suspect this will not be the case when using MKAnnotationView.
I think you need to take a close look at the following documentation.
Also, maybe make sure that the view in didSelect.. method is actually a pinAnnotionView and that the image is what you think it is.
From the documentation on MKAnnotationView:
Annotation views support the concept of a selection state, which determines whether the view is unselected, selected, or selected and displaying a standard callout view. The user toggles between the selection states through interactions with the annotation view. In the unselected state, the annotation view is displayed but not highlighted. In the selected state, the annotation is highlighted but the callout is not displayed. And finally, the annotation can be displayed both with a highlight and a callout. The callout view displays additional information such as a title string and controls for viewing more information. The title information is provided by the annotation object but your annotation view is responsible for providing any custom controls. For more information, see the subclassing notes.
This is my code
#import "FirstViewController.h"
#import "LocationObject.h"
#define THE_SPAN 0.01f;
#interface FirstViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (weak, nonatomic) IBOutlet UITextField *latitude_value;
#property (weak, nonatomic) IBOutlet UITextField *longitude_value;
#property (copy, nonatomic) NSString *title_value;
#property(nonatomic,assign) CLLocationCoordinate2D myCoordinate;
#property(nonatomic,copy) NSMutableArray *locations;
#property(nonatomic,retain) MKPointAnnotation * myAnnotation;
#property (readwrite) int tag;
#property(retain) MKPinAnnotationView *pinView;
#property (weak, nonatomic) IBOutlet UITextView *title_para;
#property(assign) CLLocationCoordinate2D *coordsArray;
#property(nonatomic,assign) MKPolyline * routeLine;
#end
#implementation FirstViewController
#synthesize latitude_value;
#synthesize longitude_value;
#synthesize title_value;
#synthesize myCoordinate;
#synthesize mapView;
#synthesize locations;
#synthesize myAnnotation;
#synthesize tag;
#synthesize pinView;
#synthesize title_para;
#synthesize title;
#synthesize coordsArray;
#synthesize routeLine;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setMapView:nil];
[self setLatitude_value:nil];
[self setLongitude_value:nil];
[self setLatitude_value:nil];
[self setLongitude_value:nil];
[self setTitle_value:nil];
[self setTitle_para:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polyLineView = [[MKPolylineView alloc] initWithPolyline:routeLine];
polyLineView.fillColor = [UIColor blueColor];
polyLineView.strokeColor = [UIColor redColor];
polyLineView.lineWidth = 2;
return polyLineView;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
//map view : region nad annotation
#pragma mark map view delegate methods
-(void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//map region and center location
MKCoordinateRegion myRegion;
CLLocationCoordinate2D center;
center.latitude=13.040223;
center.longitude=80.240995;
MKCoordinateSpan span;
span.latitudeDelta=THE_SPAN;
span.longitudeDelta=THE_SPAN;
myRegion=MKCoordinateRegionMake(center, span);
MKCoordinateRegion adjusted_region=[self.mapView regionThatFits:myRegion];
[self.mapView setRegion:adjusted_region animated:YES];
locations=[[NSMutableArray alloc]init];
//first point
CLLocationCoordinate2D first;
first.latitude=13.040202;
first.longitude=80.24298;
myAnnotation = [[MKPointAnnotation alloc]init];
myAnnotation.coordinate=first;
myAnnotation.title=#"Wifin Technology";
myAnnotation.subtitle=#"Globus";
[locations addObject:myAnnotation];
//second point
CLLocationCoordinate2D second;
second.latitude=13.0406527;
second.longitude=80.2437427;
myAnnotation= [[MKPointAnnotation alloc]init];
myAnnotation.coordinate=second;
myAnnotation.title=#"The Residency Towers";
myAnnotation.subtitle=#"Chennai";
[locations addObject:myAnnotation];
//third point
CLLocationCoordinate2D third;
third.latitude=13.040202;
third.longitude=80.240191;
myAnnotation= [[MKPointAnnotation alloc]init];
myAnnotation.coordinate=third;
myAnnotation.title=#"Rado Cool Zone";
myAnnotation.subtitle=#"Chennai";
[locations addObject:myAnnotation];
[self.mapView addAnnotations:locations];
title_para.text=[[NSString alloc]initWithString:#"The position displayed is Pondy Bazaar"];
coordsArray = malloc(sizeof(CLLocationCoordinate2D) * locations.count);
int i = 0;
for (CLLocation *loc in locations) {
coordsArray[i] = loc.coordinate;
i++;
}
routeLine = [MKPolyline polylineWithCoordinates:coordsArray
count:locations.count];
[mapView addOverlay:routeLine];
self.longitude_value.text=[NSString stringWithFormat:#"%f",center.longitude];
self.latitude_value.text=[NSString stringWithFormat:#"%f",center.latitude];
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
float latitude = [[view annotation ] coordinate].latitude;
float longitude = [[view annotation ] coordinate].longitude;
title_value=[[view annotation] title];
NSString * subtitle_val =[[view annotation] subtitle];
title_para.text=[NSString stringWithFormat:#"%#, %#",title_value,subtitle_val];
latitude_value.text=[NSString stringWithFormat:#"%f",latitude];
longitude_value.text=[NSString stringWithFormat:#"%f",longitude];
}
//Annotation view: icons
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
{
pinView = nil;
static NSString *identifier = #"Wifintech";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if ( pinView == nil )
pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:identifier];
if([[annotation title] isEqualToString:#"Wifin Technology"])
{
pinView.image = [UIImage imageNamed:#"car-side.png"];
pinView.canShowCallout = YES;
}
else if ([[annotation title] isEqualToString:#"The Residency Towers"])
{
pinView.image=[UIImage imageNamed:#"lorry-side.png"];
pinView.canShowCallout = YES;
}
else if([[annotation title] isEqualToString:#"Rado Cool Zone"])
{
//pinView.pinColor = MKPinAnnotationColorGreen;
pinView.canShowCallout = YES;
//pinView.animatesDrop = YES;
pinView.image = [UIImage imageNamed:#"car.png"];
}
else {
NSLog(#"Nothing");
}
return pinView;
}
#end

Problems with MapView Pin Annotation - Pin loses color when map is zoomed/panned/region changes

I have a mapview that displays locations of cash points. Annotations are dropped and the callout can be clicked on to go to a page with more detail about that location. There are two categories of cashpoint, free and paid, free cashpoint pins are green and the other red. When the pins drop they are the correct colours. Everything works fine untill i zoom to user location or other areas of the map then when i go back to the pins they have lost their colour formatting and are all the original red colour.
I assume this is something to do with the map reloading when it downloads tiles and not reloading the pins properly, although i could be wrong.
Any help will be much appreciated.
here is my code:
#import "CashPointMapViewController.h"
#import "PinDrop.h"
#import "CashPointDetailViewController.h"
#implementation CashPointMapViewController
#synthesize app, theCashList, mapview, ann, count, myArray, pinColor;
- (IBAction) getlocation {
MKCoordinateRegion region;
region.center = self.mapview.userLocation.coordinate;
region.span.longitudeDelta = 0.01f;
region.span.longitudeDelta = 0.01f;
[mapview setRegion:region animated:YES];
}
- (void)viewDidLoad {
[super viewDidLoad];
mapview.showsUserLocation = YES;
[mapview setMapType:MKMapTypeStandard];
[mapview setZoomEnabled:YES];
[mapview setScrollEnabled:YES];
MKCoordinateRegion region = { {0.0, 0.0 }, {0.0, 0.0 } };
region.center.latitude = 53.801279;
region.center.longitude = -1.548567;
region.span.longitudeDelta = 0.3f;
region.span.longitudeDelta = 0.3f;
[mapview setRegion:region animated:YES];
app = [[UIApplication sharedApplication]delegate];
UIImage *locate = [UIImage imageNamed:#"location arrow white.png"];
UIBarButtonItem *userlocatebutton = [[UIBarButtonItem alloc] initWithImage:locate style:UIBarButtonItemStylePlain target:self action:#selector(getlocation)];
self.navigationItem.rightBarButtonItem = userlocatebutton;
[self performSelectorInBackground:#selector(annloop) withObject:self];
}
-(void) annloop {
int i;
for (i=0; i<=count-1; i = i+1) {
theCashList = [myArray objectAtIndex:i];
NSString *trimlat = [theCashList.lat stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *trimlon = [theCashList.lon stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
double latdouble = [trimlat doubleValue];
double londouble = [trimlon doubleValue];
CLLocationCoordinate2D coord = {(latdouble),(londouble)};
ann = [[PinDrop alloc] init];
ann.index = i;
ann.title = [theCashList.name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *street = [theCashList.street stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *town = [theCashList.town stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *postcode = [theCashList.postcode stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *address = [[NSString alloc] initWithFormat:#"%#, %#, %#", street, town, postcode];
ann.subtitle = address;
ann.coordinate = coord;
NSString *trimprice = [theCashList.price stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([trimprice isEqualToString:#"Free"])
{
ann.price = 1;
}
else
{
ann.price = 0;
}
[mapview performSelectorOnMainThread:#selector(addAnnotation:) withObject:ann waitUntilDone:YES];
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]initWithAnnotation:ann reuseIdentifier:#"current"];
mypin.backgroundColor = [UIColor clearColor];
UIButton *goToDetail = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mypin.rightCalloutAccessoryView = goToDetail;
mypin.draggable = NO;
mypin.animatesDrop = TRUE;
mypin.canShowCallout = YES;
if (ann.price == 1)
{
mypin.pinColor = MKPinAnnotationColorGreen;
}
else
{
mypin.pinColor = MKPinAnnotationColorRed;
}
return mypin;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control {
PinDrop *annView = view.annotation;
CashPointDetailViewController *detailView = [[CashPointDetailViewController alloc]init];
theCashList = [myArray objectAtIndex:annView.index];
detailView.theCashList = theCashList;
[self.navigationController pushViewController:detailView animated:YES];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
EDIT: Here is my .h if it helps.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "CashPointList.h"
#import <MapKit/MapKit.h>
#import "PinDrop.h"
#interface CashPointMapViewController : UIViewController {
MKMapView *mapview;
PinDrop *ann;
}
#property (nonatomic, retain) AppDelegate *app;
#property (nonatomic, retain) CashPointList *theCashList;
#property (nonatomic, retain) PinDrop *ann;
#property (nonatomic, retain) IBOutlet MKMapView *mapview;
#property (nonatomic, readwrite) int count;
#property (nonatomic, retain) NSMutableArray *myArray;
#property (nonatomic) MKPinAnnotationColor pinColor;
-(IBAction) getlocation;
#end
It's not a problem related to the map reloading tiles.
The issue is that the code in the viewForAnnotation delegate is using the ann object with the incorrect assumption that the class-instance-level ann object will be in sync with whenever the delegate method is called.
The viewForAnnotation delegate is not necessarily called in the order that you add annotations and can be called multiple times for the same annotation if the map needs to re-display an annotation when it comes back into view.
When the delegate method gets called again for a previously added annotation, ann and annotation no longer point to the same object. ann is now probably pointing to the last added annotation and so all the annotations change to its color.
In that delegate method, you must use the annotation parameter which is a reference to the annotation that the map view wants the view for in the current call (which may be completely unrelated to your outside loop).
So this line:
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]
initWithAnnotation:ann reuseIdentifier:#"current"];
should be:
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:#"current"];
^^^^^^^^^^
and when checking the annotation's properties, use the annotation parameter (and cast it to your custom class to get at the custom properties):
PinDrop *ann = (PinDrop *)annotation;
//Note that this local "ann" is NOT the same as the class-level "ann".
//May want to use a different name to avoid confusion.
//The compiler may also warn you about this.
if (ann.price == 1)
...
A separate, unrelated, but highly recommended suggestion is to implement annotation view re-use by using dequeueReusableAnnotationViewWithIdentifier. This will improve performance when you have lots of annotations.

Mapkit new annotations with pin without popup

i've just created a new app, and i've implemented a map in a view.
I've created the map with some personal annotation but, when the user touch the pin, doesn't appear anything. I've tried to set the colour of the pin but nothing seem's to work. I need that the user, when touch the pin, can touch the disclosure button on the popup, to use "native maps".
Now, when i touch the pin, this one become darker, but nothing else.
Can someone help me? Please!!
io ne avrei bisogno, per far aprire poi un disclosure e far aprire l'app nativa mappe per creare il percorso!! Se ora tocco il pin, questo diventa piĆ¹ scuro ma non succede nulla! non riesco nemmeno ad agire su di loro per cambiare colore, immagini,.... ho guardato i tutorial ma non trovo l'errore!
header subclass
#import <Foundation/Foundation.h>
#import <MapKit/Mapkit.h>
#interface myAnnotation : NSObject <MKAnnotation>{
CLLocationCoordinate2D coordinate;
NSString *titolo;
NSString *sottotitolo;
}
#property(nonatomic,assign) CLLocationCoordinate2D coordinate;
#property(nonatomic,copy) NSString *titolo;
#property(nonatomic,copy) NSString *sottotitolo;
#end
implementation subclass
#implementation myAnnotation
#synthesize titolo;
#synthesize sottotitolo;
#synthesize coordinate;
-init{
return self;
}
#end
file .m view controller
CLLocation *userLoc = myMapView.userLocation.location;
CLLocationCoordinate2D userCoordinate = userLoc.coordinate;
NSLog(#"user latitude = %f",userCoordinate.latitude);
NSLog(#"user longitude = %f",userCoordinate.longitude);
myMapView.delegate=self;
NSMutableArray* annotations=[[NSMutableArray alloc] init];
CLLocationCoordinate2D theCoordinate1;
theCoordinate1.latitude = 45.;
theCoordinate1.longitude = 7.;
CLLocationCoordinate2D theCoordinate2;
theCoordinate2.latitude = 45.;
theCoordinate2.longitude = 12.;
CLLocationCoordinate2D theCoordinate3;
theCoordinate3.latitude = 45.;
theCoordinate3.longitude = 8.;
CLLocationCoordinate2D theCoordinate4;
theCoordinate4.latitude = 43.;
theCoordinate4.longitude = 7.;
myAnnotation* myAnnotation1=[[myAnnotation alloc] init];
myAnnotation1.coordinate=theCoordinate1;
myAnnotation1.titolo=#"xxxx";
myAnnotation1.sottotitolo=#"xxx";
myAnnotation* myAnnotation2=[[myAnnotation alloc] init];
myAnnotation2.coordinate=theCoordinate2;
myAnnotation2.titolo=#"yyyy";
myAnnotation2.sottotitolo=#"yyyy";
myAnnotation* myAnnotation3=[[myAnnotation alloc] init];
myAnnotation3.coordinate=theCoordinate3;
myAnnotation3.titolo=#"zzz";
myAnnotation3.sottotitolo=#"zzz";
myAnnotation* myAnnotation4=[[myAnnotation alloc] init];
myAnnotation4.coordinate=theCoordinate4;
myAnnotation4.titolo=#"kkk";
myAnnotation4.sottotitolo=#"kkk";
[myMapView addAnnotation:myAnnotation1];
[myMapView addAnnotation:myAnnotation2];
[myMapView addAnnotation:myAnnotation3];
[myMapView addAnnotation:myAnnotation4];
[annotations addObject:myAnnotation1];
[annotations addObject:myAnnotation2];
[annotations addObject:myAnnotation3];
[annotations addObject:myAnnotation4];
NSLog(#"%d",[annotations count]);
and then this snippet to show and personalize the pin
-(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] autorelease];
pinView.pinColor = MKPinAnnotationColorPurple;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
}
else {
[mapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
The MKAnnotation protocol requires that the class responds to title and subtitle. The properties must be named exactly like that.
Although you can also have your own differently named properties for the same, the map view will not call them (it is looking for title and subtitle).
For the disclosure button, in viewForAnnotation, set the rightCalloutAccessoryView to a UIButton and respond to its tap in the calloutAccessoryControlTapped delegate method.
In that delegate method, you can access the annotation object using (myAnnotation *)view.annotation and then call openURL to open the Maps app.

Resources