web-dev-qa-db-ja.com

iOSMKMapViewズームですべてのマーカーを表示

私はMKMapViewを使用していて、地図上にいくつかの点をプロットしました。 MKCoordinateRegionMKCoordinateSpanを使用して、ポイントの1つを中心にズームなどを有効にしましたが、それは私が望んでいることではありません...

Javascriptの境界へのズーム機能に似たものを使おうとしています。したがって、すべてのポイントがユーザーに表示されるはずです。 (英国の周りには約10ポイントあります)それらすべてを表示したいのですが、それらのほとんどがロンドンエリアにあった場合は、そこにズームします。

これをプログラムで解決する方法はありますか?

22
Matt Facer

承知しました。注釈の中から緯度と経度の最大値と最小値を見つけ(map.annotationsを反復処理することで実行できます)、それらすべてを表示するようにマップを設定します。

// pad our map by 10% around the farthest annotations
#define MAP_PADDING 1.1

// we'll make sure that our minimum vertical span is about a kilometer
// there are ~111km to a degree of latitude. regionThatFits will take care of
// longitude, which is more complicated, anyway. 
#define MINIMUM_VISIBLE_LATITUDE 0.01

MKCoordinateRegion region;
region.center.latitude = (minLatitude + maxLatitude) / 2;
region.center.longitude = (minLongitude + maxLongitude) / 2;

region.span.latitudeDelta = (maxLatitude - minLatitude) * MAP_PADDING;

region.span.latitudeDelta = (region.span.latitudeDelta < MINIMUM_VISIBLE_LATITUDE)
    ? MINIMUM_VISIBLE_LATITUDE 
    : region.span.latitudeDelta;

region.span.longitudeDelta = (maxLongitude - minLongitude) * MAP_PADDING;

MKCoordinateRegion scaledRegion = [map regionThatFits:region];
[map setRegion:scaledRegion animated:YES];
68
Seamus Campbell

IOS 7以降のみを対象としている場合は、以下を使用できます。

- (void)showAnnotations:(NSArray *)annotations 
               animated:(BOOL)animated
18
Gerry Shaw

これは、マップにオーバーレイしている注釈ビューの高さを考慮した改善です(たとえば、座標オフセットが下部にあるときに注釈の上部が切り取られないようにします)。または、さらに一般化すると、パーセンテージではなくピクセル単位でパディングを指定できます。注釈の境界を見つける2段階のパスが必要です。次に、マップのパディングを考慮して境界をさらに増やします。

- (void) zoomToAnnotationsBounds:(NSArray *)annotations {

CLLocationDegrees minLatitude = DBL_MAX;
CLLocationDegrees maxLatitude = -DBL_MAX;
CLLocationDegrees minLongitude = DBL_MAX;
CLLocationDegrees maxLongitude = -DBL_MAX;

for (MyAnnotation *annotation in annotations) {
            double annotationLat = annotation.coordinate.latitude;
            double annotationLong = annotation.coordinate.longitude;
    minLatitude = fmin(annotationLat, minLatitude);
    maxLatitude = fmax(annotationLat, maxLatitude);
    minLongitude = fmin(annotationLong, minLongitude);
    maxLongitude = fmax(annotationLong, maxLongitude);
}

    // See function below
[self setMapRegionForMinLat:minLatitude minLong:minLongitude maxLat:maxLatitude maxLong:maxLongitude];

// If your markers were 40 in height and 20 in width, this would zoom the map to fit them perfectly. Note that there is a bug in mkmapview's set region which means it will snap the map to the nearest whole zoom level, so you will rarely get a perfect fit. But this will ensure a minimum padding.
UIEdgeInsets mapPadding = UIEdgeInsetsMake(40.0, 10.0, 0.0, 10.0);
CLLocationCoordinate2D relativeFromCoord = [self.mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:self.mapView];

// Calculate the additional lat/long required at the current zoom level to add the padding
CLLocationCoordinate2D topCoord = [self.mapView convertPoint:CGPointMake(0, mapPadding.top) toCoordinateFromView:self.mapView];
CLLocationCoordinate2D rightCoord = [self.mapView convertPoint:CGPointMake(0, mapPadding.right) toCoordinateFromView:self.mapView];
CLLocationCoordinate2D bottomCoord = [self.mapView convertPoint:CGPointMake(0, mapPadding.bottom) toCoordinateFromView:self.mapView];
CLLocationCoordinate2D leftCoord = [self.mapView convertPoint:CGPointMake(0, mapPadding.left) toCoordinateFromView:self.mapView];

double latitudeSpanToBeAddedToTop = relativeFromCoord.latitude - topCoord.latitude;
double longitudeSpanToBeAddedToRight = relativeFromCoord.latitude - rightCoord.latitude;
double latitudeSpanToBeAddedToBottom = relativeFromCoord.latitude - bottomCoord.latitude;
double longitudeSpanToBeAddedToLeft = relativeFromCoord.latitude - leftCoord.latitude;

maxLatitude = maxLatitude + latitudeSpanToBeAddedToTop;
minLatitude = minLatitude - latitudeSpanToBeAddedToBottom;

maxLongitude = maxLongitude + longitudeSpanToBeAddedToRight;
minLongitude = minLongitude - longitudeSpanToBeAddedToLeft;

[self setMapRegionForMinLat:minLatitude minLong:minLongitude maxLat:maxLatitude maxLong:maxLongitude];
}

-(void) setMapRegionForMinLat:(double)minLatitude minLong:(double)minLongitude maxLat:(double)maxLatitude maxLong:(double)maxLongitude {

    MKCoordinateRegion region;
    region.center.latitude = (minLatitude + maxLatitude) / 2;
    region.center.longitude = (minLongitude + maxLongitude) / 2;
    region.span.latitudeDelta = (maxLatitude - minLatitude);
    region.span.longitudeDelta = (maxLongitude - minLongitude);

    // MKMapView BUG: this snaps to the nearest whole zoom level, which is wrong- it doesn't respect the exact region you asked for. See http://stackoverflow.com/questions/1383296/why-mkmapview-region-is-different-than-requested
    [self.mapView setRegion:region animated:YES];
}
14
Willster

それは古い質問であり、あなたが助けを必要としないかもしれないことを私は知っています。しかし、iOS7の時点で使用できる新しいメソッドがMKMapViewにあるので、今これを行う方法を探している人のためにそれを公開しています。清潔で簡単です。

宣言

Swift

func showAnnotations(_ annotations: [AnyObject]!,
            animated animated: Bool)

目的-C

- (void)showAnnotations:(NSArray *)annotations
               animated:(BOOL)animated

パラメーター

注釈マップに表示する注釈。アニメーション化マップ領域の変更をアニメーション化する場合はYES、アニメーションなしでマップに新しい領域をすぐに表示する場合はNO。

討論

このメソッドを呼び出すと、regionプロパティの値と、場合によっては他のプロパティが更新され、新しいマップリージョンが反映されます。

7
Matt

すべての完全な作業コードで修正された回答。

//Zooming the ploted Area
- (void)zoomToAnnotationsBounds:(NSArray *)latLongArray {
        __block CLLocationDegrees minLatitude = DBL_MAX;
        __block CLLocationDegrees maxLatitude = -DBL_MAX;
        __block CLLocationDegrees minLongitude = DBL_MAX;
        __block CLLocationDegrees maxLongitude = -DBL_MAX;

        [latLongArray enumerateObjectsUsingBlock:^(NSString *latLongObj, NSUInteger latLongIdx, BOOL *stop) {
            latLongObj = [latLongArray objectAtIndex:latLongIdx];
            NSArray *latLongPoint = [latLongObj componentsSeparatedByString:@","];

            double annotationLat = [[latLongPoint objectAtIndex:0] doubleValue];
            double annotationLong = [[latLongPoint objectAtIndex:1] doubleValue];
            minLatitude = fmin(annotationLat, minLatitude);
            maxLatitude = fmax(annotationLat, maxLatitude);
            minLongitude = fmin(annotationLong, minLongitude);
            maxLongitude = fmax(annotationLong, maxLongitude);
        }];

        [self setMapRegionForMinLat:minLatitude minLong:minLongitude maxLat:maxLatitude maxLong:maxLongitude];
}


-(void) setMapRegionForMinLat:(double)minLatitude minLong:(double)minLongitude maxLat:(double)maxLatitude maxLong:(double)maxLongitude {

    // pad our map by 10% around the farthest annotations

    // we'll make sure that our minimum vertical span is about a kilometer
    // there are ~111km to a degree of latitude. regionThatFits will take care of
    // longitude, which is more complicated, anyway.

    MKCoordinateRegion region;
    region.center.latitude = (minLatitude + maxLatitude) / 2;
    region.center.longitude = (minLongitude + maxLongitude) / 2;

    region.span.latitudeDelta = (maxLatitude - minLatitude) * MAP_PADDING;

    region.span.latitudeDelta = (region.span.latitudeDelta < MINIMUM_VISIBLE_LATITUDE)
    ? MINIMUM_VISIBLE_LATITUDE
    : region.span.latitudeDelta;

    region.span.longitudeDelta = (maxLongitude - minLongitude) * MAP_PADDING;

    MKCoordinateRegion scaledRegion = [regionsMapView regionThatFits:region];
    [regionsMapView setRegion:scaledRegion animated:YES];

}
0