주석 핀에 맞게 MKMapView를 확대 하시겠습니까?


193

MKMapView를 사용하고 있으며 5-10km 면적에 대한 주석 핀을 맵에 추가했습니다. 응용 프로그램을 실행하면 전 세계를 표시하기 위해지도가 축소되기 시작합니다. 핀이보기에 맞도록지도를 확대 / 축소하는 가장 좋은 방법은 무엇입니까?

편집 : 내 초기 생각은 MKCoordinateRegionMake를 사용하고 내 주석에서 좌표 중심, 경도 델타 및 위도 델타를 계산하는 것입니다. 나는 이것이 효과가있을 것이라고 확신하지만, 나는 명백한 것이 누락되지 않았는지 확인하고 싶었다.

코드 추가, BTW : FGLocation은을 준수하는 클래스 MKAnnotation이며 locationFake는 NSMutableArray이러한 객체 중 하나입니다. 의견은 언제나 환영합니다 ....

- (MKCoordinateRegion)regionFromLocations {
    CLLocationCoordinate2D upper = [[locationFake objectAtIndex:0] coordinate];
    CLLocationCoordinate2D lower = [[locationFake objectAtIndex:0] coordinate];

    // FIND LIMITS
    for(FGLocation *eachLocation in locationFake) {
        if([eachLocation coordinate].latitude > upper.latitude) upper.latitude = [eachLocation coordinate].latitude;
        if([eachLocation coordinate].latitude < lower.latitude) lower.latitude = [eachLocation coordinate].latitude;
        if([eachLocation coordinate].longitude > upper.longitude) upper.longitude = [eachLocation coordinate].longitude;
        if([eachLocation coordinate].longitude < lower.longitude) lower.longitude = [eachLocation coordinate].longitude;
    }

    // FIND REGION
    MKCoordinateSpan locationSpan;
    locationSpan.latitudeDelta = upper.latitude - lower.latitude;
    locationSpan.longitudeDelta = upper.longitude - lower.longitude;
    CLLocationCoordinate2D locationCenter;
    locationCenter.latitude = (upper.latitude + lower.latitude) / 2;
    locationCenter.longitude = (upper.longitude + lower.longitude) / 2;

    MKCoordinateRegion region = MKCoordinateRegionMake(locationCenter, locationSpan);
    return region;
}

10
iOS 7 참고 : 새로운 showAnnotations : animated : 메소드를 사용하면이 수동 영역 계산을 피할 수 있습니다.

답변:


123

맞습니다.

최대 및 최소 위도 및 경도를 찾고 간단한 산술을 적용하고를 사용하십시오 MKCoordinateRegionMake.

사용, 아이폰 OS 7 이상 showAnnotations:animated:에서 MKMapView.h:

// Position the map such that the provided array of annotations are all visible to the fullest extent possible. 
- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);

158
아이폰 OS 7의 경우와 (MKMapView.h를 참조) 위 : // Position the map such that the provided array of annotations are all visible to the fullest extent possible. - (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);
Abhishek 베디

1
이것은 잘 작동하지만 때때로 (지도에서) 확대 한 다음이 방법을 호출하는 버튼을 사용하여 중앙에 배치하려고하면 작동하지 않는 것 같습니다.
RPM

5
showAnnotations해당 위치에 대한 주석이 이미있는 경우에도 주석을지도에 추가 한다는 점에 유의해야 합니다.
Eneko Alonso

@EnekoAlonso 당신은 removeAnnotations(_ annotations:)즉시 전화 후이 문제를 해결할 수 있습니다showAnnotations(_ annotations:animated)
Alain Stulz

1
또한 showAnnotations가 영역을 주석을 표시하도록 설정하는 동안 영역은 여전히 ​​가로 세로 비율에 맞게 조정됩니다. 이로 인해 일부 주석이 제외되는 경우가 많습니다. 또한 showAnnotations가 여기에 제시된 유일한 솔루션입니다. 다른 답변들조차도 국제 날짜 표시 줄에 걸친 주석을 처리하려고 시도하지 않습니다.
Gordon Dove

335

이것은 나를 위해 여기 에서 찾은 입니다.

(편집 : @Micah의 제안을 사용하여 해결책을 업데이트하여 rect가 무한히 작아지지 않도록 pointRect를 0.1 씩 증가시킵니다!)

MKMapRect zoomRect = MKMapRectNull;
for (id <MKAnnotation> annotation in mapView.annotations)
{
    MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
    MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
    zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
[mapView setVisibleMapRect:zoomRect animated:YES];

 

첫 번째 줄을 다음과 같이 바꾸어 userLocation 핀을 포함하도록 이것을 업데이트 할 수도 있습니다.

MKMapPoint annotationPoint = MKMapPointForCoordinate(mapView.userLocation.coordinate);
MKMapRect zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);

4
참으로 좋습니다. isNull을 확인할 필요는 없습니다. MKMapRectUnion이이를 수행합니다. 문서에서 : "두 사각형 중 하나가 null이면이 메서드는 다른 사각형을 반환합니다."
Felix Lamouroux

37
아주 좋은 해결책 !!! 패딩을 추가하기위한 약간의 터치가 있습니다 : double inset = -zoomRect.size.width * 0.1; [self.mapView setVisibleMapRect : MKMapRectInset (zoomRect, inset, inset) animated : YES];
Craig B

1
대박! 잠재적 인 추가 : '현재 위치 주석'을 제외하려면 for 루프에 if 문을 추가하십시오. if (! [annotation isKindOfClass : [MKUserLocation class]]) {// 여기서 할 일}
kgaidis

2
패딩을위한 @CraigB 솔루션은 훌륭하지만 경로가 수직 인 경우 (예 : 남쪽에서 북쪽으로의 이동) 이중 인세 트 = MIN (-zoomRect.size.width * 0.1, -zoomRect.size)를 수정하기 위해 제대로 작동하지 않습니다. 높이 * 0.1);
Farhad Malekpour

1
패딩으로 향상 : double insetWidth = -zoomRect.size.width * 0.2; double insetHeight = -zoomRect.size.height * 0.2; MKMapRect insetRect = MKMapRectInset (zoomRect, insetWidth, insetHeight); 그런 다음이 새로운 insertRect
dulgan

121

Apple은 삶을 조금 단순화하기 위해 IOS 7을위한 새로운 방법을 추가했습니다.

[mapView showAnnotations:yourAnnotationArray animated:YES];

맵 뷰에 저장된 배열에서 쉽게 가져올 수 있습니다.

yourAnnotationArray = mapView.annotations;

카메라를 빠르게 조정하십시오!

mapView.camera.altitude *= 1.4;

사용자에게 iOS 7 이상 또는 OS X 10.9 이상이 설치되어 있지 않으면 작동하지 않습니다. 여기 에서 커스텀 애니메이션을 확인 하십시오


이것이 내 구현의 다른 요인 때문인지 확실 showAnnotations하지 않지만 수동 구현과 달리 주석의 확대 / 축소와 밀접한 관련이 없으므로 수동 주석을 고수했습니다.
Ted Avery

1
mapView.camera.altitude * = .85와 같이 카메라 고도에 1을 곱하십시오. 더 가까운 뷰포트
Ryan Berg

또한 현재 보이는지도 영역 외부에서 주석을 선택하는 데 유용하다는 것을 알았습니다. 기본적으로 MapView는 보이지 않는 주석을 선택하지 않습니다. selectAnnotation을 호출하기 전에 표시 할 수없는 주석 배열로 showAnnotations를 호출하면지도에서 볼 수있는 영역이 업데이트됩니다.
MandisaW

42

이 코드를 사용하고 나에게 잘 작동합니다.

-(void)zoomToFitMapAnnotations:(MKMapView*)aMapView
{
    if([aMapView.annotations count] == 0)
        return;

    CLLocationCoordinate2D topLeftCoord;
    topLeftCoord.latitude = -90;
    topLeftCoord.longitude = 180;

    CLLocationCoordinate2D bottomRightCoord;
    bottomRightCoord.latitude = 90;
    bottomRightCoord.longitude = -180;

    for(MapViewAnnotation *annotation in mapView.annotations)
    {
        topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
        topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);

        bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
        bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
    }

    MKCoordinateRegion region;
    region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
    region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides

    region = [aMapView regionThatFits:region];
    [mapView setRegion:region animated:YES];
}

작동하지 않음 : ▿ 2 요소 ▿ 0 ​​: CLLocationCoordinate2D-위도 : 46.969995730376894-경도 : -109.2494943434474 ▿ 1 : CLLocationCoordinate2D-위도 : 63.23212154333072-경도 : 174.13666611126533
Olexiy Pyvovarov 2019 년

23

스위프트 사용

mapView.showAnnotations(annotationArray, animated: true)

목표 c에서

[mapView showAnnotations:annotationArray animated:YES];

2
주석이 이미 mapView에 설정되어 있으면 다음을 참조하여 직접 참조 할 수 있습니다.mapView.showAnnotations(mapView.annotations, animated: true)
Justin Vallely

14

Rafael Moreira의 답변을 변환했습니다. 크레딧은 그에게갑니다. Swift 버전을 찾는 사람들을 위해 다음 코드가 있습니다.

 func zoomToFitMapAnnotations(aMapView: MKMapView) {
    guard aMapView.annotations.count > 0 else {
        return
    }
    var topLeftCoord: CLLocationCoordinate2D = CLLocationCoordinate2D()
    topLeftCoord.latitude = -90
    topLeftCoord.longitude = 180
    var bottomRightCoord: CLLocationCoordinate2D = CLLocationCoordinate2D()
    bottomRightCoord.latitude = 90
    bottomRightCoord.longitude = -180
    for annotation: MKAnnotation in myMap.annotations as! [MKAnnotation]{
        topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude)
        topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude)
        bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude)
        bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude)
    }

    var region: MKCoordinateRegion = MKCoordinateRegion()
    region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5
    region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.4
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.4
    region = aMapView.regionThatFits(region)
    myMap.setRegion(region, animated: true)
}

14

Swift 3지도의 모든 주석에 맞는 올바른 방법입니다.

func zoomMapaFitAnnotations() {

        var zoomRect = MKMapRectNull
        for annotation in mapview.annotations {

            let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)

            let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0)

            if (MKMapRectIsNull(zoomRect)) {
                zoomRect = pointRect
            } else {
                zoomRect = MKMapRectUnion(zoomRect, pointRect)
            }
        }
        self.mapview.setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(50, 50, 50, 50), animated: true)

    }

@ArshadShaik Swift 4.2에 대한 새로운 답변을 제공하려는 경우 제안 된 편집 이 거부되었습니다. 다른 사용자 게시물로 편집하지 말고 자유롭게 답변으로 추가하십시오.
Nick

13

@jowie의 솔루션은 훌륭합니다. 한 번의 캐치,지도에 하나의 주석 만있는 경우 완전히 축소 된 맵으로 끝납니다. setVisibleMapRect가 확대해야 할 것을 확인하기 위해 rect make 크기에 0.1을 추가했습니다.

MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);

12

iOS 8 이상을 찾고 있다면 가장 간단한 방법은 var layoutMargins: UIEdgeInsets { get set }전화하기 전에지도보기 를 설정하는 것 입니다func showAnnotations(annotations: [MKAnnotation], animated: Bool)

예를 들어 (Swift 2.1) :

@IBOutlet weak var map: MKMapView! {
    didSet {
        map.delegate = self
        map.mapType = .Standard
        map.pitchEnabled = false
        map.rotateEnabled = false
        map.scrollEnabled = true
        map.zoomEnabled = true
    }
}

// call 'updateView()' when viewWillAppear or whenever you set the map annotations
func updateView() {
    map.layoutMargins = UIEdgeInsets(top: 25, left: 25, bottom: 25, right: 25)
    map.showAnnotations(map.annotations, animated: true)
}

12

여기저기서 약간의 코드를 사용하여 모든 주석을 신속하게 표시하는 확장을 만들었습니다. 최대 줌 레벨에서도 표시 할 수없는 경우 모든 주석이 표시되지 않습니다.

import MapKit

extension MKMapView {
    func fitAllAnnotations() {
        var zoomRect = MKMapRectNull;
        for annotation in annotations {
            let annotationPoint = MKMapPointForCoordinate(annotation.coordinate)
            let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
            zoomRect = MKMapRectUnion(zoomRect, pointRect);
        }
        setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50), animated: true)
    }
}

UIEdgeInsetsMake매개 변수 를 변경하여 더 나은 결과를 얻을 수 있었고 30에서 100 사이의 값이 좋았습니다. iPhone SE i) S 10.2 Simulator를 사용하여 테스트했습니다. 예제 코드 : setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(100, 100, 100, 100), animated: true). 참고로이 코드는 Swift 3 및 XCode 8.2.1에서 작동합니다.
nyxee 2016 년

8

이 메소드에서 사용자 위치 핀을 제외하기 위해 for 루프 내에이 If 루프를 추가했습니다 (필자의 경우 및 기타)

if (![annotation isKindOfClass:[MKUserLocation class]] ) {

//Code Here...

}

8

iOS 7 이상 (MKMapView.h 참조) :

// Position the map such that the provided array of annotations are all visible to the fullest extent possible.          

- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);

발언 – Abhishek Bedi

당신은 단지 전화 :

 [yourMapView showAnnotations:@[yourAnnotation] animated:YES];

참고로 NS_AVAILABLE 텍스트는 2011 년 1 월에 기기에 iOS 7을 설치하지 않았기 때문에 NS_AVAILABLE 텍스트가 있었으며 NS_AVAILABLE은 빌드 실패 또는 충돌로부터 앱을 보호했습니다.
Matthew Frederick

5

스위프트에서

    var zoomRect = MKMapRectNull;

    for i in 0..<self.map.annotations.count {

        let annotation: MKAnnotation = self.map.annotations[i]

        let annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }

    self.map.setVisibleMapRect(zoomRect, animated: true)

5
    var zoomRect: MKMapRect = MKMapRect.null
    for annotation in mapView.annotations {
        let annotationPoint = MKMapPoint(annotation.coordinate)
        let pointRect = MKMapRect(x: annotationPoint.x, y: annotationPoint.y, width: 0.1, height: 0.1)
        zoomRect = zoomRect.union(pointRect)
    }
    mapView.setVisibleMapRect(zoomRect, animated: true)

// 신속한 5 편집


4

jowie 덕분에 이전 카테고리를보다 우아한 솔루션으로 업데이트했습니다. 완벽하고 거의 복사 및 붙여 넣기 준비된 솔루션 공유

MKMapView + AnnotationsRegion.h

#import <MapKit/MapKit.h>

@interface MKMapView (AnnotationsRegion)

-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated;
-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding;

-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated;
-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding;

@end

MKMapView + AnnotationsRegion.m

#import "MKMapView+AnnotationsRegion.h"

@implementation MKMapView (AnnotationsRegion)

-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated{
    [self updateRegionForCurrentAnnotationsAnimated:animated edgePadding:UIEdgeInsetsZero];
}
-(void)updateRegionForCurrentAnnotationsAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding{
    [self updateRegionForAnnotations:self.annotations animated:animated edgePadding:edgePadding];
}

-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated{
    [self updateRegionForAnnotations:annotations animated:animated edgePadding:UIEdgeInsetsZero];
}
-(void)updateRegionForAnnotations:(NSArray *)annotations animated:(BOOL)animated edgePadding:(UIEdgeInsets)edgePadding{
    MKMapRect zoomRect = MKMapRectNull;
    for(id<MKAnnotation> annotation in annotations){
        MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }
    [self setVisibleMapRect:zoomRect edgePadding:edgePadding animated:animated];
}

@end

그것이 누군가를 돕고 다시 jowie 감사합니다!


4
 - (void)zoomMapViewToFitAnnotationsWithExtraZoomToAdjust:(double)extraZoom
{

    if ([self.annotations count] == 0) return;

   int i = 0;
  MKMapPoint points[[self.annotations count]];

   for (id<MKAnnotation> annotation in [self annotations])
  {
      points[i++] = MKMapPointForCoordinate(annotation.coordinate);
   }

  MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i];

MKCoordinateRegion r = MKCoordinateRegionForMapRect([poly boundingMapRect]);
r.span.latitudeDelta += extraZoom;
r.span.longitudeDelta += extraZoom;

[self setRegion: r animated:YES];

}

4

Abhishek Bedi가 의견에서 지적했듯이 iOS7 앞으로는 가장 좋은 방법은 다음과 같습니다.

//from API docs: 
//- (void)showAnnotations:(NSArray *)annotations animated:(BOOL)animated NS_AVAILABLE(10_9, 7_0);
[self.mapView showAnnotations:self.mapView.annotations animated:YES];

개인 프로젝트 (iOS7 이전)의 경우 MKMapView 클래스에 범주를 추가하여 매우 일반적인 작업을 위해 "표시 영역"기능을 캡슐화했습니다. MKMapView 인스턴스에서 현재로드 된 모든 주석을 볼 수 있도록 설정 ( 여기에는 사용자 위치뿐만 아니라 배치 한 핀 수가 포함됩니다). 결과는 다음과 같습니다.

.h 파일

#import <MapKit/MapKit.h>

@interface MKMapView (Extensions)

-(void)ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:(BOOL)animated;
-(void)ij_setVisibleRectToFitAnnotations:(NSArray *)annotations animated:(BOOL)animated;


@end

.m 파일

#import "MKMapView+Extensions.h"

@implementation MKMapView (Extensions)

/**
 *  Changes the currently visible portion of the map to a region that best fits all the currently loadded annotations on the map, and it optionally animates the change.
 *
 *  @param animated is the change should be perfomed with an animation.
 */
-(void)ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:(BOOL)animated
{
    MKMapView * mapView = self;

    NSArray * annotations = mapView.annotations;

    [self ij_setVisibleRectToFitAnnotations:annotations animated:animated];

}


/**
 *  Changes the currently visible portion of the map to a region that best fits the provided annotations array, and it optionally animates the change.
    All elements from the array must conform to the <MKAnnotation> protocol in order to fetch the coordinates to compute the visible region of the map.
 *
 *  @param annotations an array of elements conforming to the <MKAnnotation> protocol, holding the locations for which the visible portion of the map will be set.
 *  @param animated    wether or not the change should be perfomed with an animation.
 */
-(void)ij_setVisibleRectToFitAnnotations:(NSArray *)annotations animated:(BOOL)animated
{
    MKMapView * mapView = self;

    MKMapRect r = MKMapRectNull;
    for (id<MKAnnotation> a in annotations) {
        ZAssert([a conformsToProtocol:@protocol(MKAnnotation)], @"ERROR: All elements of the array MUST conform to the MKAnnotation protocol. Element (%@) did not fulfill this requirement", a);
        MKMapPoint p = MKMapPointForCoordinate(a.coordinate);
        //MKMapRectUnion performs the union between 2 rects, returning a bigger rect containing both (or just one if the other is null). here we do it for rects without a size (points)
        r = MKMapRectUnion(r, MKMapRectMake(p.x, p.y, 0, 0));
    }

    [mapView setVisibleMapRect:r animated:animated];

}

@end

보시다시피, 지금까지지도의 보이는 영역을 MKMapView 인스턴스에 현재로드 된 모든 주석에 맞는 것으로 설정하는 방법과 객체의 배열로 설정하는 다른 방법을 추가했습니다. 따라서 mapView의 가시 영역을 설정하려면 코드는 다음과 같이 간단합니다.

   //the mapView instance  
    [self.mapView ij_setVisibleRectToFitAllLoadedAnnotationsAnimated:animated]; 

도움이되기를 바랍니다 =)


3

이 페이지의 모든 답변 은지도가 전체 화면을 차지한다고 가정합니다 . 실제로지도 상단에 정보를 제공하는 HUD 디스플레이 (예 : 상단 및 하단에 흩어져있는 버튼)가 있습니다. 따라서 페이지의 알고리즘에 핀이 모두 표시되지만 일부 는 HUD 디스플레이 버튼 아래 에 나타납니다. .

내 솔루션은지도를 확대하여 화면 의 하위 집합주석표시하고 다양한 화면 크기 (예 : 3.5 "대 4.0"등)에서 작동합니다.

// create a UIView placeholder and throw it on top of the original mapview
// position the UIView to fit the maximum area not hidden by the HUD display buttons
// add an *other* mapview in that uiview, 
// get the MKCoordinateRegion that fits the pins from that fake mapview
// kill the fake mapview and set the region of the original map 
// to that MKCoordinateRegion.

여기 코드에서 내가 한 일이 있습니다 (참고 : NSConstraints코드가 다른 화면 크기에서 작동하도록 도우미 메서드와 함께 사용 합니다. 코드를 읽을 수는 있지만 여기에 대한 대답 더 잘 설명합니다. 기본적으로 동일한 워크 플로우입니다.)

// position smallerMap to fit available space
// don't store this map, it will slow down things if we keep it hidden or even in memory
[@[_smallerMapPlaceholder] mapObjectsApplyingBlock:^(UIView *view) {
    [view removeFromSuperview];
    [view setTranslatesAutoresizingMaskIntoConstraints:NO];
    [view setHidden:NO];
    [self.view addSubview:view];
}];

NSDictionary *buttonBindingDict = @{ @"mapPlaceholder": _smallerMapPlaceholder};

NSArray *constraints = [@[@"V:|-225-[mapPlaceholder(>=50)]-176-|",
                          @"|-40-[mapPlaceholder(<=240)]-40-|"
                          ] mapObjectsUsingBlock:^id(NSString *formatString, NSUInteger idx){
                              return [NSLayoutConstraint constraintsWithVisualFormat:formatString options:0 metrics:nil views:buttonBindingDict];
                          }];

[self.view addConstraints:[constraints flattenArray]];
[self.view layoutIfNeeded];

MKMapView *smallerMap = [[MKMapView alloc] initWithFrame:self.smallerMapPlaceholder.frame];
[_smallerMapPlaceholder addSubview:smallerMap];

MKCoordinateRegion regionThatFits = [smallerMap getRegionThatFits:self.mapView.annotations];
[smallerMap removeFromSuperview];
smallerMap = nil;
[_smallerMapPlaceholder setHidden:YES];

[self.mapView setRegion:regionThatFits animated:YES];

다음은 적합한 영역을 얻는 코드입니다.

- (MKCoordinateRegion)getRegionThatFits:(NSArray *)routes {
    MKCoordinateRegion region;
    CLLocationDegrees maxLat = -90.0;
    CLLocationDegrees maxLon = -180.0;
    CLLocationDegrees minLat = 90.0;
    CLLocationDegrees minLon = 180.0;
    for(int idx = 0; idx < routes.count; idx++)
    {
        CLLocation* currentLocation = [routes objectAtIndex:idx];
        if(currentLocation.coordinate.latitude > maxLat)
            maxLat = currentLocation.coordinate.latitude;
        if(currentLocation.coordinate.latitude < minLat)
            minLat = currentLocation.coordinate.latitude;
        if(currentLocation.coordinate.longitude > maxLon)
            maxLon = currentLocation.coordinate.longitude;
        if(currentLocation.coordinate.longitude < minLon)
            minLon = currentLocation.coordinate.longitude;
    }
    region.center.latitude     = (maxLat + minLat) / 2.0;
    region.center.longitude    = (maxLon + minLon) / 2.0;
    region.span.latitudeDelta = 0.01;
    region.span.longitudeDelta = 0.01;

    region.span.latitudeDelta  = ((maxLat - minLat)<0.0)?100.0:(maxLat - minLat);
    region.span.longitudeDelta = ((maxLon - minLon)<0.0)?100.0:(maxLon - minLon);

    MKCoordinateRegion regionThatFits = [self regionThatFits:region];
    return regionThatFits;
}

2

MKMapView 카테고리에 대한 Rafael의 코드를 약간 수정했습니다 .

- (void)zoomToFitMapAnnotations {
    if ([self.annotations count] == 0)
        return;

    CLLocationCoordinate2D topLeftCoord;
    topLeftCoord.latitude = -90;
    topLeftCoord.longitude = 180;

    CLLocationCoordinate2D bottomRightCoord;
    bottomRightCoord.latitude = 90;
    bottomRightCoord.longitude = -180;

    for (id <MKAnnotation> annotation in self.annotations) {
        topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
        topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);

        bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
        bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
    }

    MKCoordinateRegion region;
    region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
    region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides

    [self setRegion:[self regionThatFits:region] animated:YES];
}

2

위의 답변을 기반으로 범용 메소드를 사용하여 모든 주석 및 오버레이에 동시에 맞게 맵을 확대 / 축소 할 수 있습니다.

-(MKMapRect)getZoomingRectOnMap:(MKMapView*)map toFitAllOverlays:(BOOL)overlays andAnnotations:(BOOL)annotations includeUserLocation:(BOOL)userLocation {
    if (!map) {
        return MKMapRectNull;
    }

    NSMutableArray* overlaysAndAnnotationsCoordinateArray = [[NSMutableArray alloc]init];        
    if (overlays) {
        for (id <MKOverlay> overlay in map.overlays) {
            MKMapPoint overlayPoint = MKMapPointForCoordinate(overlay.coordinate);
            NSArray* coordinate = @[[NSNumber numberWithDouble:overlayPoint.x], [NSNumber numberWithDouble:overlayPoint.y]];
            [overlaysAndAnnotationsCoordinateArray addObject:coordinate];
        }
    }

    if (annotations) {
        for (id <MKAnnotation> annotation in map.annotations) {
            MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
            NSArray* coordinate = @[[NSNumber numberWithDouble:annotationPoint.x], [NSNumber numberWithDouble:annotationPoint.y]];
            [overlaysAndAnnotationsCoordinateArray addObject:coordinate];
        }
    }

    MKMapRect zoomRect = MKMapRectNull;
    if (userLocation) {
        MKMapPoint annotationPoint = MKMapPointForCoordinate(map.userLocation.coordinate);
        zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
    }

    for (NSArray* coordinate in overlaysAndAnnotationsCoordinateArray) {
        MKMapRect pointRect = MKMapRectMake([coordinate[0] doubleValue], [coordinate[1] doubleValue], 0.1, 0.1);
        zoomRect = MKMapRectUnion(zoomRect, pointRect);
    }

    return zoomRect;
}

그리고:

MKMapRect mapRect = [self getZoomingRectOnMap:mapView toFitAllOverlays:YES andAnnotations:YES includeUserLocation:NO];
[mapView setVisibleMapRect:mapRect edgePadding:UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0) animated:YES];

1

이것에 대한 관찰 결과를 공유하십시오.

스토리 보드에서 화면에 "유추 된"크기의 xCode> 6을 사용하는 경우 (파일 관리자의 "시뮬레이션 된 메트릭"참조)

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

의는 viewDidLoad지도의 레이아웃은 스토리 보드에서 더 넓은 화면의 크기에 여전히 있기 때문에 4인치와 아이폰에 너무 큰 줌 레벨에서 발생합니다.

당신은 당신의 전화를 이동할 수 있습니다 showAnnotations...viewDidAppear. 그런 다음지도의 크기가 이미 iPhone 4의 작은 화면으로 조정되었습니다.

또는 "시뮬레이트 된 메트릭"아래의 파일 관리자에서 "추론 된"값을 iphone 4 인치로 변경하십시오.


1

주석과 함께 표시 할 모양을 선택할 수 있습니다.

extension MKMapView {
  func setVisibleMapRectToFitAllAnnotations(animated: Bool = true,
                                            shouldIncludeUserAccuracyRange: Bool = true,
                                            shouldIncludeOverlays: Bool = true,
                                            edgePadding: UIEdgeInsets = UIEdgeInsets(top: 35, left: 35, bottom: 35, right: 35)) {
    var mapOverlays = overlays

    if shouldIncludeUserAccuracyRange, let userLocation = userLocation.location {
      let userAccuracyRangeCircle = MKCircle(center: userLocation.coordinate, radius: userLocation.horizontalAccuracy)
      mapOverlays.append(MKOverlayRenderer(overlay: userAccuracyRangeCircle).overlay)
    }

    if shouldIncludeOverlays {
      let annotations = self.annotations.filter { !($0 is MKUserLocation) }
      annotations.forEach { annotation in
        let cirlce = MKCircle(center: annotation.coordinate, radius: 1)
        mapOverlays.append(cirlce)
      }
    }

    let zoomRect = MKMapRect(bounding: mapOverlays)
    setVisibleMapRect(zoomRect, edgePadding: edgePadding, animated: animated)
  }
}

extension MKMapRect {
  init(bounding overlays: [MKOverlay]) {
    self = .null
    overlays.forEach { overlay in
      let rect: MKMapRect = overlay.boundingMapRect
      self = self.union(rect)
    }
  }
}

0

@ "이것이 내 구현의 다른 요인 때문인지 확실하지 않지만 showAnnotations가 수동 구현과 마찬가지로 주석의 확대 / 축소와 밀접한 관련이 없다는 것을 알았습니다. 수동 하나. – Ted Avery 4 월 17 일 0:35 "

나는 같은 문제가 있었지만 showAnnotations를 두 번 시도했지만 (아래와 같이) 어떤 이유로 든 작동했습니다.

[mapView showAnnotations : yourAnnotationArray 애니메이션 : YES]; [mapView showAnnotations : yourAnnotationArray 애니메이션 : YES];


0

iOS 7 호환 방식은 다음을 사용하는 것입니다. showAnnotation모든 주석을 포함하는 사각형을 얻으려면 먼저 호출하십시오 . 그 후 UIEdgeInset핀 높이의 상단 삽입 부를 작성하십시오. 따라서 전체 핀을지도에 표시해야합니다.

[self.mapView showAnnotations:self.mapView.annotations animated:YES];
MKMapRect rect = [self.mapView visibleMapRect];
UIEdgeInsets insets = UIEdgeInsetsMake(pinHeight, 0, 0, 0);
[self.mapView setVisibleMapRect:rect edgePadding:insets animated:YES];

0

이에 따라 코드에 이것을 넣으십시오.

  - (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
    {
    id<MKAnnotation> mp = [annotationView annotation];
        MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate] ,250,250);

       [mv setRegion:region animated:YES];

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.