MapKit custom pin annotation - ios

I have the following files:
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
And in the main code, which takes in an NSURL found elsewhere:
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[spinner stopAnimating];
// json parsing
results = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
annotation * myAnn;
NSArray *pins = mapView.annotations;
if ([pins count])
{
[mapView removeAnnotations:pins];
}
/* loop through the array, each key in the array has a JSON String with format:
* title <- string
* strap <- string
* id <- int
* date <- date
* lat <- floating point double
* long <- floating point double
* link <- string
*/
int i;
for (i = 0; i < [results count]; i++) {
//NSLog(#"Result: %i = %#", i, results[i]);
//NSLog(#"%#",[[results objectAtIndex:i] objectForKey:#"long"]);
myAnn = [[annotation alloc] init];
location.latitude = (double)[[[results objectAtIndex:i] objectForKey:#"lat"] doubleValue];
location.longitude = (double)[[[results objectAtIndex:i] objectForKey:#"long"] doubleValue];
myAnn.coordinate = location;
myAnn.title = [[results objectAtIndex:i] objectForKey:#"title"];
myAnn.subtitle = [[results objectAtIndex:i] objectForKey:#"strap"];
[locations addObject:myAnn];
//NSLog(#"%i", [[results objectAtIndex:i] objectForKey:#"lat"]);
}
[self.mapView addAnnotations:locations];
Previous things I have looked at for this say that I need to use MKAnnotationView as opposed to MKPinAnnotationView but as you can see I do not use either, is it possible for me to use custom images for the pins that are dropped on the screen.

You (a) make sure to define your view controller to be the delegate for your MKMapView; and (b) implement viewForAnnotation, e.g.:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
static NSString * const identifier = #"MyCustomAnnotation";
MKAnnotationView* annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView) {
annotationView.annotation = annotation;
} else {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier];
}
// set your annotationView properties
annotationView.image = [UIImage imageNamed:#"Your image here"];
annotationView.canShowCallout = YES;
// if you add QuartzCore to your project, you can set shadows for your image, too
//
// [annotationView.layer setShadowColor:[UIColor blackColor].CGColor];
// [annotationView.layer setShadowOpacity:1.0f];
// [annotationView.layer setShadowRadius:5.0f];
// [annotationView.layer setShadowOffset:CGSizeMake(0, 0)];
// [annotationView setBackgroundColor:[UIColor whiteColor]];
return annotationView;
}
return nil;
}
By the way, in my example above, I changed the name of your annotation class to CustomAnnotation. annotation is a horrible name for a class because (a) it doesn't follow class naming conventions of upper case first letter; and (b) it's identical to the variable name, annotation, that many MKMapViewDelegate methods will use by default.
References
Location Awareness Programming Guide
Map Kit Framework Reference

You can certainly use custom images for an MKAnnotationView, see iOS MapKit custom pins.

Both MKAnnotationPinView and MKAnnotationView are subclasses of UIView and therefore will allow custom views.

Related

MKAnnotationView show different text on label

I want to display different text on each annotationView, but same value is displayed on every annotation.
Following is my code :
NSMutableArray *strAnnoTitle;
-(void)callAddAnnotations{
cnt = 0;
[_mapView removeAnnotations:[_mapView annotations]];
for (id obj in arrPropTemp) {
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake([[[arrPropTemp valueForKey:#"Latitude"] objectAtIndex:cnt] floatValue], [[[arrPropTemp valueForKey:#"Longitude"] objectAtIndex:cnt] floatValue]);
strAnnoTitle[cnt] = [obj valueForKey:#"ListPriceForMap"];
// Add an annotation
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = coords;
[self.mapView addAnnotation:point];
cnt++;
}
}
-(MKAnnotationView *)createAnnotation:(MKAnnotationView *)viewAn{
UILabel *lbl = (UILabel *)[viewAn viewWithTag:100];
[lbl setText:strAnnoTitle[cnt]];
return viewAn;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *viewAn = [[[NSBundle mainBundle] loadNibNamed:#"MapAnnotation" owner:self options:nil] lastObject];
viewAn = [self createAnnotation:viewAn];
return viewAn;
return nil;
}
Output:
Where am I getting wrong? How do I solve this?
Change your implementation .
-(void)callAddAnnotations{
cnt = 0;
[_mapView removeAnnotations:[_mapView annotations]];
for (id obj in arrPropTemp) {
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake([[[arrPropTemp valueForKey:#"Latitude"] objectAtIndex:cnt] floatValue], [[[arrPropTemp valueForKey:#"Longitude"] objectAtIndex:cnt] floatValue]);
strAnnoTitle[cnt] = [obj valueForKey:#"ListPriceForMap"];
// Add an annotation
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = coords;
[point setTitle:strAnnoTitle[cnt]];
[self.mapView addAnnotation:point];
cnt++;
}
}
change your create method
-(MKAnnotationView *)createAnnotation:(MKAnnotationView *)viewAn{
UILabel *lbl = (UILabel *)[viewAn viewWithTag:100];
[lbl setText: viewAn.annotation.title];//can move this also to delegate
return viewAn;
}
Change your viewForAnnotation method to like this.
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView * viewAn =[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
MKAnnotationView *viewAn = [[[NSBundle mainBundle] loadNibNamed:#"MapAnnotation" owner:self options:nil] lastObject];
viewAn = [self createAnnotation:viewAn];
}
return viewAn;
}
Take 1 NSObject file with the required fields u want for annotation. Add annotation on mapview and attach information on that Nsobject file also and same do as in viewforannotation method it will work.
Like
1.) NSObject file
REVPin.h
#interface REVPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSInteger tag;
NSArray *nodes;
}
#property(nonatomic, retain) NSArray *nodes;
#property(readwrite, nonatomic) NSInteger tag;
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
-(void)AddPinToMap:(NSMutableArray *)PinArray
{
NSMutableArray *pins = [NSMutableArray array];
oldZoomLevel = (int)[self zoomLevelForMapRect:MapView.visibleMapRect withMapViewSizeInPixels:CGSizeMake(MapView.frame.size.width, MapView.frame.size.height)];
if ([isFirstTimeN isEqualToString:#"YES"]) {
[MapView removeAnnotations:MapView.annotations];
for(int i=0;i<[PinArray count];i++) {
CGFloat latitude=[[[PinArray objectAtIndex:i] objectForKey:#"lat"] floatValue];
CGFloat longitude=[[[PinArray objectAtIndex:i] objectForKey:#"lon"] floatValue];
CLLocationCoordinate2D newCoord = {latitude, longitude};
REVPin *pin = [[REVPin alloc] init];
pin.title = [NSString stringWithFormat:#"Pin %i",i+1];
pin.subtitle = [NSString stringWithFormat:#"Pin %i subtitle",i+1];
pin.coordinate = newCoord;
pin.tag = i;
pin.userId = [NSString stringWithFormat:#"%#",[[PinArray objectAtIndex:i] objectForKey:#"u"]];
[pins addObject:pin];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
REVPin *pin = (REVPin *)annotation;
MKAnnotationView *annView;
if([annotation class] == MKUserLocation.class)
{
return nil;
}
annView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"pin"];
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"pin"];
[array addObject:pin];
return annView;
}
try by using above way it will work

Mapbox Annotation

I want to create multiple annotations with different images. To create the annotations, in viewDidLoad:
for (int i=0; i<[annotationsArray count]; i++) {
RMAnnotation *annotation = [[RMAnnotation alloc]
initWithMapView:mapView
coordinate:CLLocationCoordinate2DMake([[latitudeArray objectAtIndex:i] doubleValue], [[longitudeArray objectAtIndex:i] doubleValue])
andTitle:[nameArray objectAtIndex:i]];
[self.mapView addAnnotation:annotation];
}
In the method below, it gives every annotation the same image:
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation
{
if (annotation.isUserLocationAnnotation) {
return nil;
}
RMMarker *marker = [[RMMarker alloc] initWithUIImage:[UIImage imageNamed:#"CoffeeShopsIcon.png"]];
marker.canShowCallout = YES;
marker.leftCalloutAccessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"CoffeeShopsIcon.png"]];
marker.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return marker;
}
I have an array that holds the image names. How can I achieve this issue?
You want to use the -[RMAnnotation userInfo] API.
/** Storage for arbitrary data. */
#property (nonatomic, strong) id userInfo;
You could setup a property on your RMAnnotation that denotes which image to use and then create your marker based on this property for each annotation.

Building MapView Annotations is very slow

I have an application which shows something around 100 Annotations (with custom pin-images, callout accessories and annotation-images) in a MapView. While building the annotations I store a link between annotation and building so I can assign the right building and open the right segue afterwards.
In iOS 6 they get built really fast, I also enabled animation while adding them, so one pin got dropped after the other, but with apple maps in iOS7 this isn't possible anymore (?). Now building those 100 annotations takes over 1 second on my iPhone 4S and that's too long. Is there anyway to improve the code?
- (void)viewDidLoad
...
//creating annotations
annotationlink = [[NSMutableArray alloc] init];
for (int i = 0; i < data.count; i++) {
NSDictionary *dataItem = [data objectAtIndex:i];
//storing annotation in array for link
Annotation *buildingannotation = [[Annotation alloc] init];
NSNumber *index = [NSNumber numberWithInteger:i];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:index, indexKey, buildingannotation, annotationKey, nil];
[annotationlink addObject:dict];
buildingannotation.title = [dataItem objectForKey:#"Building"];
buildingannotation.subtitle = [dataItem objectForKey:#"Info"];
MKCoordinateRegion buildingcoordinates;
buildingcoordinates.center.latitude = [[dataItem objectForKey:#"Latitude"] floatValue];
buildingcoordinates.center.longitude = [[dataItem objectForKey:#"Longitude"] floatValue];
buildingannotation.coordinate = buildingcoordinates.center;
[self.mapView addAnnotation:buildingannotation];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
MKAnnotationView *pinView = (MKAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
MKAnnotationView *customAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
customAnnotationView.canShowCallout = YES;
//right button to detail view
UIButton* disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
customAnnotationView.rightCalloutAccessoryView = disclosureButton;
//left button for image
NSInteger *buildingindex = [self getIndex:annotation];
NSDictionary *dataItem = [data objectAtIndex:buildingindex];
NSString* filename = [dataItem objectForKey:#"Thumb"];
filename = [filename stringByAppendingString:#"#2x.jpg"];
NSString* resourceimagePath = [resourcePath stringByAppendingPathComponent:filename];
Image = [UIImage imageWithContentsOfFile:resourceimagePath];
UIImageView *AnnotationThumb = [[UIImageView alloc] initWithImage:Image];
AnnotationThumb.frame = CGRectMake(0, 0, 31, 31);
customAnnotationView.leftCalloutAccessoryView = AnnotationThumb;
//annotation image
customAnnotationView.image = [UIImage imageNamed:#"Annotation_white.png"];
return customAnnotationView;
return pinView;
}
the following function gets the index of the current annotation using nspredicate to filter the array with the dictionaries. the advantage of this is the fact, that i can also use it when calloutAccessoryControlTapped:
-(NSInteger*) getIndex:(Annotation*)searchannotation
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K == %#", annotationKey, searchannotation];
NSArray *filteredarray = [annotationlink filteredArrayUsingPredicate:predicate];
NSDictionary *building = [filteredarray objectAtIndex:0];
NSInteger *buildingIndex = [[building objectForKey:indexKey] integerValue];
return buildingIndex;
}
With an iPhone 4S the last pin is built 1.14 seconds after the view gets loaded.
if i search the annotation link array manually instead of using nspredicate function like this:
//left button for image
int buildingIndex;
for (int i = 0; i < annotationlink.count; i++) {
NSDictionary *annotationDict = [annotationlink objectAtIndex:i];
if ([[annotationDict objectForKey:annotationKey] isEqual:annotation]) {
buildingIndex= [[annotationDict objectForKey:indexKey] integerValue];
i = annotationlink.count;
}
}
NSDictionary *dataItem = [data objectAtIndex:buildingIndex];
the log says that the last pin is built 1.89 seconds after the viewDidLoad.
if i create the annotations in viewDidApper instead of viewDidLoad the View is shown off course immediately but the background takes some time to load so until the pins are dropped everything is gray which is also not very nice...
Thank you Anna for your suggestions! I implemented the improvements like this:
Annotation.h:
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject <MKAnnotation> {}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#property NSInteger *ID;
#end
Annotation.m:
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate, title, subtitle, ID;
#end
ViewDidAppear:
//creating annotations
for (int i = 0; i < data.count; i++) {
NSDictionary *dataItem = [data objectAtIndex:i];
Annotation *buildingannotation = [[Annotation alloc] init];
buildingannotation.ID = i;
buildingannotation.title = [dataItem objectForKey:#"Building"];
buildingannotation.subtitle = [dataItem objectForKey:#"Subtitle"];
MKCoordinateRegion buildingcoordinates;
buildingcoordinates.center.latitude = [[dataItem objectForKey:#"Latitude"] floatValue];
buildingcoordinates.center.longitude = [[dataItem objectForKey:#"Longitude"] floatValue];
buildingannotation.coordinate = buildingcoordinates.center;
[self.mapView addAnnotation:buildingannotation];
}
viewForAnnotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
MKAnnotationView *pinView = (MKAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
if (pinView == nil) {
MKAnnotationView *customAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
customAnnotationView.canShowCallout = YES;
//right button to detail view
UIButton* disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
customAnnotationView.rightCalloutAccessoryView = disclosureButton;
//left button for image
Annotation *buildingAnnotation = (Annotation *)annotation;
NSInteger *buildingindex = buildingAnnotation.ID;
NSString *filePath = [thumbname objectAtIndex:buildingindex];
UIImageView *AnnotationThumb = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:filePath]];
AnnotationThumb.frame = CGRectMake(0, 0, 31, 31);
customAnnotationView.leftCalloutAccessoryView = AnnotationThumb;
//annotation image
customAnnotationView.image = [UIImage imageNamed:#"Annotation_white.png"];
return customAnnotationView;
} else {
pinView.annotation = annotation;
}
return pinView;
}
Callout:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
Annotation *buildingAnnotation = (Annotation *)view.annotation;
selectedbuilding = buildingAnnotation.ID;
[self performSegueWithIdentifier:#"DetailViewController" sender:self];
}
Takes still some time for showing all Annotations. Is there any chance to further improve the code?
I updated the vievForAnnotation function regarding to Anna's reply and the PhotosByLocation Sample Application. It works now and I hope it's the correct way to implement the reuse...
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
MKAnnotationView *buildingAnnotationView = (MKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
if (buildingAnnotationView) {
[buildingAnnotationView prepareForReuse];
} else {
buildingAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
buildingAnnotationView.canShowCallout = YES;
//right button to detail view
UIButton* disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
buildingAnnotationView.rightCalloutAccessoryView = disclosureButton;
//annotation image
buildingAnnotationView.image = [UIImage imageNamed:#"Annotation_white.png"];
}
//left button for image
Annotation *buildingAnnotation = (Annotation *)annotation;
NSInteger *buildingindex = buildingAnnotation.ID;
NSString *filePath = [thumbname objectAtIndex:buildingindex];
UIImageView *AnnotationThumb = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:filePath]];
AnnotationThumb.frame = CGRectMake(0, 0, 31, 31);
buildingAnnotationView.leftCalloutAccessoryView = AnnotationThumb;
return buildingAnnotationView;
}

how to display data from plist in detail view using segue when map view annotation is pressed

as the title describes i am having trouble displaying the data that i have in my plist for annotations in the map view project i am working on using segue in storyboard. i have the map view and all the annotations (pins) are showing their co ordinates properly. now i want to use segue to transition into a detail view when the user has pressed the detail disclosure button. so far i have the following which is an empty perform segue:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
[self performSegueWithIdentifier:#"Details" sender:view];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
}
the details i want to display in detail view are declared as strings. as follows
#interface ItalyMapDetail : UIViewController{
IBOutlet UIImageView *appImage;
IBOutlet UITextView *appText;
IBOutlet UILabel *appName;
NSString *appImageString;
NSString *appTextString;
NSString *appNameString;
}
#property (nonatomic, retain) NSString *appImageString;
#property (nonatomic, retain) NSString *appTextString;
#property (nonatomic, retain) NSString *appNameString;
#property (nonatomic, strong) UIImage* image;
#end
and in .m file it is as follows
#synthesize appImageString, appTextString, appNameString;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
appImage.image = [UIImage imageNamed:appImageString];
appText.text = appTextString;
appName.text = appNameString;
}
which is truly generic declaration of some strings in detail view. the segue identifier fires and the view transitions to detail view and back properly since i have a navigation controller already. now i know how to declare the strings in prepare for segue when it comes to tableview but i don't know how to declare these details from my plist in the segue in order to display the annotation details in the detail view controller. can anyone give me a hand with this.
oh by the way here is the decleration of the annotations which i derive from plist in my view did load if that helps.
NSMutableArray *annotations = [[NSMutableArray alloc]init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Map" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSArray *anns = [dict objectForKey:#"Italy"];
for(int i = 0; i < [anns count]; i++) {
float realLatitude = [[[anns objectAtIndex:i] objectForKey:#"Latitude"] floatValue];
float realLongitude = [[[anns objectAtIndex:i] objectForKey:#"Longitude"] floatValue];
Annotation *myAnnotation = [[Annotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate = theCoordinate;
myAnnotation.title = [[anns objectAtIndex:i] objectForKey:#"Title"];
myAnnotation.subtitle = [[anns objectAtIndex:i] objectForKey:#"Subtitle"];
[myMapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
i know this might be very easy for most of you guys out there but i am truly stuck and i can use some help in code level.
Edit 1:
here is the code after the changes suggested :
NSMutableArray *annotations = [[NSMutableArray alloc]init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"ItalyMap" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSArray *anns = [dict objectForKey:#"Italy"];
for(int i = 0; i < [anns count]; i++) {
float realLatitude = [[[anns objectAtIndex:i] objectForKey:#"Latitude"] floatValue];
float realLongitude = [[[anns objectAtIndex:i] objectForKey:#"Longitude"] floatValue];
Annotation *myAnnotation = [[Annotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate = theCoordinate;
myAnnotation.title = [[anns objectAtIndex:i] objectForKey:#"Title"];
myAnnotation.subtitle = [[anns objectAtIndex:i] objectForKey:#"Subtitle"];
[myMapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
myAnnotation.annotationData = [anns objectAtIndex:i];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"view for annotation works");
if([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *annotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (!pinView)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
[pinView setPinColor:MKPinAnnotationColorGreen];
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"acolon1.png"]];
pinView.leftCalloutAccessoryView = iconView;
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
// Keep a reference to the callout's annotation data
self.selectedAnnotationData = [(Annotation *)view.annotation annotationData];
[self performSegueWithIdentifier:#"Details" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Details"])
{
ItalyMapDetail *controller = segue.destinationViewController;
controller.annotationData = self.selectedAnnotationData;
}
}
now i have added the dic to the annotation and detail view is imported. the only thing that is not showing still is the strings and the image in the detail view.
You could pass the particular data object to the Annotation using
myAnnotation.annotationData = [anns objectAtIndex:i];
Then in prepareForSegue:sender: you could access the annotation data and pass it to the detail view controller.
Edit: Added sample code
Declare a property on the Annotation class:
#property (nonatomic, strong) NSDictionary *annotationData;
Declare a property on the same view controller as your map view:
#property (nonatomic, strong) NSDictionary *selectedAnnotationData;
And implement the map view delegate method:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
// Keep a reference to the callout's annotation data
self.selectedAnnotationData = [(Annotation *)view.annotation annotationData];
[self performSegueWithIdentifier:#"MY_SEGUE_IDENTIFIER" sender:self];
}
Then pass the annotation data to the subsequent controller in the prepareForSegue:sender: method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showPlattegrondDetails"])
{
ItalyMapDetail *controller = segue.destinationViewController;
controller.annotationData = self.selectedAnnotationData;
}
}
Edit 2: Based on edited question.
Without knowing the names of the keys in the plist, I can only point you in the direction you should be looking.
Your ItalyMapDetail controller should have the annotation data dictionary as provided in prepareForSegue:sender: of the previous controller, it should just be a case of using values from that dictionary to populate your UI...
Update your viewDidLoad method of the ItalyMapDetail controller as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
// temporary test: print out the annotation data so
// we can see what we've got. This shouldn't be nil.
NSLog("Annotation Data: %#", self.annotationData);
// replace these keys with appropriate ones for your plist
appImage.image = [UIImage imageNamed:self.annotationData[#"imageName"]];
appText.text = self.annotationData[#"appText"];
appName.text = self.annotationData[#"appName"];
}

Detail disclosure send data from custom annotation

I have pins showing on a map with data from a JSON string from a db. I set the id of the pin (defined in a custom class) but I need to pass the ID to a action when pressing the detail disclosure button.
It will then open a new view with some information on that pin (via a database and it will lookup the row id and return the data, not sure how im going to do that just yet)
This is the code:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[spinner stopAnimating];
// json parsing
results = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
CustomAnnotation * myAnn;
NSArray *pins = mapView.annotations;
if ([pins count])
{
[mapView removeAnnotations:pins];
}
/* loop through the array, each key in the array has a JSON String with format:
* title <- string
* strap <- string
* id <- int
* date <- date
* lat <- floating point double
* long <- floating point double
* link <- string
*/
int i;
for (i = 0; i < [results count]; i++) {
//NSLog(#"Result: %i = %#", i, results[i]);
//NSLog(#"%#",[[results objectAtIndex:i] objectForKey:#"long"]);
myAnn = [[CustomAnnotation alloc] init];
location.latitude = (double)[[[results objectAtIndex:i] objectForKey:#"lat"] doubleValue];
location.longitude = (double)[[[results objectAtIndex:i] objectForKey:#"long"] doubleValue];
myAnn.coordinate = location;
myAnn.title = [[results objectAtIndex:i] objectForKey:#"title"];
myAnn.subtitle = [[results objectAtIndex:i] objectForKey:#"strap"];
myAnn.pinId = [[results objectAtIndex:i] objectForKey:#"id"];
NSLog(#"id: %i", myAnn.pinId);
[locations addObject:myAnn];
//NSLog(#"%i", [[results objectAtIndex:i] objectForKey:#"lat"]);
}
[self.mapView addAnnotations:locations];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *s = #"ann";
MKAnnotationView *pin = [mapView dequeueReusableAnnotationViewWithIdentifier:s];
if (!pin) {
pin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:s];
pin.canShowCallout = YES;
//pin.image = [UIImage imageNamed:#"pin.png"];
pin.calloutOffset = CGPointMake(0, 0);
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[button addTarget:self
action:#selector(viewDetails) forControlEvents:UIControlEventTouchUpInside];
pin.rightCalloutAccessoryView = button;
}
return pin;
}
-(void)viewDetails{
NSLog(#"press");
}
seems to me that you wish to detect which annotation is selected or its accessory view is clicked.
use the following method
-(void) mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
available to detect the callout tap action. But rather than setting the tag of button, tag the mkannotationView which you will provide for display of you annotation
-(MKAnnotationView*) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
Some of the best tutorials are
http://www.raywenderlich.com/21365/introduction-to-mapkit-in-ios-6-tutorial

Resources