web-dev-qa-db-ja.com

iOS-MapViewを特定の地域に制限するにはどうすればよいですか?

私は次の問題を抱えています:

MapViewにオーバーレイとして追加する「描画マップ」(画像)があります。問題ありません。ただし、MapViewをオーバーレイの領域に制限する必要があるため、ユーザーはこの領域の外側でスクロール/ズームできません。ただし、「境界」の内側でスクロール/ズームできるはずです。オーバーレイの「」-MapViewのズーム/スクロールを無効にできないことを意味します。

このトピックに関するアイデア/解決策はありますか? MapView/-Kitを使用する理由は、カスタムマップにさまざまなPOIを追加する必要があるためです。これは、カスタムマップを表示するためにImageView + ScrollViewを使用するだけの場合、より複雑になる可能性があります。

私はこのトピックについて多くのことを研究しましたが、良い解決策は見つかりませんでした。

どんな助けでも大歓迎です!

よろしく、クリスチャン

編集:これが私たちの解決策です:マップを制限するために左上と右下の座標を指定します。 (最小)ズームレベルも制限されています。減速を無効にしました。マップから少し跳ね返ることができます(パフォーマンス/ uxを向上させるため)。ユーザーがグーグルの元の世界地図を見ることができないように、オーバーレイに最大1kmの灰色の境界線を追加しました。

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
17
cweinberger

実装することによって:

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

リージョンを特定のリージョンにリセットできるはずです。

その答えで これを行う方法の例を見てください。


別の解決策は、より正確なイベントをもたらしますが、より複雑です(私は現在、これを別のニーズにうまく使用しています)は、MKMapViewをサブクラス化し、UIScrollViewDelegateプロトコルをオーバーライドすることです。

その場合は、必ず次のようにsuper実装を呼び出してください。

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

注:プロトコルは公開されていますが、MKMapViewの実装は不明であり、iOSのバージョンによって異なる可能性があるため、事前にrespondsToSelector:で確認する方が安全です。 mustスーパー実装を呼び出さないと、Mapが正しく機能しません

6
Vincent Guerci

制限されたMKMapViewのさまざまな方法を試した後、mapDidChangeを使用し、中心点が境界の外側にある場合にリセットすると、アニメーションで最も効果的であると結論付けました。はい

これが私がそれを行う方法です(ニュージーランドの緯度/ロングスパン/センターを使用)。

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

これはかなり古い質問ですが、無限ループを回避するには、次のようなものを試すことができます: https://stackoverflow.com/a/4126011/1234011

基本的に、値を設定したのがあなたである場合にコールバックが再度発生しないようにフラグを設定します。

  • ケン
0
Ken Koch