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

Replacing MapKit with ArcGIS

Previous Page | Next Page

Tracking the user

One of the most useful features of MKMapView is setUserTrackingMode:(MKUserTrackingMode). It is a very easy way to trigger zooming to and following the user's vicinity:

[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];

This results in the map displaying a blue dot where the user is at and the map pans to follow the dot as the user moves through the world:

ArcGIS SDK for iOS includes a similarly easy functionality through the AGSGPS class, available via the gps property of AGSMapView objects. It also gives the developer flexibility by being able to set both "auto-panning" and "wander extent" properties. Auto-panning is to set if the map should pan to follow the user dot or not; wander extent is a float between 0 and 1 to set a threshold to being auto-panning at. It is calculated as a percent of the visible area.

self.mapView.autoPanMode = AGSGPSAutoPanModeDefault;
self.mapView.wanderExtentFactor = 0.25;
[self.mapView.gps start];

NOTE: you may notice that the extent of the ArcGIS Map is much smaller than the MapKit map. Currently, this is unsettable when using the convenience method AGSGPS#start. As noted on the ArcGIS resources site, AGSGPS "provides a simple façade over the CoreLocation framework and greatly simplifies working with location services." However, you can implement auto-panning on your own...

Handrolling Autopanning

If the zoom level that AGSGPS#start uses is a bit too close for you, it is simple enough to implement your own auto-panning feature:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = [locations objectAtIndex:(locations.count - 1)];
    CLLocationCoordinate2D latlng = location.coordinate;

    float extentDelta = 0.01;
    AGSEnvelope *envelope = [AGSEnvelope envelopeWithXmin:(latlng.longitude - extentDelta)
                                                     ymin:(latlng.latitude -  extentDelta)
                                                     xmax:(latlng.longitude + extentDelta)
                                                     ymax:(latlng.latitude +  extentDelta)
                                         spatialReference:[AGSSpatialReference wgs84SpatialReference]];
    [self.mapView zoomToEnvelope:envelope animated:YES];
}

Handling User Pan and Zoom

Apple provides a lot of helpful delegate methods in the MKMapKitDelegate protocol. Two of these are:

  • – mapView:regionWillChangeAnimated:
  • – mapView:regionDidChangeAnimated:

Implementing these delegate methods allows you to respond to common events such as the user panning around or zooming in or out. This is very simple in MapKit:

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
    NSLog(@"started panning or zooming");
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    NSLog(@"stopped panning or zooming");
}

The same thing can be done using Key-Value Observation with ArcGIS SDK for iOS.

To acheive the same result as handling regionWillChangeAnimated, the value of the AGSMapView object that you want to observe is keyed at visibleArea. For regionDidChangeAnimated, you want to listen for two NSNotifications:

  • MapDidEndPanning
  • MapDidEndZooming

Here is some example code for this scenario:

// key to watch on the AGSMapView object
static NSString *const LQRegionWillChangeObserverKeyPath = @"self.mapView.visibleArea";

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self addObserver:self forKeyPath:LQRegionWillChangeObserverKeyPath options:NSKeyValueObservingOptionNew context:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mimicRegionDidChange) name:@"MapDidEndPanning" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mimicRegionDidChange) name:@"MapDidEndZooming" object:nil];

}

- (void)dealloc {
    [self removeObserver:self forKeyPath:LQRegionWillChangeObserverKeyPath];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:LQRegionWillChangeObserverKeyPath]) {
        [self mimicRegionWillChange];
    }
}

Previous Page | Next Page