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];
}
}