Question

I have a map view and I have plotted the coordinates from a JSON response. It shows the pin/annotation name when they first click it. Now I need to somehow allow the user to click on the same pin/annotation again and perform a seque and some action/code. How can I do this?

Was it helpful?

Solution

Here's how I've implemented this in many apps... First I create my own custom annotation that includes some values I might want to store that are unique to the each object associated with the pin. In this case it is a URL. Here is a generic "CustomAnnotation" object's .h and .m:

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface CustomAnnotation : NSObject <MKAnnotation>

@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, retain) NSString *URL;


@end

// the .m file doesn't need anything else in it

#import "CustomAnnotation.h"
#import <MapKit/MapKit.h>

@implementation CustomAnnotation

@end

Then inside the view controller I'm adding the mapview to you need to add the annotation, customize the view that it shows when you tap it, and handle the action:

- (void)createMapAndAddAnnotation {
    // create the mapview and add it to the view
    MKMapView *mapView = [[MKMapView alloc] initWithFrame:self.view.frame];
    mapView.delegate = self;
    [self.view addSubview:mapView];

    // create the annotation however you want, this is just for demo purposes
    CustomAnnotation *annotation = [[CustomAnnotation alloc] init];
    annotation.coordinate = CLLocationCoordinate2DMake(50, 50);
    annotation.title = @"Test Title";
    annotation.subtitle = @"Subtitle";
    annotation.URL = @"www.google.com";
    [mapView addAnnotation:annotation];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    // if the annotation is a custom annotation
    if ([annotation isKindOfClass:[CustomAnnotation class]]) {
        // create the reuse identifier so we can recycle annotatinons
        NSString *pinAnnotationViewReuseID = @"PinAnnotationView";

        // attempt to reuse one
        MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pinAnnotationViewReuseID];

        // if we were unable to dequeue one for reuse
        if (!pinView) {
            // create and format it accordingly
            pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinAnnotationViewReuseID];
            pinView.pinColor = MKPinAnnotationColorRed;
            pinView.animatesDrop = YES;
            pinView.canShowCallout = YES;
            pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        }

        // otherwise all we want to do is set the annotation on the pin
        else {
            pinView.annotation = annotation;
        }

        // and return it
        return pinView;
    }

    // otherwise we don't want to return one at all
    else {
        return nil;
    }
}

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
    // get the annotation object from the view that was tapped
    CustomAnnotation *tappedAnnotation = view.annotation;

    // get the info from the annotation itself
    NSString *urlFromAnnotation = tappedAnnotation.URL;

    // do something with the info - in this case I'm just popping up an alert for demo purposes
    [[[UIAlertView alloc] initWithTitle:@"The URL was:" message:urlFromAnnotation delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
}

Here's a video showing the result:

https://www.dropbox.com/s/rbcpvo3cuspgly9/annotation.mov

EDIT: based on your edit/questions

You said you added the custom annotation files, but in the code you showed you didn't use a custom annotation object, you just used a regular MKPointAnnotation... Below I edited your code a bit to make it more readable and clear - you probably want to try making your variable names and dictionary keys make a bit more sense. This is all assuming you have an array called employees that is filled with dictionaries and each dictionary has a key called "GymName" and the value for that key is a % separated string with lat and lon values?

for (int index = 0; index < employees.count; index++) {
        NSLog(@"Inside Loop!");

        // get the employee dictionary based on the array index
        NSDictionary *employee = employees[index];

        // get the coordinate string - I'm guessing based on your code it's something like "45.254%72.156"
        NSString *coordinateString = employee[@"GymName"];

        // break up the lat and lon into components in an array
        NSArray *coordinateComponents = [coordinateString componentsSeparatedByString:@"%"];

        // get the latitude and longitude values from the components array and conver them to doubles
        double latitude = [coordinateComponents[0] doubleValue];
        double longitude = [coordinateComponents[1] doubleValue];

        // create the coordinate object from the lat and long
        CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);

        // create the custom annotation and add it to the map
        CustomAnnotation *annotation = [[CustomAnnotation alloc] init];
        annotation.coordinate = coordinate;
        [_mapView addAnnotation:annotation];
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top