在MKMapview上移动MKCircle并拖动MKMapview

我在MKMapView上有一个MKCircle。 它是用户可拖动的,但如果用户拖动圆圈外的区域,则应该移动地图。

- (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; } } 

拖动圆圈工作正常,但在尝试拖动地图时,它会保持静止。 我的假设是

 _mapView.scrollEnabled=YES; 

使地图可拖动,但需要启动另一个拖动手势。 如何在不失去移动圆圈的能力的情况下实现这一目标?

如果用户开始在圆圈外拖动(并且如果用户开始圆圈拖动则不拖动地图),可以拖动地图,不要scrollEnabled开始禁用scrollEnabled – 保持开启(直到拖动开始 ,我们可以决定是否禁用)。

为了最初scrollEnabled (即让地图自己进行平移) 添加我们自己的手势识别器,我们需要实现shouldRecognizeSimultaneouslyWithGestureRecognizer并返回YES

更新后的createPanGestureRecognizer:如下所示:

 - (IBAction)createPanGestureRecognizer:(id)sender { //_mapView.scrollEnabled=NO; // <-- do NOT disable scrolling here _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(respondToPanGesture:)]; _panRecognizer.delegate = self; // <-- to implement shouldRecognize [_mapView addGestureRecognizer:_panRecognizer]; } -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } 

然后在我们的手势处理程序中,当手势开始时 ,根据平移开始的位置(圆圈外部或内部)启用或禁用scrollEnabled

 if ([tapLocation distanceFromLocation:originalLocation] > [_circle radius]) { _mapView.scrollEnabled=YES; _isAllowedToMove=NO; } else //if ([tapLocation distanceFromLocation:originalLocation] < [_circle radius]) { //NOTE: It's not really necessary to check if distance is less than radius // in the ELSE part since in the IF we checked if it's greater-than. // If we get to the ELSE, we know distance is <= radius. // Unless for some reason you want to handle the case where // distance exactly equals radius differently but this is unlikely. { originalPoint = [_mapView convertCoordinate:originalCoordinate toPointToView:sender.view]; _mapView.scrollEnabled=NO; // <-- disable scrolling HERE _isAllowedToMove=YES; } 

最后,总是在手势结束时重新启用scrollEnabled (以防万一)。
当下一个手势开始时,如有必要,将重新禁用它:

 if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateCancelled) { _mapView.scrollEnabled=YES; // <-- enable instead of disable _isAllowedToMove=NO; } 

请注意,如果允许用户多次调用createPanGestureRecognizer: ,您可能应该在其他位置移动识别器的创建和添加(可能是viewDidLoad ),否则会将多个实例添加到地图中。

或者,将按钮更改为切换,以便在“移动”模式为ON时,它会从地图中删除手势识别器,而不是创建和添加手势识别器。

使用swift 4更新了答案

包括一些更改: panGesture.maximumNumberOfTouches = 1以避免检测到缩放以缩放为平移手势用于活动区域的屏幕点可以启动平移手势。

 private func addPanGestureRecognizer(to map: MKMapView) { let panGesture = UIPanGestureRecognizer(target: self, action: #selector(respondToPanGesture(_:))) panGesture.maximumNumberOfTouches = 1 panGesture.delegate = self map.addGestureRecognizer(panGesture) } @objc private func respondToPanGesture(_ sender: UIPanGestureRecognizer) { guard let map = self.map else { return } let circlePoint = map.convert(startPoint, toPointTo: map) // circle center in View coordinate system switch sender.state { case .began: let point = sender.location(in: map) // Set touch radius in points (20), not meters to support different map zoom levels if point.radiusContainsPoint(radius: 20, point: circlePoint) { // set class property to store initial circle position before start dragging initialDragPoint = circlePoint map.isScrollEnabled = false isDragEnabled = true } else { map.isScrollEnabled = true isDragEnabled = false } case .changed: if isDragEnabled { let translation = sender.translation(in: map) let newPoint = CGPoint(x: initialDragPoint.x + translation.x, y: initialDragPoint.y + translation.y) let updatedCoordinate = map.convert(newPoint, toCoordinateFrom: map) let newOverlay = makeCircleOverlay(at: updatedCoordinate) map.remove(circleOverlay) map.add(newOverlay) circleOverlay = newOverlay } case .ended, .failed, .cancelled: map.isScrollEnabled = true isDragEnabled = false case .possible: break } } // MARK: - UIGestureRecognizerDelegate func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true }