9

パス スタイルの視差テーブル ビュー ヘッダー内に MKMapView を表示しています。効果を作成するには、mapView の境界をユーザーに表示される領域よりも大きくします。すべてのマップの注釈が MKMapView の表示領域内に含まれるように、マップ ビューの領域を設定する必要があります。これを行う最善の方法は何ですか?

可視領域が制限された MKMapView

明確にするために編集してください:これはユースケースです。mapView のサイズは 320 x 380 です。ただし、可視領域は rect (0.0、20.0、320.0、100.0) によって定義されます。mapView 内のこの rect にすべての注釈が表示されるように、領域を設定する必要があります。

4

7 に答える 7

18

すべての注釈が の特定の部分に含まれるようにマップ リージョンを設定するにはMKMapView、3 つの手順を実行します。入力はmapViewannotationsFrameです。

  1. MKMapRect mapRectすべての注釈を含む を計算します。
  2. mapView.boundsとからパディング インセットを計算しますannotationsFrame
  3. -setVisibleMapRect:edgePadding:animated:マップ ビューで呼び出します。

以下はテストのスクリーンショットです。赤いオーバーレイはannotationsFrame.

すべての注釈が指定された注釈フレーム内にあることを示すテストのスクリーン ショット

これがコードです。注意: コードへの追加を簡素化するためのすべてが 1 つの方法であり、同じ座標で n 個の注釈を渡す、またはマップもズームアウトする必要があるほど注釈が離れているなどのエッジ ケースについてはテストされていません。または、経度 +/-180 度でマップの端にまたがる座標を持っています。

- (void)zoomAnnotationsOnMapView:(MKMapView *)mapView toFrame:(CGRect)annotationsFrame animated:(BOOL)animated
{
    if (_mapView.annotations.count < 2) return;


    // Step 1: make an MKMapRect that contains all the annotations

    NSArray *annotations = _mapView.annotations;

    id <MKAnnotation> firstAnnotation = [annotations objectAtIndex:0];
    MKMapPoint minPoint = MKMapPointForCoordinate(firstAnnotation.coordinate);
    MKMapPoint maxPoint = minPoint;

    for (id <MKAnnotation> annotation in annotations) {
        MKMapPoint point = MKMapPointForCoordinate(annotation.coordinate);
        if (point.x < minPoint.x) minPoint.x = point.x;
        if (point.y < minPoint.y) minPoint.y = point.y;
        if (point.x > maxPoint.x) maxPoint.x = point.x;
        if (point.y > maxPoint.y) maxPoint.y = point.y;
    }

    MKMapRect mapRect = MKMapRectMake(minPoint.x, minPoint.y, maxPoint.x - minPoint.x, maxPoint.y - minPoint.y);


    // Step 2: Calculate the edge padding

    UIEdgeInsets edgePadding = UIEdgeInsetsMake(
        CGRectGetMinY(annotationsFrame),
        CGRectGetMinX(annotationsFrame),
        CGRectGetMaxY(mapBounds) - CGRectGetMaxY(annotationsFrame),
        CGRectGetMaxX(mapBounds) - CGRectGetMaxX(annotationsFrame)
    );


    // Step 3: Set the map rect

    [mapView setVisibleMapRect:mapRect edgePadding:edgePadding animated:animated];
}

完璧な配置を目指す場合 (そうでない人も)、考慮すべき 3 つの点を次に示します。

  1. このコードは、すべての座標が 内にあることを保証しますannotationsFrameが、注釈自体は外部にある可能性があります。これを防ぐには、単純にパディングを増やします。たとえば、注釈が 20x20 で、座標の中央に配置されている場合は、すべての側面で 10 個のパディングを使用します。
  2. iOS 7 より前では、マップは完全なズーム スケールではなく、次のタイル サイズ (2 のべき乗) にズームされていました。そのため、スクリーンショットに示されているように、注釈の周りに必要以上のスペースができてしまいます。
  3. iOS 7 では、マップ ビューは完全にズームするだけでなく、ステータス バーを自動的に考慮します。計算を正しく行うには、iOS 7 の上部パディングからステータス バーの高さを差し引く必要があります。
于 2013-02-25T20:53:30.950 に答える
6

iOS 7.0 以降、これは で簡単に実現できますshowAnnotations

迅速:

mapView.showAnnotations(mapView.annotations, animated: true)

目的 C:

[mapView showAnnotations:mapView.annotations animated:YES];

上記のステートメントは、すべての注釈を表示するために、マップ ビューの可視四角形を調整します。

于 2016-01-21T10:56:27.853 に答える
0

特定の四角形にある注釈を見つけたい場合:

- (NSArray*)allAnnotationsInMapRect:(MKMapRect)mapRect {
    NSMutableArray *annotationsInRect = [NSMutableArray array];
    for(id<MKAnnotation *ann in self.allAnnotations) {
        MKMapPoint pt = MKMapPointForCoordinate(ann.coordinate);
        if(MKMapRectContainsPoint(mapRect, pt)) {
            [annotationsInRect addObject:ann];
        }
    }

    return annotationsInRect;
}

注釈ビューが四角形にあることを確認するには、注釈の領域を取得し、それらをウォークスルーして各ビューの境界を取得し、境界がマップの visibleRect 内に収まるかどうかを確認し、そうでない場合は領域を変更します!

~~ このように:

- (void)assureAnnotationViewsAreVisible:(NSArray*)annotations originalRegion:(MKCoordinateRegion)originalRegion {
    CGFloat smallestX = MAXFLOAT;
    CGFloat smallestY = MAXFLOAT;
    CGFloat biggestX = -100;
    CGFloat biggestY = -100;

    //NSLog(@"---: %d", annotations.count);
    for(id<MKAnnotation> *annotation in annotations) {
        UIView *annotationView = [self.mapView viewForAnnotation:v];

        CGRect annotationViewFrame = annotationView.bounds;
        annotationViewFrame.origin = [self.mapView convertCoordinate:annotationView.coordinate toPointToView:self.mapView];
        annotationViewFrame.origin = CGPointMake(annotationViewFrame.origin.x-annotationViewFrame.size.width/2,
                                                 annotationViewFrame.origin.y-annotationViewFrame.size.height);

        smallestX = MIN(annotationViewFrame.origin.x, smallestX);
        smallestY = MIN(annotationViewFrame.origin.y, smallestY);
        biggestX = MAX(annotationViewFrame.origin.x+annotationViewFrame.size.width, biggestX);
        biggestY = MAX(annotationViewFrame.origin.y+annotationViewFrame.size.height, biggestY);
    }
    //NSLog(@"---");

    CGRect bounds = self.mapView.bounds;
    if(smallestX < bounds.origin.x || smallestY < bounds.origin.y || biggestX > bounds.origin.x+bounds.size.width || biggestY > bounds.origin.y+bounds.size.height) {
        CGRect neededRect = bounds;
        neededRect.origin = CGPointMake(MIN(bounds.origin.x, smallestX), MIN(bounds.origin.y, smallestY));
        neededRect.size = CGSizeMake(MAX(bounds.size.width, biggestX), MAX(bounds.size.height, biggestY));

        MKCoordinateRegion neededRegion = [self.mapView convertRect:neededRect toRegionFromView:self.mapView];
        _ignoreRegionChange = YES;
        [self.mapView setRegion:originalRegion animated:NO];
        _ignoreRegionChange = NO;
        [self.mapView setRegion:neededRegion animated:YES];
    }
    else {
        MKCoordinateRegion currentRegion = self.mapView.region;
        _ignoreRegionChange = YES;
        [self.mapView setRegion:originalRegion animated:NO];
        _ignoreRegionChange = NO;
        [self.mapView setRegion:currentRegion animated:YES];
    }
}
于 2013-02-22T08:34:10.440 に答える
0

計算を近似する準備ができている場合は、巧妙なスケーリングを使用して実行できます。

ターゲット エリアは、380 である mapView のうち高さが 80 です。したがって、注釈に合わせて計算された領域よりも 4.75 倍高い領域が必要です。(上に 0.25 追加、下に 3.5 追加)。

最初に、リージョン (または maprect など、作業したいもの) を取得し、ターゲットの表示可能領域と同じ比率にする必要があります。これは、非常に広くて短い領域は、表示可能な領域の上部と下部に接触しないため、その高さを乗算しても、マップ ビューの上部と下部に接触するものにはなりません。したがって、viewable_height/viewable_width > annotations_height/annotations_widthをに設定する必要があるannotations_height場合annotations_width * (viewable_height/viewable_width)

次に、注釈ボックスの北に 25%、南に 350% を追加します。これを行うには、中心を (現在の高さの) 212.5% 南に移動し、垂直スパンを 475% 増やします。

ここで、世界が球体であり、平面投影を見ていないことを考えると、これはすべて概算です (つまり、赤道付近の 1 度の緯度は、極付近の 1 度よりも小さく描かれます)。しかし、正確にしたい場合は、緯度などに応じて数値をスケーリングすることを検討できます。都市規模の注釈のみを扱っている場合は、おそらく問題ありません。

それが役立つことを願っています。

于 2013-02-22T03:30:08.967 に答える
-1

lan と lon のすべての注釈エッジ値 (最大値と最小値) から取得してみてください。

最初に次の値を定義します。

static float maxLat = FLT_MIN;
static float maxLon = FLT_MIN;
static float minLat = FLT_MAX;
static float minLon = FLT_MAX;

次に、この関数を使用してスパンとリージョンを計算します。

- (void) zoomAndFit {
    for(int i = 0; i < [self.points count]; i++) {
        PRPlaceModel *place = [self.points objectAtIndex:i];
        CLLocationCoordinate2D location; 
        location.latitude = [place.lat floatValue];
        location.longitude = [place.lon floatValue];
        minLat = MIN(minLat, location.latitude);
        minLon = MIN(minLon, location.longitude);
        maxLat = MAX(maxLat, location.latitude);
        maxLon = MAX(maxLon, location.longitude);
    }
    MKCoordinateRegion region; 
    MKCoordinateSpan span; 
    span.latitudeDelta = 1.2*(maxLat - minLat); 
    span.longitudeDelta = 1.2*(maxLon - minLon);

    CLLocationCoordinate2D location; 
    location.latitude = (minLat + maxLat)/2;
    location.longitude = (minLon + maxLon)/2;

    region.span=span; 
    region.center=location; 
    [self.mapView setRegion:region animated:TRUE]; 
    [self.mapView regionThatFits:region]; 
}

そしてそれをviewDidLoadメソッドで使用します:

-(void)viewDidLoad
{
    [super viewDidLoad];
    [self zoomAndFit];
}
于 2013-02-16T23:34:47.320 に答える