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;
}
fuzzygoat
źródło
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);
Matthew Frederick
źródło
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);
jowie
źródło
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ę

Ryan Berg
źródło
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];
}
Rafael Moreira
źródło
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];
Sreedeepkesav MS
źródło
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)
}
Prashant Khanal
źródło
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)

    }
oscar castellon
źródło
@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);
Micheasz
źródło
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)
}
Henrik Perrochon
źródło
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)
    }
}
Ankit Srivastava
źródło
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...

}
Sammio2
źródło
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];
Seke1412
źródło
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)
Matheus Domingos
źródło
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

alicanbatur
źródło
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!

JakubKnejzlik
źródło
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];

}
Ravi Karadbhajane
źródło
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 =)

Robertibiris
źródło
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;
}
abbood
źródło
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];
}
Kirow
źródło
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];
Alexander Korotkov
źródło
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.

Jens
źródło
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)
    }
  }
}
Anirudha Mahale
źródło
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];

zakton
źródło
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];
Morfeusz78
źródło
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];

}
Abhishek Bedi
źródło