I did not have a lot of luck with any of these answers. Doing my own pinch just conflicted too much. I was running into cases where the normal zoom would zoom farther in than I could do with my own pinch.
Originally, I tried as the original poster to do something like:
- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
MKCoordinateRegion region = mapView.region;
//...
// adjust the region.center
//...
mapView.region = region;
}
What I found was that that had no effect. I also discovered through NSLog
s that this method will fire even when I set the region
or centerCoordinate
programmatically. Which led to the question: "Wouldn't the above, if it DID work go infinite?"
So I'm conjecturing and hypothesizing now that while user zoom/scroll/rotate is happening, MapView somehow suppresses or ignores changes to the region. Something about the arbitration renders the programmatic adjustment impotent.
If that's the problem, then maybe the key is to get the region adjustment outside of the regionDidChanged:
notification. AND since any adjustment will trigger another notification, it is important that it be able to determine when not to adjust anymore. This led me to the following implementation (where subject
is supplying the center coordinate that I want to stay in the middle):
- (void) recenterMap {
double latDiff = self.subject.coordinate.latitude self.mapView.centerCoordinate.latitude;
double lonDiff = self.subject.coordinate.longitude - self.mapView.centerCoordinate.longitude;
BOOL latIsDiff = ABS(latDiff) > 0.00001;
BOOL lonIsDiff = ABS(lonDiff) > 0.00001;
if (self.subject.isLocated && (lonIsDiff || latIsDiff)) {
[self.mapView setCenterCoordinate: self.subject.coordinate animated: YES];
}
}
- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
if (self.isShowingMap) {
if (self.isInEdit) {
self.setLocationButton.hidden = NO;
self.mapEditPrompt.hidden = YES;
}
else {
if (self.subject.isLocated) { // dispatch outside so it will happen after the map view user events are done
dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^{
[self recenterMap];
});
}
}
}
}
The delay where it slides it back can vary, but it really does work pretty well. And lets the map interaction remain Apple-esque while it's happening.