determine if MKMapView was dragged/moved
The code in the accepted answer fires when the region is changed for any reason. To properly detect a map drag you have to add a UIPanGestureRecognizer. Btw, this is the drag gesture recognizer (panning = dragging).
Step 1: Add the gesture recognizer in viewDidLoad:
-(void) viewDidLoad { [super viewDidLoad]; UIPanGestureRecognizer* panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didDragMap:)]; [panRec setDelegate:self]; [self.mapView addGestureRecognizer:panRec];}
Step 2: Add the protocol UIGestureRecognizerDelegate to the view controller so it works as delegate.
@interface MapVC : UIViewController <UIGestureRecognizerDelegate, ...>
Step 3: And add the following code for the UIPanGestureRecognizer to work with the already existing gesture recognizers in MKMapView:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES;}
Step 4: In case you want to call your method once instead 50 times per drag, detect that "drag ended" state in your selector:
- (void)didDragMap:(UIGestureRecognizer*)gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateEnded){ NSLog(@"drag ended"); }}
This is the only way that worked for me that detects pan as well as zoom changes initiated by user:
- (BOOL)mapViewRegionDidChangeFromUserInteraction{ UIView *view = self.mapView.subviews.firstObject; // Look through gesture recognizers to determine whether this region change is from user interaction for(UIGestureRecognizer *recognizer in view.gestureRecognizers) { if(recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateEnded) { return YES; } } return NO;}static BOOL mapChangedFromUserInteraction = NO;- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated{ mapChangedFromUserInteraction = [self mapViewRegionDidChangeFromUserInteraction]; if (mapChangedFromUserInteraction) { // user changed map region }}- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ if (mapChangedFromUserInteraction) { // user changed map region }}
(Just the) Swift version of @mobi's excellent solution:
private var mapChangedFromUserInteraction = falseprivate func mapViewRegionDidChangeFromUserInteraction() -> Bool { let view = self.mapView.subviews[0] // Look through gesture recognizers to determine whether this region change is from user interaction if let gestureRecognizers = view.gestureRecognizers { for recognizer in gestureRecognizers { if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) { return true } } } return false}func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) { mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction() if (mapChangedFromUserInteraction) { // user changed map region }}func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { if (mapChangedFromUserInteraction) { // user changed map region }}