I know this is a question asked a lot. I have been reading through many of the questions on here regarding this for a while. I was hoping someone would have a simpler way using the code I have to replace the pins on my map with an image. I am still very new to objective c.The code I have is very short and easy. Most of what I have found online to post pins to a map is very long and drawn out. I have the following classes and controllers for my map view:
LocationsViewController.h
#import "TechBookAppDelegate.h"
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface LocationsViewController : UIViewController <MKMapViewDelegate>
{
IBOutlet MKMapView *worldView;
IBOutlet UIActivityIndicatorView *activityIndicator;
}
#end
LocationsViewController.m
#import "LocationsViewController.h"
#import "MapAnnotation.h"
#interface LocationsViewController ()
#end
#implementation LocationsViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Initialization code
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
CLLocationCoordinate2D wisconsin = {.latitude = xx.xxxxxxx, .longitude = -xx.xxxxxx};
CLLocationCoordinate2D pennsyvainia = {.latitude = xx.xxxxxxx, .longitude = -xx.xxxxxx};
CLLocationCoordinate2D nevada = {.latitude = xx.xxxxxxx, .longitude = -xx.xxxxxx};
CLLocationCoordinate2D texas = {.latitude = xx.xxxxxxx, .longitude = -xx.xxxxxx};
MapAnnotation *pinWI = [[MapAnnotation alloc] initWithCoordinate: wisconsin];
MapAnnotation *pinPA = [[MapAnnotation alloc] initWithCoordinate: pennsyvainia];
MapAnnotation *pinNV = [[MapAnnotation alloc] initWithCoordinate: nevada];
MapAnnotation *pinTX = [[MapAnnotation alloc] initWithCoordinate: texas];
[worldView addAnnotation:pinTX];
[worldView addAnnotation:pinNV];
[worldView addAnnotation:pinWI];
[worldView addAnnotation:pinPA];
}
MapAnnotation.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D _coordinate;
MKAnnotationView *mapView;
}
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate;
#end
MapAnnotation.m
#import "MapAnnotation.h"
#import "LocationsViewController.h"
#implementation MapAnnotation
#synthesize coordinate = _coordinate;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
{
self = [super init];
if (self != nil)
{
_coordinate = coordinate;
}
return self;
}
#end
I have tried to implement methods similar to this:
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{.......
with various types of code but to no avail. Not sure what I am doing wrong. Isn't there a shorter way to do what I am thinking than this than what I have seen so far online.
I was hoping there was something similar to :
MapAnnotation *pinWI = [[[MapAnnotation alloc] initWithCoordinate: wisconsin] initWithPinImage:#"imagename.png"];
or could I implement something similar to this:
pinWI:MKPinAnnotationColorGreen;
only with a image location defined?
or something along those lines. Thanks in advance for everyones help and patience with a newbie.
I really need to change the pin to a custom image. One coding schema I tried was this:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID] autorelease];
}
annotationView.image = [UIImage imageNamed:#"location.png"];
annotationView.annotation = annotation;
return annotationView;
}
WORKING CODE:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView *annotationView = (MKAnnotationView *)[worldView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}
annotationView.image = [UIImage imageNamed:#"locations_marker.png"];
annotationView.annotation = annotation;
return annotationView;
}
add the type property(example-firstPin, secondPin,thirdPin etc) to your custom MapViewAnnotation class.
MapViewAnnotation *newAnnotation = [[MapViewAnnotation alloc] init...
newAnnotation.type = #"firstPin"; // <-- set property in annotation
[self.mapView addAnnotation:newAnnotation];
and in your - (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation method put a simple check
MapViewAnnotation *mvAnn = (MapViewAnnotation *)annotation;
if ([mvAnn.type isEqualToString:#"firstPin"])
{
annView.pinColor = MKPinAnnotationColorGreen;
}
else if ([mvAnn.type isEqualToString:#"secondPin"])
{
annView.pinColor = MKPinAnnotationColorRed;
}
else if ([mvAnn.type isEqualToString:#"thirdPin"])
{
annView.pinColor = MKPinAnnotationColorOrange;
}
Related
I have written simple mapView application.It is showing two kind of problems.
1- Execution is stopping on Thread 1: signal SIGABRT error.
2- This function is showing compile time error .
- (IBAction)findMe:(id)sender {
If( [[toggleButton titleForState:UIControlStateNormal] isEqualToString:#"Find Me"] )
{
[toggleButton setTitle:#"Hide Me" forState:UIControlStateNormal];
mapView.showsUserLocation=YES;
}
else
{
[toggleButton setTitle:#"Find Me" forState:UIControlStateNormal];
mapView.showsUserLocation=NO;
}
}
How to remove these error ?
I want put coordinates of more then one location in my code i want to show loc.png icon on map corresponding to those coordinates how i can accomplish this task?
You can see the sample project from this link: https://drive.google.com/open?id=0B5pNDpbvZ8SnRmNFS0pjVnJFWHc
You are getting compile time error for 3 reasons:
1) The "If" you are using in if-else condition should be "if" i.e lowercase.
2). You have an IBOutlet connect to findMe button in storyboard which do not exist in your view controller. So either remove it or add it.
3)You are using MKMapView but you didn't added the MapKit Framework in "Link Binaries" in build phases option of your project.
Please do all these steps to have your code compiled & executed error free.
Answer to your query:
I want put coordinates of more then one location in my code i want to show loc.png icon on map corresponding to those coordinates how i can accomplish this task?
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.m
#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:#"loc.png"];
[annotationArray addObject:annotation1];
[self.myMapView addAnnotations:annotationArray];
[annotationArray removeAllObjects];
CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(25.085130, -77.336428);
MyAnnotation *annotation2 = [[MyAnnotation alloc] initWithCoordinates:location2 image:#"loc.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:#"loc.png"];
if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:#"pin2.png"])
annotationView.image = [UIImage imageNamed:#"loc.png"];
return annotationView;
}
return nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Add new files MyAnnotation.h/MyAnnotation.m
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
I want to use my Pin (not default).
I tried above code. First, I can see default pin. When I touched showMyLocation, after I touched sightLocation, default pin change with my custom pin. I want to show my custom pin in first view.
TOCGSightAnnotation.h
#interface TOCGSightAnnotation : NSObject <MKAnnotation>
#property (strong, nonatomic) NSString *title;
#property (nonatomic,assign) CLLocationCoordinate2D coordinate;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate title:(NSString *)title;
#end
TOCGSightAnnotation.m
#implementation TOCGSightAnnotation
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate title:(NSString *)title
{
if ((self = [super init])) {
self.coordinate =coordinate;
self.title = title;
}
return self;
}
#end
TOCGSightseeingMapKitViewController.h
#interface TOCGSightseeingMapKitViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>
#property (strong) NSNumber *latitude;
#property (strong) NSNumber *longitude;
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (strong, nonatomic) CLLocationManager * locationManager;
#end
TOCGSightseeingMapKitViewController.m
#import "TOCGSightseeingMapKitViewController.h"
#import "TOCGSightAnnotation.h"
CLLocationCoordinate2D sightCoordinate;
MKCoordinateRegion region;
#interface TOCGSightseeingMapKitViewController ()
#end
#implementation TOCGSightseeingMapKitViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[self.locationManager startUpdatingLocation];
sightCoordinate = CLLocationCoordinate2DMake([self.latitude doubleValue], [self.longitude doubleValue]);
TOCGSightAnnotation *annotation = [[TOCGSightAnnotation alloc] initWithCoordinate:sightCoordinate title:#"Sight Title"];
[self.mapView addAnnotation:annotation];
region =
MKCoordinateRegionMakeWithDistance(sightCoordinate, 500, 500);
[self.mapView setRegion:region animated:YES];
}
- (IBAction)myLocation:(id)sender
{
self.mapView.delegate = self;
self.mapView.showsUserLocation = YES;
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
}
- (IBAction)sightLocation:(id)sender
{
[self.mapView setRegion:region animated:YES];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
if ([annotation isKindOfClass:[TOCGSightAnnotation class]])
{
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView
dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"CustomPinAnnotationView"];
pinView.image = [UIImage imageNamed:#"mapIcon.png"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
}
else
pinView.annotation = annotation;
return pinView;
}
return nil;
}
The reason is simple. The method
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation
will get called only if you set the MKMapViewDelegate. As long as you didn't touch the button that calls the IBAction
- (IBAction)myLocation:(id)sender
the delegate is not set, so the delegate methods are not called. Try moving the line
self.mapView.delegate = self;
after your MKMapView allocation.
I tried this and it works.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[self.locationManager startUpdatingLocation];
}
- (void)viewDidAppear:(BOOL)animated
{
self.mapView.delegate = self;
sightCoordinate = CLLocationCoordinate2DMake([self.latitude doubleValue], [self.longitude doubleValue]);
TOCGSightAnnotation *annotation = [[TOCGSightAnnotation alloc] initWithCoordinate:sightCoordinate title:#"Sight Title"];
[self.mapView addAnnotation:annotation];
region =
MKCoordinateRegionMakeWithDistance(sightCoordinate, 500, 500);
[self.mapView setRegion:region animated:YES];
}
I have this code that displays 4 points on a map with a custom image. I have begun to learn that perhaps the way I structured it is not optimal but it is what I have.
Please help me to learn how to make the titles I created show up on the map with the custom poi when someone taps it.
I have two classes that work with the view. The classes are MapAnnotation and LocationsViewController.
Here is the code for each.
MapAnnotation.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapAnnotation : NSObject <MKAnnotation, MKMapViewDelegate>
{
CLLocationCoordinate2D _coordinate;
NSString * title;
}
#property (nonatomic, copy) NSString *title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate;
#end
MapAnnotation.m
#import "MapAnnotation.h"
#import "LocationsViewController.h"
#implementation MapAnnotation
#synthesize coordinate = _coordinate;
#synthesize title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
{
self = [super init];
if (self != nil)
{
_coordinate = coordinate;
}
return self;
}
#end
LocationsViewController.h
#import "TechBookAppDelegate.h"
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface LocationsViewController : UIViewController <MKMapViewDelegate, MKAnnotation>
{
IBOutlet MKMapView *worldView;
IBOutlet UIActivityIndicatorView *activityIndicator;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation;
#end
LocationsViewController.m
#import "LocationsViewController.h"
#import "MapAnnotation.h"
#interface LocationsViewController ()
#end
#implementation LocationsViewController
#synthesize coordinate = _coordinate;
#synthesize title;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Initialization code
}
return self;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}
annotationView.image = [UIImage imageNamed:#"app_icon_sm.png"];
annotationView.annotation = annotation;
return annotationView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
worldView.showsUserLocation = NO;
CLLocationCoordinate2D wisconsin = {.latitude = 45.620775, .longitude = -89.47844};
CLLocationCoordinate2D pennsyvainia = {.latitude = 39.912417, .longitude = -77.663268};
CLLocationCoordinate2D nevada = {.latitude = 36.054362, .longitude = -115.020470};
CLLocationCoordinate2D texas = {.latitude = 32.555038, .longitude = -94.295592};
MapAnnotation *pinWI = [[MapAnnotation alloc] initWithCoordinate: wisconsin] ;
MapAnnotation *pinPA = [[MapAnnotation alloc] initWithCoordinate: pennsyvainia];
MapAnnotation *pinNV = [[MapAnnotation alloc] initWithCoordinate: nevada];
MapAnnotation *pinTX = [[MapAnnotation alloc] initWithCoordinate: texas];
//UIImage *star = [UIImage imageNamed:#"locations_marker.png"];
//////////////////
pinWI.title = #"Rhinelander, WI";///////
pinPA.title = #"Chambersburg, PA";//////I dont understand why these do not output a
pinNV.title = #"Henderson, NV";/////////title if the title property is a part of the
pinTX.title = #"Marshall, TX";////////// MKAnnotation
//////////////////
[worldView addAnnotation:pinTX];
[worldView addAnnotation:pinNV];
[worldView addAnnotation:pinWI];
[worldView addAnnotation:pinPA];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I suppose I need a function to create the titles? I really am hoping I do not have to create more classes to do this.
Your main question is:
How to make the titles I created show up on the map with the custom poi when someone taps it.
In the viewForAnnotation delegate method, you need to set the canShowCallout property of the annotation view to YES (the default is NO):
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation...
annotationView.canShowCallout = YES; // <-- add this line
}
Some additional comments unrelated to the question:
In MapAnnotation.h, this class will only be implementing MKAnnotation, not MKMapViewDelegate so remove it from the protocol list to avoid potential compiler warnings and to make the code clearer and cleaner:
#interface MapAnnotation : NSObject <MKAnnotation>
In MapAnnotation.m, you don't need the #import "LocationsViewController.h". Remove it.
In LocationsViewController.h, this class will not be implementing MKAnnotation so remove it from the protocol list to avoid potential compiler warnings and to make the code clearer and cleaner:
#interface LocationsViewController : UIViewController <MKMapViewDelegate>
Also in LocationsViewController.h, it's unnecessary to declare the delegate methods you'll be implementing. You can remove the viewForAnnotation declaration.
In LocationsViewController.m, the #synthesizes for coordinate and title don't belong here. Remove them.
-(void)locatePlaceonMap:(NSDictionary*)dic
{
[map_bar setScrollEnabled:YES];
map_bar.delegate = self;
MKCoordinateRegion zoomIn = map_bar.region;
zoomIn.span.latitudeDelta = 0.1f;
zoomIn.span.longitudeDelta = 0.1f;
zoomIn.center.latitude = ApplicationDelegate.latitude;
zoomIn.center.longitude = ApplicationDelegate.longitude;
[map_bar setRegion:zoomIn animated:NO];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc]init];
annotation.title = [dic valueForKey:#"vName"];
annotation.subtitle = [dic valueForKey:#"t_long_address"];
CLLocationCoordinate2D newlocation = [map_bar.userLocation coordinate];
newlocation.latitude=[[dic valueForKey:#"dLat"]doubleValue];
newlocation.longitude=[[dic valueForKey:#"dLong"]doubleValue];
annotation.coordinate = newlocation;
[map_bar addAnnotation:annotation];
}
#pragma mark MkMapViewDelegate Methods
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation: (id<MKAnnotation>)annotation
{
MKPinAnnotationView *pinView = nil;
static NSString *defaultPinID = #"ReusedPin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
if (annotation == mapView.userLocation) {
return nil;
}else{
pinView.image = [UIImage imageNamed:#"pin_trophy.png"];
pinView.pinColor = MKPinAnnotationColorRed;
}
pinView.canShowCallout = YES;
pinView.animatesDrop = NO;
return pinView;
}
I am trying to create draggable custom pin with Title popup with MapKit. but when I implement viewForAnnotation to make PIN appear as custom image, its disappears pop title as if I youch Pin on map it does not show titla popup,
while if I comments viewForAnnotation it works fine, but I want both things custom image and popup title when tap pin.
below is code
- (void)viewDidLoad
{
MKCoordinateRegion newRegion = MKCoordinateRegionMakeWithDistance(LocCoordinate, 20000, 20000);
DDAnnotation *point = [[DDAnnotation alloc] init];
[point setCoordinate:mapCenter];
[point setTitle:#"Where am I"];
[point setSubtitle:#"I am here"];
[self.mvTripMap addAnnotation:point];
[self.mvTripMap setRegion:newRegion animated:YES];
[super viewDidLoad];
}
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView *annotationView=[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:cabAnnotationIdentifier];
annotationView.image=[UIImage imageNamed:#"start.png"];
annotationView.draggable = YES;
}
return annotationView;
}
DDAnnotation.h
#import <MapKit/MapKit.h>
#interface DDAnnotation : MKPlacemark {
CLLocationCoordinate2D coordinate_;
NSString *title_;
NSString *subtitle_;
}
// Re-declare MKAnnotation's readonly property 'coordinate' to readwrite.
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
#end
DDAnnotation.m
#import "DDAnnotation.h"
#implementation DDAnnotation
#synthesize coordinate = coordinate_;
#synthesize title = title_;
#synthesize subtitle = subtitle_;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary *)addressDictionary {
if ((self = [super initWithCoordinate:coordinate addressDictionary:addressDictionary])) {
self.coordinate = coordinate;
}
return self;
}
#end
Just put annotationView.canShowCallout= YES; and it will work
updated code
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView *annotationView=[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:cabAnnotationIdentifier];
annotationView.image=[UIImage imageNamed:#"start.png"];
annotationView.draggable = YES;
annotationView.canShowCallout= YES;
}
return annotationView;
}
I'm having trouble getting the MKAnnotationViews show up on the map in MapKit. I'm using iOS 7, and have now searched the forums and the web for many hours, trying different samples and setups.
Below I have the most basic setup possible (I think) to make it work. The app contains a single ViewController with a toolbar with a button on top, and the rest is the MapView. The button triggers the method zoomToUser:(UIBarButtonItem*)sender. Right-clicking and checking my outlets and delegates seem to be correct. I have some NSLog-statements being triggered to output some debug info.
First the VC:
#import "ViewController.h"
#import "Data.h"
#interface ViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
- (IBAction)zoomToUser:(UIBarButtonItem *)sender;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.showsUserLocation = YES;
Data *ann = [[Data alloc] init];
[self.mapView addAnnotation:ann];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self zoomToUser:nil];
}
-(IBAction)zoomToUser:(UIBarButtonItem *)sender
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 2000, 2000);
NSLog(#"region: %f x %f",self.mapView.userLocation.coordinate.latitude,self.mapView.userLocation.coordinate.longitude);
[self.mapView setRegion:region animated:YES ];
NSArray *arr = self.mapView.annotations;
for(int i = 0, max = arr.count; i < max; i++)
{
id<MKAnnotation> annotation = arr[i];
NSLog(#"%d of %d: %# (%#)",i+1,max,annotation.title, [annotation class]);
}
}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
NSString *reuseId = #"Test";
if([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
else if( [annotation isKindOfClass:[Data class]])
{
MKAnnotationView *annov = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if(!annov)
{
annov = [[MKAnnotationView alloc]initWithAnnotation:annotation
reuseIdentifier:reuseId];
}
else
{
annov.annotation = annotation;
}
annov.canShowCallout = YES;
NSLog(#"Title: %#",annotation.title);
return annov;
}
else
{
return nil;
}
}
#end
And the Data class:
#import "Data.h"
#implementation Data
-(NSString *)title
{
return #"The title";
}
-(NSString *)subtitle
{
return #"A subtitle";
}
-(CLLocationCoordinate2D)coordinate
{
CLLocationCoordinate2D coordinate;
coordinate.latitude = 60.123456;
coordinate.longitude = 10.123456;
return coordinate;
}
#end
The Data.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Data : NSObject <MKAnnotation>
#end
And the ViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController
#end
As you can see the viewForAnnotation-method prints the annotations title in console when it's requested, and each time the map pans the area, it prints.
Pressing the BarButton and triggering the zoomToUser:-method logs to console that the map indeed has two annotations, the MKUserLocation and the one I added.
How come my MapView tells me it has the annotation, it asks for the view, it gets the view, but it does not show it?
In viewForAnnotation, the code is creating and returning an MKAnnotationView for annotations of type Data.
The MKAnnotationView class, by default, creates an empty view.
That is, its image property is nil and the view basically contains no content.
So, as-is, the annotation views are being created and added but they are invisible.
You can either:
Set the image property on the MKAnnotationView:
annov.image = [UIImage imageNamed:#"something"];
Or, simpler, create an MKPinAnnotationView instead which is a convenient subclass of MKAnnotationView that displays a pin image for you:
MKPinAnnotationView *annov = (MKPinAnnotationView *)[mapView dequeue...
if(!annov)
{
annov = [[MKPinAnnotationView alloc]initWithAnnotation:annotation
reuseIdentifier:reuseId];
annov.pinColor = MKPinAnnotationColorRed; //or Green or Purple
}
else
...
Unrelated:
You've created a custom annotation class Data which is fine but if all you need are the three properties title, subtitle, and coordinate, then you can just use the pre-defined MKPointAnnotation class which lets you set all the properties per-instance:
MKPointAnnotation *ann = [[MKPointAnnotation alloc] init];
ann.title = #"The title";
ann.subtitle = #"A subtitle";
ann.coordinate = CLLocationCoordinate2DMake (60.123456, 10.123456);
[self.mapView addAnnotation:ann];