Reputation: 1856
i am using MKMapView in my custom app and would like to show a map scale (tape measure) during zooming like Apple's Maps.app. Is this possible?
If not, and i would implement my own map scale, how can i get continious update information while the zoom ov the MKMapView is changed?
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
seems to be called only once at the begining of a zoom while
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
is called only once at the end of the zoom.
Maps.app map scale is shown and updated in realtime continiously during a zoom.
thanks in advance.
Upvotes: 2
Views: 2250
Reputation: 152
As you figured out, the methods
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool)
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool)
are triggered when you start and end your zoom gestures. But using the delegate method
func mapViewDidChangeVisibleRegion(_ mapView: MKMapView)
you get continuous updates when the zoom is changing.
Upvotes: 0
Reputation: 4196
I had a similar problem, getting the camera.altitude based on user zooming, to display in a label.
Since there is no method such as "regionISChangingAnimated", but only WillChange and DidChange, I start a timer at WillChange and invalidate it at DidChange. The timer calls a method (updateElevationLabel) that calculates the altitude of the camera above the map.
However, since camera.altitude is not calculated until regionDidChange is called, use the zoomscale and the starting height of the map (zoomscale = 1.0 does not always equal altitude = 0m, it depends on where you are in the world) to calculate the current height. Starting height is a float in the method below, set it once on load and for each region change.
Finally you can change the format of the altitude, e.g. from km from m beyond a certain altitude (10'000 metres below).
For the oldschool: 1m = 3.2808399 ft.
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
if (showsElevation) {
//update starting height for the region
MKMapCamera *camera = map.camera;
CLLocationDistance altitude = camera.altitude;
MKZoomScale currentZoomScale = map.bounds.size.width / map.visibleMapRect.size.width;
float factor = 1.0/currentZoomScale;
startingHeight = altitude/factor;
elevationTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(updateElevationLabel)
userInfo:Nil
repeats:YES];
[elevationTimer fire];
}
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
[elevationTimer invalidate];
}
-(void)updateElevationLabel {
//1. create the label
if (!elevationLabel) {
elevationLabel = [UILabel new];
[elevationLabel setFrame:CGRectMake(0, 18, 200, 44)];
[elevationLabel setBackgroundColor:[UIColor redColor]];
[self addSubview:elevationLabel];
}
//2. grab the initial starting height (further updated on region changes)
if (startingHeight == 0) {
MKMapCamera *camera = map.camera;
CLLocationDistance altitude = camera.altitude;
MKZoomScale currentZoomScale = map.bounds.size.width / map.visibleMapRect.size.width;
float factor = 1.0/currentZoomScale;
startingHeight = altitude/factor;
}
//3. get current zoom scale and altitude, format changes
MKZoomScale currentZoomScale = map.bounds.size.width / map.visibleMapRect.size.width;
float altitude = startingHeight * (1/currentZoomScale);
if (altitude>10000) {
altitude = altitude/1000;
[elevationLabel setText:[NSString stringWithFormat:@"%.1fkm", altitude]];
} else {
[elevationLabel setText:[NSString stringWithFormat:@"%.0fm", altitude]];
}
}
Upvotes: 1
Reputation: 6404
From Apple's docs on MKMapView's regionWillChangeAnimated: method (emphasis mine):
This method is called whenever the currently displayed map region changes. During scrolling, this method may be called many times to report updates to the map position. Therefore, your implementation of this method should be as lightweight as possible to avoid affecting scrolling performance.
Sounds like you should be able to use this method continuously as the map view scrolls, which solves part of your problem - so when that method is called, take a look at (I'm guessing here) the mapview's region
attribute and derive your map scale from that.
Upvotes: 0