Question

I'm wishing that MKMapView inherited from UIScrollView just like UITableView and UICollectionView are. This way you can override the UIScrollView delegate methods and do what you need to do.

I've found the method of attaching a pan gesture to the MapView like so:

UIPanGestureRecognizer* mapPanGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(mapPanGestureHandler:)];
[mapPanGestureRecognizer setDelegate:self];
[self.mapView addGestureRecognizer:mapPanGestureRecognizer];

This works fairly well except for the fact that the mapView has a deceleration element to it. For example if you're in mid scroll and lift your finger, the map keeps going and slows down then eventually stops.

What I'm doing is rendering some offscreen annotations in an overlay on top of my map (another UIView) using core graphics. It's working great except for the deceleration problem.

All I need to know is that the map has moved. The parameters I need I can query straight from the map itself.

Has anyone found a technique to get callbacks while decelerating? I mean I suppose I could use a timer when the gesture ends to fire repeatedly for a half a second or so.

Was it helpful?

Solution

MKMapView doesn't have analogous delegate callback to UIScrollView, so you're going to need to improvise.

Has anyone found a technique to get callbacks while decelerating? I mean I suppose I could use a timer when the gesture ends to fire repeatedly for a half a second or so.

If you're wanting to accurately keep views in sync with the map's movement, you'll be better off using CADisplayLink because you'll get a callback after each screen refresh. On the other hand, if you use a timer, the callbacks won't necessarily align with the refresh rate and you may see artifacts.

You'd set it up like this:

CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateViewsBasedOnMapRegion:)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

And then handle the callback like this:

- (void)updateViewsBasedOnMapRegion:(CADisplayLink *)link
{
    // update whatever it is you need to update
}

You could use this exclusively and discard the gesture recognizer or keep the gesture recognizer and pause the link when not needed.

OTHER TIPS

The MKMapViewDelegate protocol defines mapView:regionDidChangeAnimated: that will be called when the region displayed by the map changes. It gets call repeatedly while the map is scrolling -

Discussion 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.

You should be able to use this method to access the new map region and redraw your overlay (or if the re-draw is time-consuming you could dispatch a task on another thread to redraw the overlay)

In Swift just you should use from following code. after scroll following overrided method will be called. also you can detect amount of scroll with CLLocationCoordinate2DMake like bellow.

extension UIViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) { 
       let coordinate = CLLocationCoordinate2DMake(mapView.region.center.latitude, mapView.region.center.longitude) 
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top