Esri's Geotrigger Service is replacing Geoloqi! Learn More | FAQ

Replacing MapKit with ArcGIS

Previous Page

Callout an Annotation

Dropping pins on the map and displaying a callout when the user taps one is an integral and ubiquitous map feature. With MapKit, this is handled via the MKMapViewDelegate protocol.

The Data

MapKit requires a data model that conforms to the MKAnnotation protocol. Let's start with that:

@interface LQPortlandAnnotation : NSObject <MKAnnotation>

@end

@implementation LQPortlandAnnotation

@synthesize coordinate, title, subtitle;

- (LQPortlandAnnotation *)init
{
    self = [super init];
    if (self) {
        coordinate = (CLLocationCoordinate2D){ 45.5236, -122.6750 };
        title = @"Portland!";
        subtitle = @"Yee haw!!!";
    }
    return self;
}
@end

ArcGIS SDK for iOS has the same ability, and the data model is defined by a delegate protocol called AGSInfoTemplateDelegate. We're also going to have to convert projections, so let's add some functionality to this LQPortlandAnnotation class. First, we'll make it implement the AGSInfoTemplateDelegate protocol:

@interface LQPortlandAnnotation : NSObject <MKAnnotation, AGSInfoTemplateDelegate>

@end

And add the required methods to its implementation, note that we're just returning the same property data:

- (NSString *)titleForGraphic:(AGSGraphic *)graphic screenPoint:(CGPoint)screen mapPoint:(AGSPoint *)map
{
    return self.title;
}

- (NSString *)detailForGraphic:(AGSGraphic *)graphic screenPoint:(CGPoint)screen mapPoint:(AGSPoint *)map
{
    return self.subtitle;
}

Finally, one more convenience method to get an AGSPoint in WebMercator projection:

- (AGSPoint *)webMercatorPoint
{
    AGSPoint *p = [AGSPoint pointWithX:self.coordinate.longitude
                                     y:self.coordinate.latitude
                      spatialReference:[AGSSpatialReference wgs84SpatialReference]];
    p = (AGSPoint *)[[AGSGeometryEngine defaultGeometryEngine] projectGeometry:p
                                                            toSpatialReference:[AGSSpatialReference webMercatorSpatialReference]];
    return p;
}

The Pin

Dropping a pin, which is just a symbol for a location on the map, is done by adding an MKAnnotation to the mapView:

[self.mapView addAnnotation:[LQPortlandAnnotation new]];

Then implementing the delegate method to return the view for it:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    static NSString *annotationId = @"com.geoloqi.MapKitReplacement.annotation";
    MKAnnotationView *av = [self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationId];
    if (!av) {
        MKPinAnnotationView *pav = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
                                                                   reuseIdentifier:annotationId];
        pav.pinColor = MKPinAnnotationColorRed;
        pav.animatesDrop = YES;
        pav.canShowCallout = YES;
        av = pav;
    }
    return av;
}

Using some of the handy methods we added to LQPortlandAnnotation above, we can do the same thing with ArcGIS SDK for iOS just as easily:

// call this method wherever is appropriate in the mapView's lifecycle
- (void)createCallout
{
    // pdx is an instance variable
    pdx = [LQPortlandAnnotation new];

    static NSString *graphicsLayerKey = @"graphicsLayer";

    id<AGSLayerView> lv = [self.mapView.mapLayerViews objectForKey:graphicsLayerKey];
    AGSGraphicsLayer *graphicsLayer = (AGSGraphicsLayer *)lv.agsLayer;
    if (!graphicsLayer) {
        graphicsLayer = [AGSGraphicsLayer graphicsLayer];
        [self.mapView addMapLayer:graphicsLayer withName:graphicsLayerKey];
    }

    AGSGraphic *dot = [AGSGraphic graphicWithGeometry:[pdx webMercatorPoint]
                                               symbol:[AGSSimpleMarkerSymbol simpleMarkerSymbolWithColor:[UIColor blueColor]]
                                           attributes:nil
                                 infoTemplateDelegate:pdx];

    [graphicsLayer addGraphic:dot];
    [graphicsLayer dataChanged];
}

Here are the two screenshots, this time using AGSBingMapLayer for the tile service:

Apple MapKit ArcGIS Maps

Previous Page