确定是否拖动/移动了MKMapView

时间:2011-04-05 18:54:37

标签: ios mkmapview

有没有办法确定是否拖动了MKMapView?

我想在每次用户使用CLLocationCoordinate2D centre = [locationMap centerCoordinate];拖动地图时获取中心位置,但我需要一个委托方法或用户在使用地图导航时立即触发的内容。

提前致谢

16 个答案:

答案 0 :(得分:229)

当区域因任何原因发生变化时,接受的答案中的代码将触发。要正确检测地图拖动,您必须添加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;
}

第4步:如果您想要一次调用您的方法一次而不是每次拖动50次,请在选择器中检测到“拖动已结束”状态:

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

答案 1 :(得分:69)

对我来说,这是唯一可以检测平移以及用户启动的缩放变化的方法:

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

答案 2 :(得分:30)

查看MKMapViewDelegate参考。

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

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

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

答案 3 :(得分:26)

(只是)@mobi's excellent solution的Swift版本:

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

答案 4 :(得分:12)

以上Jano's answer的Swift 3解决方案:

将协议UIGestureRecognizerDelegate添加到ViewController

class MyViewController: UIViewController, UIGestureRecognizerDelegate

viewDidLoad中创建UIPanGestureRecognizer并将delegate设置为自我

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
}

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

func didDragMap(_ sender: UIGestureRecognizer) {
    if sender.state == .ended {

        // do something here

    }
}

答案 5 :(得分:7)

另一种可能的解决方案是在保存地图视图的视图控制器中实现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;
        }
    }
}

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

答案 6 :(得分:7)

根据我的经验,类似于&#34;在键入&#34;时搜索,我发现计时器是最可靠的解决方案。它不需要添加额外的手势识别器来进行平移,捏合,旋转,敲击,双击等。

解决方案很简单:

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

    thread.join()

答案 7 :(得分:6)

您还可以在Interface Builder中向地图添加手势识别器。将它链接到你的viewController中它的动作的插座,我称之为“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才能使它工作。

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

答案 8 :(得分:6)

很多这些解决方案都属于hacky /而不是Swift的目标,所以我选择了更清洁的解决方案。

我只是将MKMapView子类化并覆盖touchesMoved。虽然此代码段不包含此内容,但我建议您创建代理或通知,以传递有关此移动的任何信息。

import MapKit

class MapView: MKMapView {
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesMoved(touches, with: event)

        print("Something moved")
    }
}

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

答案 9 :(得分:3)

识别地图视图上的任何手势何时结束:

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

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

对我来说,仅在手势完成后调用了regionDidChangeAnimated方法,并且在拖动/缩放/旋转时没有多次调用,但知道它是否是由于手势是有用的。

答案 10 :(得分:3)

Jano的回答对我有用,所以我想我会留下Swift 4 / XCode 9的更新版本,因为我不是特别精通Objective C而且我确信还有其他一些不是

第1步:在viewDidLoad中添加此代码:

let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didDragMap(_:)))
panGesture.delegate = self

第2步:确保您的班级符合UIGestureRecognizerDelegate:

class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UIGestureRecognizerDelegate {

第3步:添加以下功能以确保您的panGesture可以与其他手势同时使用:

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

第4步:并确保您的方法不会被称为“每次拖动50次”,Jano正确地指出:

@objc func didDragMap(_ gestureRecognizer: UIPanGestureRecognizer) {
    if (gestureRecognizer.state == UIGestureRecognizerState.ended) {
        redoSearchButton.isHidden = false
        resetLocationButton.isHidden = false
    }
}

*注意在最后一步添加@objc。 XCode将在您的函数上强制使用此前缀,以便进行编译。

答案 11 :(得分:3)

您可以检查动画属性 如果为false,则用户拖动了地图

function validate_seq(value) {
  $(".image_sequence").each(function(){
    if (value==this.value) {
      alert('Sequence already exist');
      return false;
    }
  });
}

答案 12 :(得分:0)

在这里输入代码我设法以最简单的方式实现这一点,它处理与地图的所有交互(点击/双/ N点击与1/2 / N手指,平移与1/2 / N手指,捏和旋转

  1. 创建gesture recognizer并添加到地图视图的容器
  2. gesture recognizer's delegate设置为实现UIGestureRecognizerDelegate
  3. 的某个对象
  4. 实施gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch)方法
  5. 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
    }
    

答案 13 :(得分:0)

我试图在地图的中心有一个注释,无论用途如何,它都始终位于地图的中心。我尝试了上面提到的几种方法,但没有一种方法足够好。我最终找到了一种解决这个问题的简单方法,借鉴了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()
}

答案 14 :(得分:0)

首先,请确保您当前的视图控制器是地图的委托人。因此,将您的Map View委托设置为self并将MKMapViewDelegate添加到视图控制器。下面的示例。

class Location_Popup_ViewController: UIViewController, MKMapViewDelegate {
   // Your view controller stuff
}

并将其添加到您的地图视图

var myMapView: MKMapView = MKMapView()
myMapView.delegate = self

第二,添加此功能,该功能在地图移动时触发。它会过滤掉所有动画,并且只有与之交互时才会触发。

func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
   if !animated {
       // User must have dragged this, filters out all animations
       // PUT YOUR CODE HERE
   }
}

答案 15 :(得分:0)

我知道这是一篇旧文章,但这里是我的{4}和Pan {Pinch}手势的Swift 4/5代码。

class MapViewController: UIViewController, MapViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.didDragMap(_:)))
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(self.didPinchMap(_:)))
        panGesture.delegate = self
        pinchGesture.delegate = self
        mapView.addGestureRecognizer(panGesture)
        mapView.addGestureRecognizer(pinchGesture)
    }

}

extension MapViewController: UIGestureRecognizerDelegate {

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

    @objc func didDragMap(_ sender: UIGestureRecognizer) {
        if sender.state == .ended {
            //code here
        }
    }

    @objc func didPinchMap(_ sender: UIGestureRecognizer) {
        if sender.state == .ended {
            //code here
        }
    }
}

享受!