2010-10-29 19 views
0

Je cherche de l'aide pour finir du code sur la définition de la région sur un MKMapView en fonction de l'annotation d'emplacement actuelle et d'une annotation que j'ai définie.Définir la région MKMapView pour la centrer sur deux annotations

Je veux calculer la distance entre les deux et définir le centre entre les deux, puis effectuer un zoom arrière pour les deux sont en vue. Il semble fonctionner correctement dans Simulator pour moi, mais malheureusement le userLocation.coordinate est fixé à Apple HQ. Quand je teste sur un appareil, je vois un comportement bizarre. Souvent, il effectuera un zoom arrière et définira une région appropriée si les deux annotations sont légèrement horizontales sur la même latitude, mais si la distance verticale est plus grande, le zoom n'est pas effectué correctement.

Je code utilisé trouvé here, et édité un peu pour répondre à mes besoins:

CLLocationCoordinate2D southWest = mapView.userLocation.coordinate; 
CLLocationCoordinate2D northEast = southWest; 

southWest.latitude = MIN(southWest.latitude, annotation.coordinate.latitude); 
southWest.longitude = MIN(southWest.longitude, annotation.coordinate.longitude); 

northEast.latitude = MAX(northEast.latitude, annotation.coordinate.latitude); 
northEast.longitude = MAX(northEast.longitude, annotation.coordinate.longitude); 

CLLocation *locSouthWest = [[CLLocation alloc] initWithLatitude:southWest.latitude longitude:southWest.longitude]; 
CLLocation *locNorthEast = [[CLLocation alloc] initWithLatitude:northEast.latitude longitude:northEast.longitude]; 

// This is a diag distance (if you wanted tighter you could do NE-NW or NE-SE) 
CLLocationDistance meters = [locSouthWest distanceFromLocation:locNorthEast]; 

MKCoordinateRegion region; 
region.center.latitude = (southWest.latitude + northEast.latitude)/2.0; 
region.center.longitude = (southWest.longitude + northEast.longitude)/2.0; 
region.span.latitudeDelta = meters/111319.5; 
region.span.longitudeDelta = 0.0; 

MKCoordinateRegion savedRegion = [mapView regionThatFits:region]; 
[mapView setRegion:savedRegion animated:YES]; 

[locSouthWest release]; 
[locNorthEast release]; 

Une chose qui m'a confondu est qu'il dit northEast = southWest ...

Merci d'avance à tous ceux qui qui a obtenu une aide et entrée :)

Répondre

-1

cette annonce de blog peut vous fournir l'aperçu besoin

http://codisllc.com/blog/zoom-mkmapview-to-fit-annotations/

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

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

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

    for(MapAnnotation* 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 = [mapView regionThatFits:region]; 
    [mapView setRegion:region animated:YES]; 
} 
+0

Parfait! Les deltas étaient le problème que je peux voir. Merci beaucoup! – runmad

+1

Malheureusement, cette page ne semble pas répondre. Quelqu'un at-il une version en cache de la page? Merci! – jowie

+0

@jowie J'ai été en mesure de trouver une version en cache de la page en utilisant la machine de retour. J'espère que ça aide. http://web.archive.org/web/20100612181520/http://codisllc.com/blog/zoom-mkmapview-à-fit-annotations – avelis

0

Ne pas avoir peur par les deux premières lignes, vous pouvez ignorer ce qui est juste de = signes, car il sera écrasé ci-dessous ...

Je pense que la question est ici:

region.span.longitudeDelta = 0.0; 
+0

Oui, le lien d'Aaron ci-dessus a les deltas correctement calculés et il semble l'avoir résolu. Juste nécessite un peu de peaufinage de la marge supplémentaire, mais le code est parfait! – runmad

1

pour transmettre la meilleure iOS 7 façon de faire est la suivante:

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

pour mon projet personnel (avant iO S7) J'ai simplement ajouté une catégorie sur la classe MKMapView pour encapsuler la fonctionnalité "zone visible" pour une opération très courante: la configurer pour pouvoir voir toutes les annotations actuellement chargées sur l'instance MKMapView (cela inclut autant de broches que vous aurait pu placer, ainsi que l'emplacement de l'utilisateur). le résultat était le suivant:

.h

#import <MapKit/MapKit.h> 

@interface MKMapView (Extensions) 

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


@end 

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

Comme vous pouvez le voir, je l'ai ajouté 2 méthodes à ce jour: un pour le réglage de la région visible la carte à celle qui correspond à toutes les annotations actuellement chargées sur l'instance MKMapView, et une autre méthode pour la définir sur n'importe quel tableau d'objets. Donc, pour définir la région visible du Mapview le code serait alors aussi simple que:

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

J'espère que cela aide =)