определить, был ли MKMapView перетащен / перемещен - PullRequest
77 голосов
/ 05 апреля 2011

Есть ли способ определить, было ли перемещено MKMapView?

Я хочу получить местоположение в центре каждый раз, когда пользователь перетаскивает карту, используя CLLocationCoordinate2D centre = [locationMap centerCoordinate];, но мне нужен метод делегата или что-то вродеЭто срабатывает, как только пользователь перемещается по карте.

Заранее спасибо

Ответы [ 15 ]

230 голосов
/ 26 июля 2012

Код в принятом ответе срабатывает при изменении региона по любой причине.Чтобы правильно определить перетаскивание карты, вы должны добавить 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");
    }
}
69 голосов
/ 23 сентября 2014

Это единственный способ, который сработал для меня, который обнаруживает изменения панорамирования и масштабирования, инициированные пользователем:

- (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
    }
}
29 голосов
/ 05 апреля 2011

Посмотрите на ссылку MKMapViewDelegate .

В частности, эти методы могут быть полезны:

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

Убедитесь, что свойство делегата представления вашей карты установлено, чтобы эти методы вызывались.

26 голосов
/ 18 июня 2015

(Только) Swift-версия отличного решения @ mobi :

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
    }
}
12 голосов
/ 14 декабря 2016

Решение Swift 3 для Ответ Яно выше:

Добавление протокола UIGestureRecognizerDelegate в ваш ViewController

class MyViewController: UIViewController, UIGestureRecognizerDelegate

Создайте UIPanGestureRecognizer в viewDidLoad и установите 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

    }
}
7 голосов
/ 29 февраля 2016

По своему опыту, подобно «поиску во время набора текста», я обнаружил, что таймер является наиболее надежным решением. Это устраняет необходимость добавления дополнительных распознавателей жестов для панорамирования, сжатия, поворота, постукивания, двойного постукивания и т. Д.

Решение простое:

  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
        }
    
    }
    
7 голосов
/ 01 августа 2014

Другое возможное решение - реализовать 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 голосов
/ 13 января 2017

Многие из этих решений имеют хакерский характер, а не тот, который предполагал 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")
    }
}

Вам необходимо обновить класс в файлах раскадровки, чтобы он указывал наэтот подкласс, а также изменять любые карты, созданные вами другими способами.

6 голосов
/ 28 января 2014

Вы также можете добавить распознаватель жестов на карту в Интерфейсном Разработчике. Свяжите это с выходом для его действия в вашем viewController, я назвал мой "mapDrag" ...

Тогда вы сделаете что-то подобное в вашем viewController'е .m:

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

Убедитесь, что у вас там тоже есть:

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

Конечно, для того, чтобы это работало, вам нужно сделать ваш viewController UIGestureRecognizerDelegate в вашем файле .h.

В противном случае ответчик карты - единственный, кто слышит событие жеста.

4 голосов
/ 06 августа 2018

Вы можете проверить анимированное свойство, если false, то пользователь перетянул карту

 func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    if animated == false {
        //user dragged map
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...