I have an MKMapView, that I drop a number of pins on from an array. Each map pin has an MKAnnotationView that links to a segue and another controller.
All of this is working perfectly now, but I can't see how to pass a variable through the MKAnnotationView to the segue.
I can work with either passing a string or an integer, as I could pass a username as a string, or pass the id of the array and use that in the second view controller after the segue.
My working code for looping through my array, dropping the pins, adding the annotations, and then calling the segue is as below.
This all works fine, populates the map, drops the bins, and the annotations work and link to the new segue. This is all perfect!
I just need to be able to pass a variable through from the map pin array to the second view controller segue.
- (void)loadMapPins {
for (int i=0; i<maparray.count; i++){
Location *item = _feedItems1[i];
CLLocationCoordinate2D myCoordinate = {[item.latitude doubleValue], [item.longitude doubleValue]};
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = myCoordinate;
point.title = item.firstname;
point.subtitle = [NSString stringWithFormat: #"%#", item.username];
[self.mapView addAnnotation:point];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation {
if (annotation == self.mapView.userLocation) return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* customPin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
customPin.pinColor = MKPinAnnotationColorRed;
customPin.animatesDrop = YES;
customPin.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
customPin.rightCalloutAccessoryView = rightButton;
return customPin;
}
- (IBAction)showDetails:(id)sender {
[self performSegueWithIdentifier:#"showProfileFromMap" sender:self];
}
You should use this MKMapViewDelegate method
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
CustomAnnotationClass *annotation = view.annotation;
selectedAnnotationVariable = annotation.yourProperty;
[self performSegueWithIdentifier:#"performSegue" sender:self];
}
Related
I have many garages and need to show multiple garages in map.
Below is the code I am using for Map to show multiple pins.
CLLocationCoordinate2D annotationCoord;
for (NSMutableDictionary* aDict in Gfeeds) {
annotationCoord.latitude = [aDict[#"GLatitude"] floatValue];
annotationCoord.longitude = [aDict[#"GLongitude"] floatValue];
MKPointAnnotation *annotationPoint2 = [[MKPointAnnotation alloc] init];
annotationPoint2.coordinate = annotationCoord;
annotationPoint2.title = [NSString stringWithFormat:#"%#", aDict[#"GName"]];
annotationPoint2.subtitle = aDict[#"GId"];
[geomapView addAnnotation:annotationPoint2];
}
Now what I wanted is show the details of garage after clicking that map pin… for that I am doing below.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
MKPinAnnotationView *pinAnnotation = nil;
if(annotation != geomapView.userLocation)
{
static NSString *defaultPinID = #"myPin";
pinAnnotation = (MKPinAnnotationView *)[geomapView 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;
}
return pinAnnotation;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
GarageDetailsViewController *secondView = [self.storyboard instantiateViewControllerWithIdentifier:#"GarageDetails"];
secondView.garageMainId = view.annotation.subtitle;
[self.navigationController pushViewController:secondView animated:YES];
}
Using this way I can able to go to GarageDetails, however risk I am taking is showing Id of garage in subtitle. I want to hide this subtitle so that Id would not get displayed.
Any idea how can I do this?
Hide subtitle
OR
Pass id to GarageDetails from map...
Why not subclass "MKPointAnnotation" (you can name it something like "FahimPointAnnotation), and in this subclass you can add a "garageID" property.
Then you can add the annotation to your map and when it's clicked on, you can retrieve the annotation and cast the "MKPointAnnotation" back to a "FahimPointAnnotation" and grab your garageID out of it (without having to worry about it appearing in the annotation view's subtitle field).
HI I have requirement to Implement Next and Previous functionality in the MKMapAnnotationView as shown in the Image.I have got reference from Here for making custom annotation but how can i change the next or previous annotation by clicking Next and Previous button.Please provide some Hint or idea regarding this.I am stack at this point.
For that you can use the rightCalloutAccessoryView and leftCalloutAccessoryView.
Here an example how to use the rightCalloutAccessoryView.
-(MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation: (id<MKAnnotation>)annotation {
if ([annotation isKindOfClass: [MKUserLocation class]]) {
return nil;
}
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
[pinView setCanShowCallout:YES];
if([annotation isKindOfClass:[ASPinAnnotation class]])
{
[pinView setPinColor:MKPinAnnotationColorRed];
}
else if([annotation isKindOfClass:[ASAddAutomatPin class]])
{
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:[annotation title] forState:UIControlStateNormal];
[pinView setRightCalloutAccessoryView:rightButton];
[pinView setPinColor:MKPinAnnotationColorPurple];
}
And to get notified when a calloutAccessoryView is tapped you have to use this function in your delegate:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
if([(UIButton*)control buttonType] == UIButtonTypeDetailDisclosure)
{
ASAddViewController *addController = [[ASAddViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addController];
[addController setDelegate:self];
[self.controller presentViewController:navController animated:YES completion:nil];
}
}
I have some problems with adding annotations when the user touch the map.
I'm using UIGestureRecognizer to detect the user's touch.
When a long press is detected, I'm calling this function :
- (void)handleLongPressGesture:(UIGestureRecognizer*)gestureRecognizer{
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) return;
NSLog(#"long press");
CGPoint touchPoint = [gestureRecognizer locationInView:mapView];
CLLocationCoordinate2D touchMapCoordinate =
[mapView convertPoint:touchPoint toCoordinateFromView:mapView];
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] init];
[rdvAnnotation initWithCoordinate:touchMapCoordinate];
[mapView removeAnnotations:mapView.annotations];
[mapView addAnnotation:rdvAnnotation];
[rdvAnnotation release]; }
I cans see the NSLog in the console and the rdvAnnotation is initialized with the good coordinate.
I don't understand why I can't see my annotation on the map.
Here's my - (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation method:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
if ([annotation isKindOfClass:[RdvAnnotation class]])
{
static NSString* RdvAnnotationIdentifier = #"rdvAnnotationIdentifier";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)
[mapView dequeueReusableAnnotationViewWithIdentifier:RdvAnnotationIdentifier];
if (!pinView)
{
MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:RdvAnnotationIdentifier] autorelease];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
return nil;}
My viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
mapView = [[MKMapView alloc] initWithFrame:self.view.frame];
[mapView setShowsUserLocation:TRUE];
[mapView setMapType:MKMapTypeStandard];
[mapView setDelegate:self];
CLLocationManager *locationManager=[[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[locationManager startUpdatingLocation];
self.navigationItem.title = #"Rendez-vous" ;
}
I just noticed something that seems weird :
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] init];
[rdvAnnotation initWithCoordinate:touchMapCoordinate];
You're calling init twice on the annotation object. You should just do it this way :
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] initWithCoordinate:touchMapCoordinate]];
EDIT :
If you have code in your init method that you don't want to lose, keep the init and change the value of the coordinate property :
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] init];
rdvAnnotation.coordinate = touchMapCoordinate;
In viewDidLoad you are creating a new map view object.
First, this new map view object is not being added as a subview to self.view so it exists in memory but is invisible.
Second, you probably already have a map view object placed in the view in Interface Builder so you don't need to create a new one.
So what is probably happening is that when you add the annotation, it is being added to the map view object in memory but not the one that is visible (the one that was created in IB).
Instead of creating a new map view in viewDidLoad, connect the mapView IBOutlet to the map view in Interface Builder.
I am trying to remove all the annotations of a map. The class that contains the MKMapView implements the MKMapViewDelegate. I am calling the remove all annotations method when a button (displayed in a modal view) is clicked. I am using the next code to remove all the annotations.
- (void)removeAllAnnotations {
NSMutableArray *annotationsToRemove = [NSMutableArray arrayWithCapacity:[self.mapView.annotations count]];
for (int i = 0; i < [self.mapView.annotations count]; i++) {
if ([[self.mapView.annotations objectAtIndex:i] isKindOfClass:[AddressAnnotation class]]) {
[annotationsToRemove addObject:[self.mapView.annotations objectAtIndex:i]];
}
}
[self.mapView removeAnnotations:annotationsToRemove];
}
The code works right but after calling the method, and when I try to add new annotations to the empty map, the class does not call to the viewForAnnotations method and the annotations do not drop down and do not show a disclosure button into the annotation view. Why is this happening?
Thanks for reading.
Edited:
The annotations are shown but with out calling the view for annotation method (with out dropping down and with out including a disclosure button into the annotation view). Here is the method that I use to add the annotations and the viewForAnnotation method.
- (void)loadAnnotations:(NSString *)type {
NSString *path = [[NSBundle mainBundle] pathForResource:#"PlacesInformation" ofType:#"plist"];
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
for (int i = 0; i < tmpArray.count; i++) {
// Breaks the string down even further to latitude and longitude fields.
NSString *coordinateString = [[tmpArray objectAtIndex:i] objectForKey:#"coordinates"];
NSString *option = [[tmpArray objectAtIndex:i] objectForKey:#"type"];
if ([option isEqualToString:type]) {
CLLocationCoordinate2D currentCoordinate = [self stringToCoordinate:coordinateString];
AddressAnnotation *annotation = [[[AddressAnnotation alloc] initWithCoordinate:currentCoordinate] autorelease];
[self.mapView addAnnotation:annotation];
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
else { // Handles the other annotations.
// Try to dequeue an existing pin view first.
static NSString *AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView) {
// If an existing pin view was not available, creates one.
MKPinAnnotationView *customPinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
// Adds a detail disclosure button.
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
} else
pinView.annotation = annotation;
}
return nil;
}
In viewForAnnotation, in the case where you are reusing a view, you are currently returning nil.
This else part:
} else
pinView.annotation = annotation;
Should probably be:
} else {
pinView.annotation = annotation;
return pinView;
}
I am working with MKPinAnnotationView annotations pins over a MKMapView. Into the view that I am developing, there is a map centered on a pin. When I call the view the pin drops down and if I make a click over it, it shows the annotation information (canShowCallout = YES). How I can get this callout just when I open the view? Without making a click over the annotation pin.
Thanks for reading.
Edited:
I am using this code.
- (void)viewDidLoad {
[super viewDidLoad];
AddressAnnotation *annotation = [[[AddressAnnotation alloc] initWithCoordinate:self.currentAnnotationCoordinate] autorelease];
[self.mapView addAnnotation:annotation];
[self zoomCoordinate:self.currentAnnotationCoordinate];
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
else { // Handles the other annotations.
// Try to dequeue an existing pin view first.
static NSString *AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView) {
// If an existing pin view was not available, creates one.
MKPinAnnotationView *customPinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
// Adds a detail disclosure button.
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
} else
pinView.annotation = annotation;
}
return nil;
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)theMapView {
AddressAnnotation *annotation = [[[AddressAnnotation alloc] initWithCoordinate:self.currentAnnotationCoordinate] autorelease];
for (id<MKAnnotation> currentAnnotation in mapView.annotations) {
if ([currentAnnotation isEqual:annotation]) {
[mapView selectAnnotation:currentAnnotation animated:FALSE];
}
}
}
Edited:
Calling didAddAnnotationViews: instead of mapViewDidFinishLoadingMap: (as aBitObvious has commented), it works fine.
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
id<MKAnnotation> myAnnotation = [self.mapView.annotations objectAtIndex:0];
[self.mapView selectAnnotation:myAnnotation animated:YES];
}
Possible duplicate: How to trigger MKAnnotationView's callout view without touching the pin?
You want to call [mapView selectAnnotation:].