Powiększanie MKMapView w celu dopasowania szpilek do adnotacji?


193

Korzystam z MKMapView i dodałem do mapy szereg pinezek z adnotacjami o obszarze 5-10 kilometrów. Kiedy uruchamiam aplikację, moja mapa zaczyna być pomniejszona, aby pokazać cały świat, jaki jest najlepszy sposób na powiększenie mapy, aby szpilki pasowały do ​​widoku?

EDYCJA: Moje początkowe myślenie byłoby użyć MKCoordinateRegionMake i obliczyć współrzędne współrzędnych, długość geograficzną i szerokość geograficzną z moich adnotacji. Jestem pewien, że to zadziała, ale chciałem tylko sprawdzić, czy nie umknęło mi nic oczywistego.

Dodano kod, BTW: FGLocation jest klasą zgodną MKAnnotation, lokalizacjaFake jest jednym NSMutableArrayz tych obiektów. Komentarze są zawsze mile widziane ....

- (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
Uwaga dotycząca systemu iOS 7: nowa metoda showAnnotations: animated: może pomóc uniknąć ręcznego obliczania regionu.

Odpowiedzi:


123

Masz rację.

Znajdź swoje maksymalne i minimalne szerokości i długości geograficzne, zastosuj prostą arytmetykę i użyj MKCoordinateRegionMake.

Dla iOS 7 i powyżej, zastosowania showAnnotations:animated:, od 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
W systemie iOS 7 i nowszym (Odnośnik 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

1
Działa to dobrze, ale czasami powiększam (na mapie), a następnie próbuję wyśrodkować (używając przycisku wywołującego tę metodę), nie działa.
RPM

5
Ważne jest, aby pamiętać, że showAnnotationsdodaje także adnotacje do mapy, nawet jeśli adnotacja dla tej lokalizacji już istnieje.
Eneko Alonso

@EnekoAlonso Możesz obejść ten problem, dzwoniąc removeAnnotations(_ annotations:)natychmiast poshowAnnotations(_ annotations:animated)
Alain Stulz

1
Warto również zauważyć, że chociaż showAnnotations ustawia region na wyświetlanie adnotacji, region wciąż dostosowuje się do proporcji; i to często wyklucza niektóre adnotacje. Zauważ też, że showAnnotations jest jedynym poprawnym rozwiązaniem przedstawionym tutaj; żadna z pozostałych odpowiedzi nie próbuje nawet obsługiwać adnotacji obejmujących międzynarodową linię daty.
Gordon Dove,

335

To tutaj znalazłem , który działał dla mnie:

(EDYCJA: Zaktualizowałem rozwiązanie, używając sugestii @ Micah, aby zwiększyć pointRect o 0,1, aby upewnić się, że odbyt nie będzie nieskończenie mały!)

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];

 

Możesz również zaktualizować to, aby zawierało pin użytkownika UserLocation, zastępując pierwszy wiersz:

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

4
Rzeczywiście miło. Nie musisz jednak sprawdzać, czy isLull. MKMapRectUnion robi to za Ciebie. Z dokumentacji: „Jeśli którykolwiek prostokąt ma wartość null, ta metoda zwraca drugi prostokąt”.
Felix Lamouroux

37
Bardzo fajne rozwiązanie !!! Oto dodatkowy drobiazg, aby dodać padding: double inset = -zoomRect.size.width * 0.1; [self.mapView setVisibleMapRect: MKMapRectInset (zoomRect, wstawka, wstawka) animowane: TAK];
Craig B,

1
Niesamowite! Potencjalne dodanie: jeśli chcesz wykluczyć „bieżącą adnotację o lokalizacji”, po prostu dodaj instrukcję if w pętli for: if (! [Adnotacja toKindOfClass: [MKUserLocation class]]) {// Zrób rzeczy tutaj}
kgaidis

2
Rozwiązanie @CraigB dla wypełniania jest doskonałe, ale nie działa dobrze, gdy ścieżka jest pionowa, np. Ruch z południa na północ, aby to naprawić, użyj podwójnej wstawki = MIN (-zoomRect.size.width * 0.1, -zoomRect.size. wysokość * 0,1);
Farhad Malekpour

1
Ulepszenie dzięki wypełnieniu: podwójna wstawka Szerokość = -zoomRect.size.width * 0,2; double insetHeight = -zoomRect.size.height * 0.2; MKMapRect insetRect = MKMapRectInset (zoomRect, insetWidth, insetHeight); Następnie użyj tego nowego insertRect
dulgan

121

Apple dodał nową metodę dla IOS 7, aby nieco uprościć życie.

[mapView showAnnotations:yourAnnotationArray animated:YES];

Możesz łatwo pobrać z tablicy zapisanej w widoku mapy:

yourAnnotationArray = mapView.annotations;

i szybko dostosuj też aparat!

mapView.camera.altitude *= 1.4;

to nie zadziała, chyba że użytkownik ma zainstalowany system iOS 7+ lub OS X 10.9+. sprawdź tutaj niestandardową animację


Nie jestem pewien, czy showAnnotationsdzieje się tak z powodu innych czynników w mojej implementacji, ale uważam, że nie robi to tak blisko powiększenia / dopasowania adnotacji, jak w przypadku implementacji ręcznej, więc utknąłem z instrukcją ręczną.
Ted Avery

1
spróbuj pomnożyć wysokość kamery przez ułamek jednego, na przykład mapView.camera.altitude * = .85; dla bliższego widoku
Ryan Berg

Uznałem to również za przydatne do wybierania adnotacji poza bieżącym widocznym obszarem mapy. Domyślnie MapView nie wybiera niewidocznych adnotacji. Wywołaj showAnnotations z tablicą niewidocznych adnotacji przed wywołaniem selectAnnotation, a mapa powinna zaktualizować swój widoczny obszar.
MandisaW,

42

Używam tego kodu i działa dobrze dla mnie:

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

Nie pracuj dla: ▿ 2 elementów ▿ 0: CLLocationCoordinate2D - szerokość: +46,969995730376894 - Długość: -109,2494943434474 ▿ 1: CLLocationCoordinate2D - szerokość: +63,23212154333072 - Długość: +174,13666611126533
Olexiy Pyvovarov

23

W szybkim użyciu

mapView.showAnnotations(annotationArray, animated: true)

W Celu c

[mapView showAnnotations:annotationArray animated:YES];

2
Jeśli adnotacje zostały już ustawione na mapView, możesz odwoływać się do nich bezpośrednio za pomocą:mapView.showAnnotations(mapView.annotations, animated: true)
Justin Vallely,

14

Przekształciłem odpowiedź Rafaela Moreiry. Kredyt należy do niego. Dla tych, którzy szukają wersji Swift, oto kod:

 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 To jest poprawny sposób na dopasowanie wszystkich adnotacji na mapie.

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 Sugerowana edycja została odrzucona, jeśli chcesz podać nową odpowiedź dla Swift 4.2, nie krępuj się, ale dodaj ją jako odpowiedź, nie edytując jej w poście innego użytkownika.
Nick

13

Rozwiązanie @ jowie działa świetnie. Jeden haczyk, jeśli mapa ma tylko jedną adnotację, otrzymasz w pełni pomniejszoną mapę. Dodałem 0,1 do rozmiaru prostokąta, aby upewnić się, że setVisibleMapRect ma coś do powiększenia.

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

12

Jeśli szukasz systemu iOS 8 lub nowszego , najprostszym sposobem jest ustawienie var layoutMargins: UIEdgeInsets { get set }widoku mapy przed zadzwonieniemfunc showAnnotations(annotations: [MKAnnotation], animated: Bool)

Na przykład (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

Utworzyłem rozszerzenie, aby szybko wyświetlać wszystkie adnotacje za pomocą kodu od czasu do czasu. Nie będą wyświetlane wszystkie adnotacje, jeśli nie będą mogły zostać wyświetlone nawet przy maksymalnym powiększeniu.

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)
    }
}

Udało mi się uzyskać lepsze wyniki, zmieniając UIEdgeInsetsMakeparametry, wartości od 30 do 100 były dla mnie dobre. Testowałem przy użyciu iPhone'a SE i) S 10.2 Simulator. Przykład Kod: setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(100, 100, 100, 100), animated: true). Uwaga: ten kod działa w Swift 3 i XCode 8.2.1.
nyxee

8

Dodano tę pętlę If w pętli for, aby wykluczyć pin lokalizacji użytkownika z tej metody (wymagane w moim przypadku i być może inne)

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

//Code Here...

}

8

W systemie iOS 7 i nowszym (Refering 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);

uwaga od - Abhishek Bedi

Po prostu dzwonisz:

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

Dla porównania, tekst NS_AVAILABLE był tam, ponieważ w styczniu 2011 r. Posiadanie iOS 7 na urządzeniu nie było zbyt prawdopodobne, a NS_AVAILABLE chronił aplikację przed niepowodzeniem lub awarią kompilacji.
Matthew Frederick

5

W Swift

    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)

// Edytowano dla szybkiego 5


4

Dzięki jowie zaktualizowałem moją starą kategorię do bardziej eleganckiego rozwiązania. Udostępnianie kompletne, prawie gotowe do skopiowania i wklejenia rozwiązanie

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

Mam nadzieję, że to komuś pomoże i jeszcze raz dziękuję 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

Jak zauważa Abhishek Bedi w komentarzu, najlepszym sposobem na iOS7 jest:

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

W moim osobistym projekcie (wcześniejszym niż iOS7) po prostu dodałem kategorię do klasy MKMapView, aby zawrzeć funkcję „widocznego obszaru” dla bardzo częstej operacji: ustawianie, aby była w stanie zobaczyć wszystkie aktualnie załadowane adnotacje w instancji MKMapView ( obejmuje to tyle pinów, ile mogłeś umieścić, a także lokalizację użytkownika). wynik był następujący:

plik .h

#import <MapKit/MapKit.h>

@interface MKMapView (Extensions)

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


@end

plik .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

Jak widać, do tej pory dodałem 2 metody: jedną do ustawiania widocznego regionu mapy na tę, która pasuje do wszystkich aktualnie załadowanych adnotacji w instancji MKMapView, oraz drugą metodę ustawiania jej na dowolną tablicę obiektów. Aby ustawić widoczny region mapView, kod byłby wtedy tak prosty jak:

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

Mam nadzieję, że to pomoże =)


3

Wszystkie odpowiedzi na tej stronie zakładają, że mapa zajmuje pełny ekran . Właściwie mam wyświetlacz HUD (tj. Przyciski rozrzucone u góry i na dole), które podają informacje na górze mapy .. i dlatego algorytmy na stronie będą wyświetlały pinezki w porządku, ale niektóre z nich pojawią się pod przyciskami wyświetlacza HUD .

Moje rozwiązanie powiększa mapę, aby wyświetlać adnotacje w podzestawie ekranu i działa dla różnych rozmiarów ekranu (tj. 3,5 "vs 4,0" itp.):

// 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.

Oto, co zrobiłem w kodzie (uwaga: używam NSConstraintsz niektórymi metodami pomocniczymi, aby mój kod działał w różnych rozmiarach ekranu .. podczas gdy kod jest dość czytelny .. moja odpowiedź tutaj wyjaśnia to lepiej .. to w zasadzie ten sam przepływ pracy :)

// 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];

oto kod, który pobiera region, który pasuje:

- (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

Dokonałem niewielkiej modyfikacji kodu Rafaela dla kategorii MKMapView.

- (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

W oparciu o powyższe odpowiedzi można użyć uniwersalnej metody powiększania mapy w celu dopasowania wszystkich adnotacji i nakładek jednocześnie.

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

I wtedy:

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

Po prostu dzielę się swoimi spostrzeżeniami na ten temat:

Jeśli używasz xCode> 6 z „wnioskowanymi” rozmiarami ekranów (patrz „symulowane metryki” w inspektorze plików) w serii ujęć, wywoływanie

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

w viewDidLoadspowoduje zbyt dużego poziomu powiększenia na iPhone z 4 cali ponieważ układ na mapie jest jeszcze od wielkości szerszych ekranach z serii ujęć.

Możesz przenieść swoje połączenie showAnnotations...do viewDidAppear. Następnie rozmiar mapy został już dostosowany do mniejszego ekranu iPhone'a 4.

Lub alternatywnie zmień wartość „wywnioskowaną” w inspektorze plików w obszarze „Symulowane metryki” na iPhone 4-calowy.


1

Możesz wybrać kształty, które chcesz pokazać wraz z adnotacjami.

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

@ „Nie jestem pewien, czy dzieje się tak z powodu innych czynników w mojej implementacji, ale uważam, że showAnnotations nie robi tak ścisłego powiększenia / dopasowania adnotacji, jak robi to ręczna implementacja, więc utknąłem manual one. - Ted Avery 17 kwietnia o 0:35 "

Miałem ten sam problem, ale potem dwukrotnie spróbowałem zrobić showAnnotations (jak poniżej) iz jakiegoś powodu zadziałało.

[mapView showAnnotations: yourAnnotationArray animated: YES]; [mapView showAnnotations: yourAnnotationArray animated: YES];


0

Sposobem zgodnym z iOS 7 jest użycie następujących. Pierwsze połączenie showAnnotationw celu uzyskania prostokąta zawierającego wszystkie adnotacje. Następnie utwórz UIEdgeInsetz górną wstawką wysokości sworznia. W ten sposób zapewniasz pokazanie całej pinezki na mapie.

[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

Wprowadź to odpowiednio do swojego kodu:

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

       [mv setRegion:region animated:YES];

}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.