Customize map annotations from plist - iphone

I found a short guide on how to load "annotation data" from a plist and add those annotations (pins) to a MapView.
My question is if anyone can tell me how I would customize the pins the most easily? As an example, I would like to define a color and an image in the plist and then have it set when adding the pins.
The pins are added like this:
MyAnnotation.m:
#implementation MyAnnotation
#synthesize title, subtitle, coordinate;
-(void) dealloc {
[super dealloc];
self.title = nil;
self.subtitle = nil;
}
MyAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* subtitle;
Running through the plist in ViewDidLoad in MapViewController.m (array containg dictionaries for each pin) and adding annotations.
NSString *path = [[NSBundle mainBundle] pathForResource:#"Annotations" ofType:#"plist"];
NSMutableArray* anns = [[NSMutableArray alloc] initWithContentsOfFile:path];
for(int i = 0; i < [anns count]; i++) {
float realLatitude = [[[anns objectAtIndex:i] objectForKey:#"latitude"] floatValue];
float realLongitude = [[[anns objectAtIndex:i] objectForKey:#"longitude"] floatValue];
MyAnnotation* myAnnotation = [[MyAnnotation 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"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
[myAnnotation release];
}
EDIT:
I have added the viewForAnnotation method which sets the color but how can I set the color of each pin individually?
-(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;
}

Solved! It can be done like this in the viewForAnnotation method:
for(MyAnnotation* a in mapView.annotations) {
if(annotation == a && annotation != mapView.userLocation) {
pinView.image = [UIImage imageNamed:a.annImage];
}
}

Related

How to add different titles and subtitles to different Annotation points in a MapView?

I am displaying different annotation points in a mapview. I want to display different titles and subtitles for all the different annotations. I have my viewForAnnotation delegate method implemented in the below manner.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
{
NSLog(#"annotation Class %#", [annotation class]);
if ([annotation isKindOfClass:[HGMovingAnnotation class]]) {
static NSString *kMovingAnnotationViewId = #"HGMovingAnnotationView";
HGMovingAnnotationView *annotationView = (HGMovingAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:kMovingAnnotationViewId];
if (!annotationView) {
annotationView = [[HGMovingAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:kMovingAnnotationViewId];
}
//configure the annotation view
annotationView.image = [UIImage imageNamed:#"symbol-moving-annotation.png"];
annotationView.bounds = CGRectMake(0, 0, 20, 20); //initial bounds (default)
annotationView.mapView = mapView;
NSLog(#"Inside Moving Annotation");
return annotationView;
}
static NSString *kCustomAnnotationView = #"CustomAnnotationView";
MKPinAnnotationView* customPinView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:kCustomAnnotationView];
if ([annotation isKindOfClass:[CLLocation class]]) {
MKAnnotationView *customAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:kCustomAnnotationView];
customAnnotationView.image = [UIImage imageNamed:#"customAnnotation"];
customAnnotationView.canShowCallout = NO;
customAnnotationView.centerOffset = CGPointMake(2,-12);
NSLog(#"Inside Custom Annotation1");
return customAnnotationView;
} else {
customPinView.annotation = annotation;
customPinView.pinColor = MKPinAnnotationColorPurple;
NSLog(#"Inside Custom Annotation2");
return customPinView;
}
}
I want to display the title and subTitle for the customPinView Annotations. Please help me.
Annotation views do not have a title or subtitle. You need to subclass MKAnnotation and set the (sub)title on the custom annotation. The viewForAnnotation method is not the right place for this, you should call [annotation setTitle:#"my title"] right before [mapView addAnnotation:annotation].
Sample code:
#interface MyCustomAnnotation : NSObject <MKAnnotation> {
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic) CLLocationCoordinate2D coordinate;
#end
I have tried the approach suggested by phix23 and came with the following code. It works..
titleArray = [[NSArray alloc]initWithObjects:#"First Point",#"Second Point",#"Third Point",#"Fourth Point",#"Fifth Point", nil];
subTitleArray = [[NSArray alloc]initWithObjects:#"Restaurant",#"Park",#"Hotel",#"Theatre",#"AmusementPark", nil];
NSInteger customAnnotationCount = annotations.count;
//CLLocationCoordinate2D coordinates[customAnnotationCount];
for (NSInteger index = 0; index < customAnnotationCount; index++) {
CLLocation *location = [annotations objectAtIndex:index];
NSString *titleString = [titleArray objectAtIndex:index];
NSString *subTitleString = [subTitleArray objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
//coordinates[index] = coordinate;
CustomAnnotations *customAnnotation = [[CustomAnnotations alloc]initWithCoordinates:coordinate placeName:titleString description:subTitleString];
[_mapView addAnnotation:customAnnotation];
[customAnnotation release];
}
"annotations" is the array that contains Location points. _mapView is my MKMapView. CustomAnnotations is an NSObject Class implementing MKAnnotation protocol in the same way described on the top.

I can't add annotations in the mapview by using latitude and longitude

I have read the latitudes and longitudes from an xml file, and I want to add some annotations with them. But except the user location, none of them was added.The count of mapview.annotations is always empty.Here is my code:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (newLocation != nil) {
self.myLocation = newLocation;
}
mapView.region = MKCoordinateRegionMake(self.myLocation.coordinate, MKCoordinateSpanMake(0.005f, 0.005f));
mapView.zoomEnabled = YES;
//mapView.showsUserLocation = YES;
mapView.centerCoordinate = self.myLocation.coordinate;
MKPointAnnotation *userLocation = [[MKPointAnnotation alloc] init];
userLocation.coordinate = myLocation.coordinate;
userLocation.title = #"my position";
userLocation.subtitle = #"my position now";
[mapView removeAnnotations:mapView.annotations];
[mapView addAnnotation:userLocation];
[userLocation release];
if ([self.positionArray count] < 5) {
NSString *dataPath = [[NSBundle mainBundle] pathForResource:#"position" ofType:#"xml"];
NSData *positionData = [[NSData alloc] initWithContentsOfFile:dataPath];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:positionData];
parser.delegate = self;
[parser parse];
}
if (self.myLocation != nil) {
[self.manager stopUpdatingLocation];
}
}
And here is the MapInfo class:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface MapInfo : NSObject<MKAnnotation>
{
NSString *subtitle;
NSString *title;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithCoordinate:(CLLocationCoordinate2D)location;
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;
#end
Then here is the delegate method
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *AnnotationIdentifier = #"AnnotationIdentifer";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if ([annotation isKindOfClass:[MapInfo class]]) {
if (pinView == nil) {
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
}
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = NO;
}else if([annotation isKindOfClass:[MKPointAnnotation class]])
{
if (pinView == nil) {
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
}
pinView.pinColor = MKPinAnnotationColorPurple;
pinView.canShowCallout = YES;
pinView.animatesDrop = NO;
}
return pinView;
}
I really don't know why only the user location can be added,someone help me please!!It has bothered me for several days!
Looks like you may have forgotten to set the mapView's delegate.

unable to display custom Annotations on the map in iPhone

I am trying to add annotations on my mapview but I am not able to add them. Can someone suggest me where I am doing wrong? Code: Code to add the map:
mapview = [[MKMapView alloc] initWithFrame:CGRectMake(10, 175, 300, 268)];
mapview.delegate = self;
mapview.userInteractionEnabled = TRUE;
[mapview setZoomEnabled:TRUE];
[mapview setScrollEnabled:TRUE];
mapview.showsUserLocation = TRUE;
[self.view addSubview:mapview];
//adding annotations in another method:
for (id annotation in mapview.annotations) {
[mapview removeAnnotation:annotation];
}
for(int i =0;i<arrEventList.count;i++){
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = [[NSString stringWithFormat:#"%#",[(NSDictionary*)[arrEventList objectAtIndex:i] objectForKey:#"lat"]] floatValue];
theCoordinate.longitude = [[NSString stringWithFormat:#"%#",[(NSDictionary*)[arrEventList objectAtIndex:i] objectForKey:#"lng"]] floatValue];
MyLocation *annotation = [[[MyLocation alloc] initWithName:[(NSDictionary*)[arrEventList objectAtIndex:i] objectForKey:#"event"] address:[(NSDictionary*)[arrEventList objectAtIndex:i] objectForKey:#"place"] coordinate:theCoordinate] autorelease];
[mapview addAnnotation:annotation];
//[annotations addObject:myAnno.annotation];
}
// delegate method:
- (MKAnnotationView *) mapView: (MKMapView *) mapView viewForAnnotation: (id<MKAnnotation>) annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image=[UIImage imageNamed:#"annotation.png"];//here we use a nice image instead of the default pins
return annotationView;
}
return nil;
}
Above delegate method is only called for self location but it is not called for other annotations that I want to add.
Can someone point me to my mistakes
#interface MyLocation : NSObject <MKAnnotation> {
NSString *_name;
NSString *_address;
CLLocationCoordinate2D _coordinate;
}
#property (copy) NSString *name;
#property (copy) NSString *address;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithName:(NSString*)name address:(NSString*)address coordinate:(CLLocationCoordinate2D)coordinate;
#end
//Mylocation class:
#implementation MyLocation
#synthesize name = _name;
#synthesize address = _address;
#synthesize coordinate = _coordinate;
- (id)initWithName:(NSString*)name address:(NSString*)address coordinate:(CLLocationCoordinate2D)coordinate {
if ((self = [super init])) {
_name = [name copy];
_address = [address copy];
_coordinate = coordinate;
}
return self;
}
- (NSString *)title {
if ([_name isKindOfClass:[NSNull class]])
return #"Unknown charge";
else
return _name;
}
- (NSString *)subtitle {
return _address;
}
I found the problem. My code is correct. The values of latittude and longitudes were some how interchanged. My mistake but I have corrected it now

How to show multiple pin annotation in map?

I m showing a pin annotation statically, but i want to do it dynamically to show a lot of pins on map with title and subtitle.
Thx in advance.
I have an array of dictionaries with have two objects lat, long and i am doing this -
if ([resultArray count])
{
for (int i =0; i < [resultArray count]; i++)
{
NSDictionary *dict = [resultArray objectAtIndex:i];
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = [[dict objectForKey:#"lat"] floatValue];
region.center.longitude = [[dict objectForKey:#"long"] floatValue];
region.span.longitudeDelta = 70.0f;
region.span.latitudeDelta = 70.0f;
MyAnnotations *ann = [[MyAnnotations alloc] init];
ann.title = #"title";
ann.coordinate = region.center;
[mapView addAnnotation:ann];
}
}
//
// MyAnnotation.h
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
//
// MyAnnotation.m
//
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize coordinate,title,subtitle;
-(void)dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
#end
use this delegate for callout -
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id )annotation
{
MKPinAnnotationView *pinView = nil;
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;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[infoButton addTarget:self action:#selector(infoButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = infoButton;
[defaultPinID release];
return pinView;
}

mapkit , tagging a disclosure button with index of annotation

i have been struggling with this for a few days, i even re-wrote half the code to try it another way.
i have my annotations imported from a csv, and placed onto the map with tile and subtitle, i am trying in vain to add a tag to disclosue buttons so i can see which one was tapped, but having problems, whatever values i assign to the annotation i cant seem to access them (like the index) i can access the title and subtitle, but thats it.
how do i assign a index to the annotation that i can then add to the button as a tag, so i can record the tap
here is my code
NSURL *dataUrl = [NSURL URLWithString:#"http://nne.ezadspro.co.uk/cms/testmap.txt"];
// URLWithString:#"http://neic.usgs.gov/neis/gis/qed.asc"];
NSString *fileString = [NSString stringWithContentsOfURL:dataUrl
encoding:NSUTF8StringEncoding
error:nil];
int count = 0;
NSScanner *scanner = [NSScanner scannerWithString:fileString];
points = [[NSMutableArray array] retain];
AnnotationData *event;
NSString *line;
NSArray *values;
while ([scanner isAtEnd] == NO) {
[scanner scanUpToString:#"\n" intoString:&line];
//skip the first line
if(count > 0) {
values = [line componentsSeparatedByString:#","];
event = [[[AnnotationData alloc] init] autorelease];
event.latitude = [[values objectAtIndex:5] floatValue];
event.longitude = [[values objectAtIndex:6] floatValue];
event.companyID = [[values objectAtIndex:0]intValue];
event.title = [values objectAtIndex:1];
event.subtitle = [values objectAtIndex:2];
//event.magnitude = [[values objectAtIndex:4] floatValue];
//event.depth = [[values objectAtIndex:5] floatValue];
//NSLog(#"%#",event.companyID);
[points addObject:event];
}
count++;
if(count == 300) {
//limit number of events to 300
break;
}
}
for (int i=0; i<points.count; i++) {
AnnotationData *annData = [points objectAtIndex:i];
coordinate.latitude = annData.latitude;
coordinate.longitude = annData.longitude;
CLLocationCoordinate2D newCoord = {coordinate.latitude, coordinate.longitude};
PlaceAnnotation* annotation = [[PlaceAnnotation alloc] initWithCoordinate:newCoord andID:i];
annotation.mTitle = annData.title;
annotation.mSubtitle = annData.subtitle;
annotation.indexID = i;
//annotation.indexID = [[i]intValue];
[mapView addAnnotation:annotation];
[annotation release];
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinAnnotation = nil;
if(annotation != mV.userLocation)
{
static NSString *defaultPinID = #"myPin";
pinAnnotation = (MKPinAnnotationView *)[mV dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinAnnotation == nil )
pinAnnotation = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinAnnotation.canShowCallout = YES;
//instatiate a detail-disclosure button and set it to appear on right side of annotation
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotation.rightCalloutAccessoryView = infoButton;
//infoButton.tag =
//[infoButton addTarget:self action:#selector(onMapVenueSelect) forControlEvents:UIControlEventTouchUpInside];
//defaultPinID.rightCalloutAccessoryView = infoButton;
//infoButton.tag = [event indexOfObject:tmpVenueData];
// [defaultPinID release];
}
return pinAnnotation;
[pinAnnotation release];
}
thanks
Consider using the MKAnnotation protocol and storing whatever you need ID or data wise your object.
A starting point header might go something like this:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface YourFancyAnnotationClass : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSNumber *companyID;
}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#property(nonatomic, copy) NSNumber *companyID;
#end
Then in your delegate do something like this...
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"calloutAccessoryControlTapped:");
YourFancyAnnotationClass *tappedSite = (SiteAnnotation *)[view annotation];
NSNumber *companyIDThatWasClickedExample = [tappedSite companyID];
etc...