2013-02-16 10 views
9

Wyświetlam MKMapView wewnątrz nagłówka widoku paralaksy w stylu ścieżki. Aby utworzyć efekt, granice mapView są większe niż obszar widoczny dla użytkownika. Muszę ustawić region widoku mapy tak, aby wszystkie adnotacje mapy były zawarte w widocznym prostokącie MKMapView. Jaki jest najlepszy sposób na zrobienie tego?Wyświetl MKMapViewAnnotations w widocznym widoku mapy

MKMapView with limited visible area

Edycja dla jasności: Oto use-case. Rozmiar mapView wynosi 320 x 380. Widoczny obszar jest jednak określony przez rect (0.0, 20.0, 320.0, 100.0). Muszę ustawić region tak, aby wszystkie adnotacje pojawiały się w tym prostokącie w mapView.

Odpowiedz

15

Ustawianie region mapy tak, że wszystkie adnotacje zawarte są w pewnej części z MKMapView może odbywać się w trzech etapach. Dane wejściowe to mapView i annotationsFrame.

  1. Obliczyć MKMapRectmapRect zawierający wszystkie adnotacje.
  2. Obliczyć wstawki wypełnienia z mapView.bounds i annotationsFrame.
  3. Zadzwoń pod -setVisibleMapRect:edgePadding:animated: w widoku mapy.

Poniżej znajduje się zrzut ekranu testu. Czerwona nakładka pokazuje annotationsFrame.

screen Shot of a test showing that all annotations are inside the given annotation frame

Oto kod. Strzeż się: Wszystko w jednym sposobie, aby uprościć dodawanie go do kodu, a nie jest testowany pod kątem przypadków brzegowych, jak przekazywanie adnotacji o tej samej współrzędnej lub rozbieżności między adnotacjami, które mapa musiałaby zbyt duże pomniejszanie lub współrzędne, które rozciągają się wzdłuż krawędzi mapy o długości +/- 180 stopni.

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


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

    NSArray *annotations = _mapView.annotations; 

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

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

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


    // Step 2: Calculate the edge padding 

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


    // Step 3: Set the map rect 

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

Jeśli pójdziesz do idealnego umieszczenia (a kto nie), tutaj są trzy rzeczy do rozważenia:

  1. Kod zapewnia, że ​​wszystkie współrzędne są w annotationsFrame, ale adnotacje same mogą być na zewnątrz. Aby temu zapobiec, po prostu użyj więcej wypełnienia. Na przykład, jeśli twoje adnotacje mają wymiary 20 x 20 i są wyśrodkowane na współrzędnych, użyj 10 dodatkowych wypełnień ze wszystkich stron.
  2. Poniżej iOS 7 mapa nie powiększała się do idealnej skali powiększenia, ale do następnego rozmiaru kafelka (potęga dwóch). Będzie więc więcej miejsca wokół adnotacji niż potrzeba, tak jak pokazano na zrzucie ekranu.
  3. W systemie iOS 7 widok mapy nie tylko perfekcyjnie powiększa, ale także automatycznie dba o pasek stanu. Aby obliczenia były prawidłowe, należy odjąć wysokość paska stanu od górnej krawędzi na iOS 7.
-1

Spróbuj uzyskać ze wszystkich wartości krawędzi opisu (max i min) dla lan i lon.

określania tej wartości na początku:

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

a następnie użyć tej funkcji, aby obliczyć rozpiętość i regionie:

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

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

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

i używać go w sposób viewDidLoad:

-(void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    [self zoomAndFit]; 
} 
+0

Ten kod pasuje do wszystkich adnotacji w granicach mapView, ale potrzebuję pasować do wszystkich adnotacji w danym CGRect w granicach mapView. – user2393462435

+1

@ user2393462435 Nie jest dokładnie to, co dokładnie próbujesz powiedzieć ... Przeczytaj to sam i jasno powiedz, o co prosisz. –

+1

@ R.A rozmiar mapView wynosi 320 x 380. Ustaw region widoku mapy tak, aby wszystkie adnotacje znajdowały się w obszarze rect (0.0, 20.0, 320.0, 100.0).to jest to! – user2393462435

0

Jeśli jesteś gotowy do przybliżenia obliczeń, możesz to zrobić za pomocą sprytnego skalowania.

Twój obszar docelowy ma 80 wysokości poza mapView, który wynosi 380. Dlatego chcesz mieć region, który jest 4.75 razy wyższy niż obszar obliczony w celu dopasowania do adnotacji. (0,25 dodatkowe powyżej i 3,5 dodatkowe poniżej).

Najpierw musisz zdobyć region (lub maprect, w dowolnym miejscu, w którym wolisz pracować) i uczynić go takim samym jak Twój docelowy obszar wyświetlania. Jest tak dlatego, że naprawdę szeroki i krótki region nie dotykałby górnej i dolnej części widocznego obszaru, a zatem pomnożenie jego wysokości nie powodowałoby czegoś, co dotknęłoby górnej i dolnej części widoku mapy. Więc jeśli viewable_height/viewable_width > annotations_height/annotations_width powinieneś ustawić annotations_height na annotations_width * (viewable_height/viewable_width).

Dzięki temu możesz dodać 25% na północ od pola adnotacji, a 350% na południe. Możesz to zrobić, przesuwając centrum o 212,5% (aktualnej wysokości) na południe i zwiększając pionowy zakres o 475%.

Wszystko to jest przybliżeniem, ponieważ świat jest kulą i nie patrzymy na rzut płaski (tj. 1 stopień szerokości geograficznej w pobliżu równika jest narysowany mniej niż 1 stopień w pobliżu biegunów). Ale jeśli chcesz być dokładnym, możesz spojrzeć na skalowanie liczb według szerokości geograficznej i takich. Jeśli masz do czynienia tylko z adnotacjami w skali wielkości miasta, prawdopodobnie wszystko będzie dobrze.

Nadzieję, że pomaga.

0

jeśli chcesz znaleźć adnotacje, które są w danym rect:

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

    return annotationsInRect; 
} 

i zapewnić adnotacji Widoki są w rect, uzyskać region dla adnotacji, następnie przejść przez nich i dostać granice każdego widoku sprawdzają, czy granice mieszczą się w polu visibleRect mapy, a jeśli nie, zmodyfikuj region!

~~ tak:

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

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

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

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

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

     MKCoordinateRegion neededRegion = [self.mapView convertRect:neededRect toRegionFromView:self.mapView]; 
     _ignoreRegionChange = YES; 
     [self.mapView setRegion:originalRegion animated:NO]; 
     _ignoreRegionChange = NO; 
     [self.mapView setRegion:neededRegion animated:YES]; 
    } 
    else { 
     MKCoordinateRegion currentRegion = self.mapView.region; 
     _ignoreRegionChange = YES; 
     [self.mapView setRegion:originalRegion animated:NO]; 
     _ignoreRegionChange = NO; 
     [self.mapView setRegion:currentRegion animated:YES]; 
    } 
} 
+1

gdzie wszystkie adnotacje w NSArray z adnotacjami, które masz (na mapie lub nie) –

+0

Jaka jest wartość MAXFLOAT? –

+0

Nie wiem. jest to określona wartość specyficzna dla platformy/łuku/os. Powiedzmy, że jest to ~ 32000 –

3

Począwszy od wersji iOS 7.0, można to łatwo osiągnąć za pomocą showAnnotations.

Swift:

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

Objective-C:

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

Powyższe stwierdzenie będzie dostosowanie widoku mapy widoczna rect, aby wyświetlić wszystkie adnotacje.

+0

Nie istnieje żadna metoda dla MKMapView ... –

+0

@ kishan94 Czy używasz Swift lub Objective-C? – Andree

+0

Używam Objective C ... –

Powiązane problemy