I want to change the callout shown on the MKMapView. When I call
[self.mapView selectAnnotation:annotation animated:YES];
it pans the map to the annotation, but does not show its callout. How do I get it to show the callout?
Set the title, and optionally the subtitle property on the annotation object. MapKit will automatically show a callout.
#interface MyAnnotation : NSObject <MKAnnotation> {
NSString *title;
NSString *subtitle;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
And the implementation,
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize title, subtitle;
#end
Usage,
MyAnnotation *foo = [[MyAnnotation alloc] init];
foo.title = #"I am Foo";
foo.subtitle = "I am jus' a subtitle";
You should implement the MKAnnotation Delegate method
-(MKAnnotationView *)mapView:(MKMapView *)_mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *AnnotationViewIdentifier = #"AnnotationViewIdentifier";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewIdentifier];
if (annotationView == nil)
{
annotationView = [[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:AnnotationViewIdentifier]autorelease];
}
annotationView.canShowCallout = YES;
return annotationView;
}
Related
I have eventually succeeded with getting the index for the annotation clicked on at callOutAccecoryControlTapped-method. :)
I have made a custom annotation class called Annotation (Annnotation *ann) which I fill with values from my db at parse.com.
But now I don't know how to pass the values on to my next view LAOpeningHoursViewController?
I can see all the values when I am debugging and *ann (se code) has for example: ann.cname="Olles cafe" etc. So that is good.
I pass the whole ann-object on to my next view. But I don't know how to get for example ann.cname on to my 'self.myLabel.text'. I show you the code:
If you have the kindness to answer me, please explain very well because I am a beginner.
Best is if you could have the trouble writing a code-snippet here… ;)
This is some code of the first view:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pinView"];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"pinView"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = rightButton;
} else {
pinView.annotation = annotation;
}
return pinView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
Annotation *ann = [[mapView selectedAnnotations] objectAtIndex:0];
NSLog(#"ann.subtitle = %#", ann.subtitle);
NSLog(#"ann.cid = %#", ann.cid);
NSLog(#"ann.cstr = %#", ann.cstr);
NSLog(#"ann.cname = %#", ann.cname);
//this works fine, I get all the values
[self performSegueWithIdentifier: #"openingHours" sender:ann];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"openingHours"]) {
LAOpeningHoursViewController *secondView = (LAOpeningHoursViewController*)segue.destinationViewController;
//PFObject *tempObject = [[myMapView selectedAnnotations] objectAtIndex:0];
Annotation *ann = (id)sender;
//Here is the problem: What to pass? I want to pass for example ann.cname that is declared in my custom annotation
//Both 'ann' and 'tempObject' has the right values for cname but I dont know how to pass it to the next view
secondView.myLabel.text = self.stringToPass;
//secondView.myLabel.text = ann.cname;
}
}
And here is the code from the second view called LAOpeningHoursViewController, that should receive the data:
- (void)viewDidLoad
{
[super viewDidLoad];
self.myLabel.text = ann.cname;
//recieving an error-code… of course
}
declared in LAOpeningHoursViewController.h as this
#property (strong, nonatomic) IBOutlet UILabel *myLabel;
#property (strong, nonatomic) NSString *textContent;
and finally, here is my Annotation.h-file where cname is the one that should go to 'myLabel'
#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;
#property(nonatomic, copy)UIButton *rightButton;
#property(nonatomic, retain)NSString *cid;
#property(nonatomic, retain)NSString *cname;
#property(nonatomic, retain)NSString *ctel;
#property(nonatomic, retain)NSString *cstr;
#property(nonatomic, retain)NSString *cmon;
#property(nonatomic, retain)NSString *ctue;
#property(nonatomic, retain)NSString *cwed;
#property(nonatomic, retain)NSString *passedId;
#property(nonatomic, retain)NSString *objectId;
#end
The sender parameter in [self performSegueWithIdentifier: #"openingHours" sender:ann]; should be set to self. This is intended to give the presented view controller reference to the presenting controller.
Add the property #property (nonatomic, strong) Annotation *selectedAnnotation to the presenting view controller. So that it can be set thus:
//this works fine, I get all the values
[self setSelectedAnnotation:ann];
[self performSegueWithIdentifier: #"openingHours" sender:ann];
Now you have the selected annotation as a property it can be used to initialize the LAOpeningHoursViewController:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"openingHours"]) {
LAOpeningHoursViewController *secondView = (LAOpeningHoursViewController*)segue.destinationViewController;
//PFObject *tempObject = [[myMapView selectedAnnotations] objectAtIndex:0];
Annotation *ann = (id)sender;
// Setup second view here:
secondView.myLabel.text = self.selectedAnnotation.cname;
// assign further properties here...
}
}
I hope this helps, good luck!
When I try to drag the pin, it does not move. When I touch it, it darkens. However, it never lifts up, and it never moves around.
Here is the header file for my annotation class:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <Parse/Parse.h>
#interface GeoPointAnnotation : NSObject <MKAnnotation>
- (id)initWithObject:(PFObject *)aObject;
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly, copy) NSString *title;
#property (nonatomic, readonly, copy) NSString *subtitle;
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;
#end
Here's where I create the annotation in my view controller:
- (void)updateMap
{
[self.mapView removeAnnotations:self.mapView.annotations];
PFGeoPoint *geoPoint = [self.post location];
// center the map around the geopoint
[self.mapView setRegion:MKCoordinateRegionMake(
CLLocationCoordinate2DMake(geoPoint.latitude, geoPoint.longitude),
MKCoordinateSpanMake(0.01, 0.01)
)];
GeoPointAnnotation *annotation = [[GeoPointAnnotation alloc] initWithObject:self.post.object];
[self.mapView addAnnotation:annotation];
}
// from Geolocations by Parse
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
static NSString *GeoPointAnnotationIdentifier = #"RedPin";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:GeoPointAnnotationIdentifier];
if (!annotationView) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:GeoPointAnnotationIdentifier];
annotationView.pinColor = MKPinAnnotationColorRed;
annotationView.canShowCallout = YES;
annotationView.draggable = YES;
annotationView.animatesDrop = YES;
}
return annotationView;
}
Any ideas?
Found the problem: I forgot to hook up the Map View's delegate in my Storyboard xib. h/t Nitin Gohel - thanks!
I am having problem in knowing which annotation is tapped on MKMapView.
let me explain my problem, there is a simple view controller on which map view is loaded.
my annotation class "MapViewAnnotation.h" is as follows
#interface MapViewAnnotation : NSObject <MKAnnotation>
{
NSString *title;
CLLocationCoordinate2D coordinate;
NSString *sID;
NSString *zipCode;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *sID;
#property (nonatomic, retain) NSString *zipCode;
- (id)initWithTitle:(NSString *)titleOfPin andStoreId:(NSString *)storeIdForDetails andCoordinate:(CLLocationCoordinate2D)coordinateOfPin andZipCode:(NSString *)zip;
here is my "MapViewAnnotation.m" file.
#import "MapViewAnnotation.h"
#import <MapKit/MapKit.h>
#implementation MapViewAnnotation
#synthesize title, coordinate,storeId,zipCode;
- (id)initWithTitle:(NSString *)titleOfPin andStoreId:(NSString *)storeIdForDetails andCoordinate:(CLLocationCoordinate2D)coordinateOfPin andZipCode:(NSString *)zip
{
[super init];
title = titleOfPin;
coordinate = coordinateOfPin;
sID = storeIdForDetails;
zipCode = zip;
return self;
}
-(void)dealloc
{
[title release];
[super dealloc];
}
#end
and this is my viewcontroller.m file
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
//I want to access the sID property of that annotation here. PLEASE HELP ME HOW CAN I DO THAT
if (!storeDetailControllerObject) {
storeDetailControllerObject = [[StoreDetailController alloc]init];
}
// storeDetailControllerObject.storeId = [view.annotation storeId];
[self.navigationController pushViewController:storeDetailControllerObject animated:YES];
From the MKMapViewDelegate protocol reference:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view;
If you handle the event in this method you may know which annotation was selected.
You have to set the MKMapView's delegate and to declare that you class implements the MKMapViewDelegate.
This should work:
MapViewAnnotation *mapViewAnnotation = (MapViewAnnotation*)view.annotation;
if( [mapViewAnnotation isKindOfClass:[MapViewAnnotation class]] ){
storeDetailControllerObject.storeId = mapViewAnnotation.storeId;
}
Trying to add some annotations for a MapView, but keep getting an ARC Semantic issue: 'No visible #interface for 'MKPointAnnotation' declares the selector initWithTitle:andCoordinate:
I'm fairly new to this so don't really know what it means, if anyone could explain/correct it i'd be grateful.
Here is my viewDidLoad method:
- (void)viewDidLoad
{
CLLocationCoordinate2D location;
location.latitude = (double) 51.501468;
location.longitude = (double) -0.141596;
MKPointAnnotation *newAnnotation = [[MKPointAnnotation alloc] initWithTitle:#"Buckingham Palace" andCoordinate:location];
[self._mapView addAnnotation:newAnnotation];
}
and my header file:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapViewAnnotation : NSObject <MKAnnotation> {
NSString *title;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d;
#end
The initWithTitle:andCoordinate method you created is a method of MapViewAnnotation rather than MKPointAnnotation.
You probably want:
MapViewAnnotation *newAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"Buckingham Palace" andCoordinate:location];
[self._mapView addAnnotation:newAnnotation];
It's trying to tell you it can't find any method that matches the signature of initWithTitle:andCoordinate:
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:coordinate];
[annotation setTitle:#"Buckingham Palace"];
I am parsing some data with some points of interests and trying to show them on map using the MapKit framework.
I created a custom class for my objects on the map which i call MyLocation.
MyLocation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyLocation : NSObject <MKAnnotation> {
NSString *_name;
NSString *_address;
NSInteger _eventId;
CLLocationCoordinate2D _coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic , copy) NSString *name;
#property (nonatomic , copy) NSString *address;
#property (nonatomic, assign) NSInteger eventId;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
- (id)initWithName:(NSString*)name address:(NSString*)address coordinate:(CLLocationCoordinate2D)coordinate;
#end
MyLocation.m:
#import "MyLocation.h"
#implementation MyLocation
#synthesize name = _name;
#synthesize eventId=_eventId;
#synthesize address = _address;
#synthesize coordinate = _coordinate;
#synthesize title;
#synthesize subtitle;
- (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]]) {
NSLog(#"11111111");
return #"Unknown charge";
}
else{
NSLog(#"222222");
return _name;
}
}
- (NSString *)subtitle {
NSLog(#"HAHAHAHAA");
return _address;
}
#end
Then on my viewController i do this :
//showing on map the points of interests that are stored on "eventList"
int i=0;
for (parsedItem *event in self.eventsList) {
CLLocationCoordinate2D coordinate;
coordinate.latitude = event.latitude;
coordinate.longitude = event.longitude;
if(i==0){
//numbers show map zoom. 500,500 = map stretches 500 meters to the North and the South of current location
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance (coordinate,1000,1000);
[mapView setRegion:region animated:NO];
}
MyLocation *eventAnnotation = [[MyLocation alloc] initWithName:event.typeEvent address:event.titleEvent coordinate:coordinate] ;
eventAnnotation.name = event.typeEvent;
eventAnnotation.address = event.titleEvent;
eventAnnotation.eventId = i;
i++;
[mapView addAnnotation:eventAnnotation];
}
Later i use some more code to give images to the annotations and everything appears on the map BUT if i click on the annotations i dont see the window with the title and the subtitle. I only see the annotations but without the extra information that i should get when i click on them.
I guess theres something wrong with this line of code :
MyLocation *eventAnnotation = [[MyLocation alloc] initWithName:event.typeEvent address:event.titleEvent coordinate:coordinate] ;
Any ideas?
EDIT
just to add that i also use this function:
- (MKAnnotationView *)mapView:(MKMapView *)mapView2 viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
NSLog(#"I got into the 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;
MyLocation *eventAnnotation=annotation;
if ([eventAnnotation.address isEqualToString: #"Culture_07/02/2012"]) {
NSLog(#"Mphkeeee");
annotationView.image=[UIImage imageNamed:#"culture.png"];
//annotation.title = #"Holla!";
} else if ([eventAnnotation.address isEqualToString: #"Sports_06/29/2012"]) {
annotationView.image=[UIImage imageNamed:#"sports.png"];
} else if ([eventAnnotation.address isEqualToString: #"Accident_06/29/2012"]) {
annotationView.image=[UIImage imageNamed:#"accident.png"];
} else if ([eventAnnotation.address isEqualToString: #"Problem_06/29/2012"]) {
annotationView.image=[UIImage imageNamed:#"problem.png"];
} else if ([eventAnnotation.address isEqualToString: #"Traffic_07/02/2012"]) {
annotationView.image=[UIImage imageNamed:#"traffic.png"];
} else if ([eventAnnotation.address isEqualToString: #"Music_06/29/2012"]) {
annotationView.image=[UIImage imageNamed:#"music.png"];
}
return annotationView;
}
return nil;
}
Using a custom getter method for the title and subtitle instead of setting those properties explicitly is fine with the map view.
The reason your callouts are not showing is because title (which is returning _name -- which is set to event.typeEvent) is returning a nil or empty string.
Your getter method is checking if _name is of type NSNull but it could be an NSString and still be nil or an empty string.
When title is nil or an empty string, the annotation will not display the callout (even if canShowCallout is set to YES and even if subtitle is returning a non-empty value).
So it's most likely that typeEvent is nil or an empty string.
Looking at your code, you never actually set the title or subtitle attributes. In the place where you set up your title, do something like this:
eventAnnotation.title = event.typeEvent;
eventAnnotation.subtitle = event.titleEvent;
and make sure you have the title and subtitle properties set up in the .h file.
Edit: Here's the header for one of my annotations:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapmarkAnnotation : NSObject
<MKAnnotation>
{
NSString *title;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readwrite) CLLocationCoordinate2D coordinate;
#end
Please refer to the Apple doc. you need to set title and subtitle of an annotation object yourself. not some other property like _address instead. There is also 2 sample projects in that doc, check them out as well.