确定是否拖动/移动MKMapView

有没有一种方法来确定是否一个MKMapView被拖动?

每当用户使用CLLocationCoordinate2D centre = [locationMap centerCoordinate];拖动地图时,我想获取中心位置CLLocationCoordinate2D centre = [locationMap centerCoordinate]; 但是我需要一个委托方法或者一旦用户在地图上浏览时触发的东西。

提前致谢

看看MKMapViewDelegate参考。

具体来说,这些方法可能是有用的:

 - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated 

确保你的地图视图的委托属性被设置,以便这些方法被调用。

接受的答案中的代码在由于任何原因而改变区域时触发。 要正确地检测地图拖动,您必须添加一个UIPanGestureRecognizer。 顺便说一句,这是拖动手势识别器(平移=拖动)。

第1步:在viewDidLoad中添加手势识别器:

 -(void) viewDidLoad { [super viewDidLoad]; UIPanGestureRecognizer* panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didDragMap:)]; [panRec setDelegate:self]; [self.mapView addGestureRecognizer:panRec]; } 

第2步:将协议UIGestureRecognizerDelegate添加到视图控制器,以便它作为委托。

 @interface MapVC : UIViewController <UIGestureRecognizerDelegate, ...> 

步骤3:为UIPanGestureRecognizer添加以下代码,以便与MKMapView中已有的手势识别器配合使用:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } 

第四步:如果你想调用你的方法一次,而不是每次拖动50次,检测到在select器中的“拖拽结束”状态:

 - (void)didDragMap:(UIGestureRecognizer*)gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateEnded){ NSLog(@"drag ended"); } } 

这是我工作的唯一方式,检测平移以及由用户发起的缩放更改:

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

(只是) @ mobi的优秀解决scheme的迅捷版本:

 private var mapChangedFromUserInteraction = false private 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 } } 

您还可以在Interface Builder中将地图识别器添加到地图中。 把它连接到你的viewController的动作sockets,我叫我的“mapDrag”…

然后,你会在你的viewController的.m中做这样的事情:

 - (IBAction)mapDrag:(UIPanGestureRecognizer *)sender { if(sender.state == UIGestureRecognizerStateBegan){ NSLog(@"drag started"); } } 

确保你也有这个:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } 

当然你必须在你的.h文件中使你的viewController成为一个UIGestureRecognizerDelegate才能工作。

否则,地图的响应者是唯一听到手势事件的人。

另一个可能的解决scheme是在视图控制器中实现touchesMoved :(或touchesEnded:等),它包含你的地图视图,如下所示:

 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; for (UITouch * touch in touches) { CGPoint loc = [touch locationInView:self.mapView]; if ([self.mapView pointInside:loc withEvent:event]) { #do whatever you need to do break; } } } 

在某些情况下,这可能比使用手势识别器更简单。

根据我的经验,类似于“键入时search”,我发现一个计时器是最可靠的解决scheme。 它不需要添加额外的手势识别器来平移,捏,旋转,敲击,双击等等。

解决scheme很简单:

  1. 当地图区域更改时,设置/重置定时器
  2. 计时器激发时,加载新区域的标记

     import MapKit class MyViewController: MKMapViewDelegate { @IBOutlet var mapView: MKMapView! var mapRegionTimer: NSTimer? // MARK: MapView delegate func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { setMapRegionTimer() } func setMapRegionTimer() { mapRegionTimer?.invalidate() // Configure delay as bet fits your application mapRegionTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "mapRegionTimerFired:", userInfo: nil, repeats: false) } func mapRegionTimerFired(sender: AnyObject) { // Load markers for current region: // mapView.centerCoordinate or mapView.region } } 

要识别mapview上的任何手势何时结束:

http://b2cloud.com.au/tutorial/mkmapview-determining-whether-region-change-is-from-user-interaction/

这对于用户完成缩放/旋转/拖动地图后仅执行数据库查询非常有用。

对于我而言,regionDidChangeAnimated方法只在手势完成后才被调用,拖动/缩放/旋转时不会被调用很多次,但是知道是否是由于手势而非常有用。

Swift 3解决scheme给Jano上面的答案 :

将协议UIGestureRecognizerDelegate添加到您的ViewController

 class MyViewController: UIViewController, UIGestureRecognizerDelegate 

viewDidLoad创buildUIPanGestureRecognizer并将delegate设置为self

 viewDidLoad() { // add pan gesture to detect when the map moves let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.didDragMap(_:))) // make your class the delegate of the pan gesture panGesture.delegate = self // add the gesture to the mapView mapView.addGestureRecognizer(panGesture) } 

添加一个协议方法,以便您的手势识别器将与现有的MKMapView手势一起工作

 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } 

在平移手势中添加将由select器调用的方法

 func didDragMap(_ sender: UIGestureRecognizer) { if sender.state == .ended { // do something here } } 

在这里input代码我设法做到这一点最简单的方法,它处理所有的交互与地图(轻拍/双/ N轻拍用1/2 / N的手指,泛1/2 / N的手指,捏和旋转

  1. 创buildgesture recognizer并添加到地图视图的容器
  2. gesture recognizer's delegate设置为实现UIGestureRecognizerDelegate某个对象
  3. 实现gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch)方法
 private func setupGestureRecognizers() { let gestureRecognizer = UITapGestureRecognizer(target: nil, action: nil) gestureRecognizer.delegate = self self.addGestureRecognizer(gestureRecognizer) } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { self.delegate?.mapCollectionViewBackgroundTouched(self) return false } 

很多这些解决scheme都是基于hacky /而不是Swift预期的方面,所以我select了一个更清晰的解决scheme。

我只是inheritanceMKMapView并覆盖touchesMoved。 虽然这个片段没有包括它,但我build议创build一个委托或通知来传递你想要的关于移动的任何信息。

 import MapKit class MapView: MKMapView { override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesMoved(touches, with: event) print("Something moved") } } 

您将需要更新故事板文件中的类以指向此子类,以及通过其他方式修改您创build的任何地图。

我试图在总是位于地图中心的地图中心注释一个注释,不pipe用途如何。 我尝试了上面提到的几种方法,但都不够好。 我最终find了解决这个问题的一个非常简单的方法,借鉴了Anna的答案,并与Eneko的答案相结合。 它基本上将regionWillChangeAnimated作为拖动的开始,而regionDidChangeAnimated作为一个结束,并使用计时器实时更新引脚:

 var mapRegionTimer: Timer? public func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) { mapRegionTimer?.invalidate() mapRegionTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { (t) in self.myAnnotation.coordinate = CLLocationCoordinate2DMake(mapView.centerCoordinate.latitude, mapView.centerCoordinate.longitude); self.myAnnotation.title = "Current location" self.mapView.addAnnotation(self.myAnnotation) }) } public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) { mapRegionTimer?.invalidate() }