Reneli
Reneli

Reputation: 1856

how to show map scale during zoom of MKMapView like Apple's Maps.app

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

Answers (3)

Andraz
Andraz

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

Johnny Rockex
Johnny Rockex

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

bryanjclark
bryanjclark

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

Related Questions