주석 핀에 맞게 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.