IOS - Как ограничить MapView конкретным регионом?

У меня есть следующая проблема:

У меня есть "нарисованная карта" (изображение), которую я добавляю к MapView в качестве наложения. Нет проблем с этим. Но мне нужно ограничить MapView областью Overlay, так что пользователь не может прокручивать/увеличивать за пределами этого региона.. но должно быть возможно прокручивать/масштабировать внутри "границ" "наложения - означает, что я не могу просто отключить масштабирование/прокрутку для MapView.

Есть ли идеи/решения по этой теме? Причиной использования MapView/-Kit является то, что мне нужно добавить различные POI на пользовательскую карту. Это может усложниться при использовании ImageView + ScrollView для представления пользовательской карты.

Я много исследовал эту тему, но я не нашел приятного решения.

Любая помощь приветствуется!

С наилучшими пожеланиями, Christian

Изменить: это наше решение: Для ограничения карты вы предоставляете точную и прямую координаты. (Минимальный) масштаб также ограничен. Я дезактивировал замедление, и вы можете немного отскакивать от карты (для лучшей производительности /ux ). Я добавил к оклеине 1 км серой границы, чтобы пользователь не смог увидеть карту мира orignal google.

LimitedMapView.h:

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>


@interface LimitedMapView : MKMapView <UIScrollViewDelegate>{

}

@property (nonatomic, assign) CLLocationCoordinate2D topLeftCoordinate;
@property (nonatomic, assign) CLLocationCoordinate2D bottomRightCoordinate;


@end

LimitedMapView.m:

#import "LimitedMapView.h"

@implementation LimitedMapView

@synthesize topLeftCoordinate, bottomRightCoordinate;

- (void)scrollViewDidZoom:(UIScrollView *)scrollView{

    if([super respondsToSelector:@selector(scrollViewDidZoom:)]) [super scrollViewDidZoom:scrollView];

    if ([self region].span.latitudeDelta > 0.002401f || [self region].span.longitudeDelta > 0.003433f) {

        CLLocationCoordinate2D center = self.centerCoordinate;
        MKCoordinateSpan span = MKCoordinateSpanMake(0.002401f, 0.003433f);

        self.region = MKCoordinateRegionMake(center, span);

    }

}

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{

    if([super respondsToSelector:@selector(scrollViewDidEndDragging:)]) [super scrollViewDidEndDragging:scrollView willDecelerate:decelerate];

    MKCoordinateRegion currentRegion = self.region;
    bool changeRegionLong = YES;
    bool changeRegionLat = YES;

    // LONGITUDE    
    if((currentRegion.center.longitude - (currentRegion.span.longitudeDelta/2)) < self.topLeftCoordinate.longitude) {

        currentRegion.center.longitude = (topLeftCoordinate.longitude + (currentRegion.span.longitudeDelta/2));

    } else if((currentRegion.center.longitude + (currentRegion.span.longitudeDelta/2)) > self.bottomRightCoordinate.longitude) {

        currentRegion.center.longitude = (bottomRightCoordinate.longitude - (currentRegion.span.longitudeDelta/2));

    } else {

        changeRegionLong = NO;

    }

    // LATITUDE    
    if((currentRegion.center.latitude + (currentRegion.span.latitudeDelta/2)) > self.topLeftCoordinate.latitude) {

        currentRegion.center.latitude = (topLeftCoordinate.latitude - (currentRegion.span.latitudeDelta/2));

    } else if((currentRegion.center.latitude - (currentRegion.span.latitudeDelta/2)) < self.bottomRightCoordinate.latitude) {

        currentRegion.center.latitude = (bottomRightCoordinate.latitude + (currentRegion.span.latitudeDelta/2));

    } else {

        changeRegionLat = NO;

    }

    if(changeRegionLong || changeRegionLat) [self setRegion:currentRegion animated:YES];

}

-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{

    [scrollView setContentOffset:scrollView.contentOffset animated:YES];
}

@end

Ответы

Ответ 1

Используя:

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

Вы должны обладать reset регионом для своего конкретного.

Посмотрите в этом ответе, чтобы иметь пример того, как это сделать.


Другое решение, которое приносит более точные события, но более сложное (в настоящее время я использую это для другой необходимости), относится к подклассу MKMapView и переопределяет протокол UIScrollViewDelegate.

Если вы это сделаете, обязательно вызовите реализацию super следующим образом:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
  if ([super respondsToSelector:@selector(scrollViewWillBeginDragging:)])
    [super scrollViewWillBeginDragging:scrollView];
  // do what you want
}

Примечание. Пока протокол является общедоступным, реализация MKMapView неизвестна и может отличаться версиями iOS, поэтому более безопасно проверять с помощью respondsToSelector: раньше. Вы должны выполнять супервыполнения или Map будет работать неправильно.

Ответ 2

После нескольких способов ограниченного MKMapView я пришел к выводу, что использование mapDidChange и сброс, если вы находитесь за центральной границей, лучше всего работают с анимированными: YES

Вот как я это делаю (использование Новой Зеландии lat/Long span/center).

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ 
  if ((mapView.region.span.latitudeDelta > 15.589921 ) || (mapView.region.span.longitudeDelta > 175.836914) ) {
    CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914);

    MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 );

    MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ);

    [mapView setRegion: NZRegion animated: YES];
  }

 if (abs(abs(mapView.region.center.latitude) - 41.162114) > (13.589921 / 2) ) {
    CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914);

    MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 );

    MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ);

    [mapView setRegion: NZRegion animated: YES];

  }

  if (abs(abs(mapView.region.center.longitude) - 172.836914) > (14.062500 / 2) ) {
    CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914);

     MKCoordinateSpan  spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 );

     MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ);

     [mapView setRegion: NZRegion animated: YES];
  }
}

Ответ 3

Я знаю, что это довольно старый вопрос, но чтобы избежать бесконечного цикла, вы можете попробовать что-то вроде этого: fooobar.com/info/367861/...

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

  • Кен