Search code examples
iosmkmapviewmkannotationviewmkmapviewdelegate

Callout I click on Map and appears ViewController2


I cannot see the second entry in the Map and take me to DetailViewController2.

Is there any way to fix this?

#import "MapViewController.h"
#import "DetailViewController.h"
#import "DetailViewController2.h"

#import "SFAnnotation.h"            // annotation for the city of San Francisco
#import "BridgeAnnotation.h"        // annotation for the Golden Gate bridge
#import "CustomAnnotation.h"        // annotation for the Tea Garden

@interface MapViewController () <MKMapViewDelegate>

@property (nonatomic, weak) IBOutlet MKMapView *mapView;
@property (nonatomic, strong) NSMutableArray *mapAnnotations;
@property (nonatomic, strong) UIPopoverController *bridgePopoverController;
@property (nonatomic, strong) UIPopoverController *sfPopoverController;
@property (nonatomic, strong) UIPopoverController *customPopoverController;

@end


#pragma mark -

@implementation MapViewController

- (void)gotoDefaultLocation
{
    // EMPEZAR CON UNA LOCALIZACIÓN DETERMINADA
    MKCoordinateRegion newRegion;
    newRegion.center.latitude = 41.651981;
    newRegion.center.longitude = -4.728561;
    newRegion.span.latitudeDelta = 0.1;
    newRegion.span.longitudeDelta = 0.1;
     self.mapView.showsUserLocation = YES;
    [self.mapView setRegion:newRegion animated:YES];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // restore the nav bar to translucent
    self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // create a custom navigation bar button and set it to always says "Back"
    UIBarButtonItem *temporaryBarButtonItem = [[UIBarButtonItem alloc] init];
    temporaryBarButtonItem.title = @"Back";
    self.navigationItem.backBarButtonItem = temporaryBarButtonItem;

    // create out annotations array (in this example only 3)
    self.mapAnnotations = [[NSMutableArray alloc] initWithCapacity:2];

    // annotation for the City of San Francisco
    SFAnnotation *sfAnnotation = [[SFAnnotation alloc] init];
    [self.mapAnnotations addObject:sfAnnotation];

    // annotation for Golden Gate Bridge
    BridgeAnnotation *bridgeAnnotation = [[BridgeAnnotation alloc] init];
    [self.mapAnnotations addObject:bridgeAnnotation];


    // annotation for Tea Garden
    CustomAnnotation *customAnnotation = [[CustomAnnotation alloc] init];
    [self.mapAnnotations addObject:customAnnotation];




    [self allAction:self];  // initially show all annotations
}


#pragma mark - Button Actions

- (void)gotoByAnnotationClass:(Class)annotationClass
{
    // user tapped "City" button in the bottom toolbar
    for (id annotation in self.mapAnnotations)
    {
        if ([annotation isKindOfClass:annotationClass])
        {
            // remove any annotations that exist
            [self.mapView removeAnnotations:self.mapView.annotations];
            // add just the city annotation
            [self.mapView addAnnotation:annotation];

            [self gotoDefaultLocation];
        }
    }
}

- (IBAction)cityAction:(id)sender
{
    [self gotoByAnnotationClass:[SFAnnotation class]];
}

- (IBAction)bridgeAction:(id)sender
{
    // user tapped "Bridge" button in the bottom toolbar
    [self gotoByAnnotationClass:[BridgeAnnotation class]];
}

- (IBAction)teaGardenAction:(id)sender
{
    // user tapped "Tea Garden" button in the bottom toolbar
    [self gotoByAnnotationClass:[CustomAnnotation class]];
}

- (IBAction)allAction:(id)sender
{
    // user tapped "All" button in the bottom toolbar

    // remove any annotations that exist
    [self.mapView removeAnnotations:self.mapView.annotations];

    // add all 3 annotations
    [self.mapView addAnnotations:self.mapAnnotations];

    [self gotoDefaultLocation];
}


#pragma mark - MKMapViewDelegate

// user tapped the disclosure button in the bridge callout
//
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    // here we illustrate how to detect which annotation type was clicked on for its callout
    id <MKAnnotation> annotation1 = [view annotation];
    if ([annotation1 isKindOfClass:[BridgeAnnotation class]])
    {
        NSLog(@"clicked Golden Gate Bridge annotation");

        DetailViewController *detailViewController = [[self storyboard] instantiateViewControllerWithIdentifier:@"DetailViewController"];
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            // for iPad, we use a popover
            if (self.bridgePopoverController == nil)
            {
                _bridgePopoverController = [[UIPopoverController alloc] initWithContentViewController:detailViewController];
            }
            [self.bridgePopoverController presentPopoverFromRect:control.bounds
                                                          inView:control
                                        permittedArrowDirections:UIPopoverArrowDirectionLeft
                                                        animated:YES];
        }
        else
        {
            // for iPhone we navigate to a detail view controller using UINavigationController
            [self.navigationController pushViewController:detailViewController animated:YES];

        }

    }
}





// user tapped the disclosure button in city of San Francisco callout
//
- (void)mapView:(MKMapView *)mapView annotationView2:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    // here we illustrate how to detect which annotation type was clicked on for its callout
    id <MKAnnotation> annotation2 = [view annotation];
    if ([annotation2 isKindOfClass:[SFAnnotation class]])
    {
        NSLog(@"clicked City of San Francisco annotation");

        DetailViewController *detailViewController2 = [[self storyboard] instantiateViewControllerWithIdentifier:@"DetailViewController2"];
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            // for iPad, we use a popover
            if (self.sfPopoverController == nil)
            {
                _sfPopoverController = [[UIPopoverController alloc] initWithContentViewController:detailViewController2];
            }
            [self.sfPopoverController presentPopoverFromRect:control.bounds
                                                          inView:control
                                        permittedArrowDirections:UIPopoverArrowDirectionLeft
                                                        animated:YES];
        }
        else
        {
            // for iPhone we navigate to a detail view controller using UINavigationController
            [self.navigationController pushViewController:detailViewController2 animated:YES];

        }

    }
}








- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MKAnnotationView *returnedAnnotationView = nil;

    // in case it's the user location, we already have an annotation, so just return nil
    if (![annotation isKindOfClass:[MKUserLocation class]])
    {
        // handle our three custom annotations
        //
        if ([annotation isKindOfClass:[BridgeAnnotation class]]) // for Golden Gate Bridge
        {
            returnedAnnotationView = [BridgeAnnotation createViewAnnotationForMapView:self.mapView annotation:annotation];

            // add a detail disclosure button to the callout which will open a new view controller page or a popover
            //
            // note: when the detail disclosure button is tapped, we respond to it via:
            //       calloutAccessoryControlTapped delegate method
            //
            // by using "calloutAccessoryControlTapped", it's a convenient way to find out which annotation was tapped
            //
            UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            [rightButton addTarget:nil action:nil forControlEvents:UIControlEventTouchUpInside];
            ((MKPinAnnotationView *)returnedAnnotationView).rightCalloutAccessoryView = rightButton;
        }






        else if ([annotation isKindOfClass:[SFAnnotation class]]) // for City of San Francisco
        {
            returnedAnnotationView = [SFAnnotation createViewAnnotationForMapView:self.mapView annotation:annotation];

            // add a detail disclosure button to the callout which will open a new view controller page or a popover
            //
            // note: when the detail disclosure button is tapped, we respond to it via:
            //       calloutAccessoryControlTapped delegate method
            //
            // by using "calloutAccessoryControlTapped", it's a convenient way to find out which annotation was tapped
            //
            UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            [rightButton addTarget:nil action:nil forControlEvents:UIControlEventTouchUpInside];
            ((MKPinAnnotationView *)returnedAnnotationView).rightCalloutAccessoryView = rightButton;
        }






        else if ([annotation isKindOfClass:[CustomAnnotation class]]) // for City of Tea Garden
        {
            returnedAnnotationView = [CustomAnnotation createViewAnnotationForMapView:self.mapView annotation:annotation];

            // add a detail disclosure button to the callout which will open a new view controller page or a popover
            //
            // note: when the detail disclosure button is tapped, we respond to it via:
            //       calloutAccessoryControlTapped delegate method
            //
            // by using "calloutAccessoryControlTapped", it's a convenient way to find out which annotation was tapped
            //
            UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            [rightButton addTarget:nil action:nil forControlEvents:UIControlEventTouchUpInside];
            ((MKPinAnnotationView *)returnedAnnotationView).rightCalloutAccessoryView = rightButton;
        }
    }

    return returnedAnnotationView;
}

@end

Solution

  • This method:

    - (void)mapView:(MKMapView *)mapView annotationView2:(MKAnnotationView *)view 
        calloutAccessoryControlTapped:(UIControl *)control
    

    will not be called by the map view because it's not named exactly mapView:annotationView:calloutAccessoryControlTapped:.

    Naming the method annotationView2 does not automatically associate it with your "second" annotation. Delegate methods must be named exactly as defined by the protocol (MKMapViewDelegate in this case).


    You must handle all callout button taps in this one method:

    - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view 
        calloutAccessoryControlTapped:(UIControl *)control
    

    In there, you can check the annotation's class and handle accordingly (like you are already doing with BridgeAnnotation). For example:

    if ([annotation1 isKindOfClass:[BridgeAnnotation class]])
    {
        //code for Bridge annotation...
    }
    else
    if ([annotation1 isKindOfClass:[SFAnnotation class]])
    {
        //code for SF annotation...
    }
    else ...