I have a MKCircle on MKMapView. It is user-draggable, but if the user drags the area outside the circle, the map should be moving instead.
- (IBAction)createPanGestureRecognizer:(id)sender
{
_mapView.scrollEnabled=NO;
_panRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:@selector(respondToPanGesture:)];
[_mapView addGestureRecognizer:_panRecognizer];
}
-(void)respondToPanGesture:(UIPanGestureRecognizer*)sender {
static CGPoint originalPoint;
if (sender.state == UIGestureRecognizerStateBegan) {
CGPoint point = [sender locationInView:_mapView];
CLLocationCoordinate2D tapCoordinate = [_mapView convertPoint:point toCoordinateFromView:_mapView];
CLLocation *tapLocation = [[CLLocation alloc] initWithLatitude:tapCoordinate.latitude longitude:tapCoordinate.longitude];
CLLocationCoordinate2D originalCoordinate = [_circle coordinate];
CLLocation *originalLocation = [[CLLocation alloc] initWithLatitude:originalCoordinate.latitude longitude:originalCoordinate.longitude];
if ([tapLocation distanceFromLocation:originalLocation] > [_circle radius]) {
_mapView.scrollEnabled=YES;
_isAllowedToMove=NO;
}
else if ([tapLocation distanceFromLocation:originalLocation] < [_circle radius]) {
originalPoint = [_mapView convertCoordinate:originalCoordinate toPointToView:sender.view];
_isAllowedToMove=YES;
}
}
if (sender.state == UIGestureRecognizerStateChanged) {
if (_isAllowedToMove)
{
CGPoint translation = [sender translationInView:sender.view];
CGPoint newPoint = CGPointMake(originalPoint.x + translation.x, originalPoint.y + translation.y);
CLLocationCoordinate2D newCoordinate = [_mapView convertPoint:newPoint toCoordinateFromView:sender.view];
MKCircle *circle2 = [MKCircle circleWithCenterCoordinate:newCoordinate radius:[_circle radius]];
[_mapView addOverlay:circle2];
[_mapView removeOverlay:_circle];
_circle = circle2;
}
}
if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateCancelled) {
_mapView.scrollEnabled=NO;
_isAllowedToMove=NO;
}
}
Dragging the circle works fine, but when trying to drag the map, it stays still. My assumption is that
_mapView.scrollEnabled=YES;
makes the map draggable, but it needs another drag gesture to be started. How to accomplish this without losing the ability to move the circle?
Updated answer using swift 4
Includes some changes:
panGesture.maximumNumberOfTouches = 1
to avoid detecting pinch to zoom as pan gesture Screen points used for active area where pan gesture can be started.To make it so that the map can be dragged if the user starts dragging outside the circle (and to not drag the map if the user starts dragging inside the circle), don't disable
scrollEnabled
from the beginning -- leave it on (until dragging starts and we can decide whether to disable or not).In order to leave
scrollEnabled
on initially (ie. let the map do its own panning) and to add our own gesture recognizer, we'll need to implementshouldRecognizeSimultaneouslyWithGestureRecognizer
and returnYES
.The updated
createPanGestureRecognizer:
would look like this:Then in our gesture handler, when the gesture begins, enable or disable
scrollEnabled
based on where the pan starts (outside or inside the circle):Finally, always re-enable
scrollEnabled
when a gesture ends (just in case).When the next gesture starts, it will be re-disabled if necessary:
Note that if the user is allowed to call
createPanGestureRecognizer:
multiple times, you should probably move the creation and addition of the recognizer somewhere else (viewDidLoad
maybe) otherwise multiple instances will get added to the map.Alternatively, change the button to a toggle so that if "move" mode is ON, it removes the gesture recognizer from the map instead of creating and adding it.