定位MKMapView一次显示多个注释

我有几个注释,我想添加到我的MKMapView(它可以0-n项目,其中n通常是5左右)。 我可以添加注释很好,但我想要调整地图以适应屏幕上的所有注释,我不知道如何做到这一点。

我一直在看-regionThatFits:但我不太确定该怎么做。 我会张贴一些代码来显示我到目前为止。 我认为这应该是一个简单的任务,但是到目前为止,我对MapKit感到有点不知所措。

 - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{ location = newLocation.coordinate; //One location is obtained.. just zoom to that location MKCoordinateRegion region; region.center = location; //Set Zoom level using Span MKCoordinateSpan span; span.latitudeDelta = 0.015; span.longitudeDelta = 0.015; region.span = span; // Set the region here... but I want this to be a dynamic size // Obviously this should be set after I've added my annotations [mapView setRegion:region animated:YES]; // Test data, using these as annotations for now NSArray *arr = [NSArray arrayWithObjects:@"one", @"two", @"three", @"four", nil]; float ex = 0.01; for (NSString *s in arr) { JBAnnotation *placemark = [[JBAnnotation alloc] initWithLat:(location.latitude + ex) lon:location.longitude]; [mapView addAnnotation:placemark]; ex = ex + 0.005; } // What do I do here? [mapView setRegion:[mapView regionThatFits:region] animated:YES]; } 

注意,这一切都发生在我收到位置更新时…我不知道这是否是一个合适的位置来执行此操作。 如果不是,哪里会更好? -viewDidLoad

提前致谢。

从iOS7开始,你可以使用showAnnotations:animated:

 [mapView showAnnotations:annotations animated:YES]; 

Jim发布的链接现在已经死了,但是我能够find代码(我已经在某处添加了书签)。 希望这可以帮助。

 - (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(id<MKAnnotation> 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; // Add a little extra space on the sides region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; region = [mapView regionThatFits:region]; [mapView setRegion:region animated:YES]; } 

为什么这么复杂?

 MKCoordinateRegion coordinateRegionForCoordinates(CLLocationCoordinate2D *coords, NSUInteger coordCount) { MKMapRect r = MKMapRectNull; for (NSUInteger i=0; i < coordCount; ++i) { MKMapPoint p = MKMapPointForCoordinate(coords[i]); r = MKMapRectUnion(r, MKMapRectMake(px, py, 0, 0)); } return MKCoordinateRegionForMapRect(r); } 

我已经做了类似的事情,以缩小(或在)到一个地区,包括点注释和当前的位置。 你可以通过循环你的注释来扩展这个。

基本步骤是:

  • 计算最低纬度/长度
  • 计算最大经纬度
  • 为这两点创buildCLLocation对象
  • 计算点之间的距离
  • 使用转换为度数的点和距离之间的中心点创build区域
  • 将区域传递到MapView进行调整
  • 使用调整的区域来设置MapView区域
  -(IBAction)zoomOut:(id)sender { CLLocationCoordinate2D southWest = _newLocation.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 getDistanceFrom: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; _savedRegion = [_mapView regionThatFits:region]; [_mapView setRegion:_savedRegion animated:YES]; [locSouthWest release]; [locNorthEast release]; } 

我有一个不同的答案。 我本人将会自己实现zoom-to-fitalgorithm,但是我认为苹果公司必须有一种方法来做我们想要的东西,而不需要太多的工作。 使用API​​ doco快速显示,我可以使用MKPolygon来做需要的事情:

 /* this simply adds a single pin and zooms in on it nicely */ - (void) zoomToAnnotation:(MapAnnotation*)annotation { MKCoordinateSpan span = {0.027, 0.027}; MKCoordinateRegion region = {[annotation coordinate], span}; [mapView setRegion:region animated:YES]; } /* This returns a rectangle bounding all of the pins within the supplied array */ - (MKMapRect) getMapRectUsingAnnotations:(NSArray*)theAnnotations { MKMapPoint points[[theAnnotations count]]; for (int i = 0; i < [theAnnotations count]; i++) { MapAnnotation *annotation = [theAnnotations objectAtIndex:i]; points[i] = MKMapPointForCoordinate(annotation.coordinate); } MKPolygon *poly = [MKPolygon polygonWithPoints:points count:[theAnnotations count]]; return [poly boundingMapRect]; } /* this adds the provided annotation to the mapview object, zooming as appropriate */ - (void) addMapAnnotationToMapView:(MapAnnotation*)annotation { if ([annotations count] == 1) { // If there is only one annotation then zoom into it. [self zoomToAnnotation:annotation]; } else { // If there are several, then the default behaviour is to show all of them // MKCoordinateRegion region = MKCoordinateRegionForMapRect([self getMapRectUsingAnnotations:annotations]); if (region.span.latitudeDelta < 0.027) { region.span.latitudeDelta = 0.027; } if (region.span.longitudeDelta < 0.027) { region.span.longitudeDelta = 0.027; } [mapView setRegion:region]; } [mapView addAnnotation:annotation]; [mapView selectAnnotation:annotation animated:YES]; } 

希望这可以帮助。

你也可以这样做..

 // Position the map so that all overlays and annotations are visible on screen. MKMapRect regionToDisplay = [self mapRectForAnnotations:annotationsToDisplay]; if (!MKMapRectIsNull(regionToDisplay)) myMapView.visibleMapRect = regionToDisplay; - (MKMapRect) mapRectForAnnotations:(NSArray*)annotationsArray { MKMapRect mapRect = MKMapRectNull; //annotations is an array with all the annotations I want to display on the map for (id<MKAnnotation> annotation in annotations) { MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate); MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0); if (MKMapRectIsNull(mapRect)) { mapRect = pointRect; } else { mapRect = MKMapRectUnion(mapRect, pointRect); } } return mapRect; } 

根据每个人的信息和build议,我提出了以下几点。 感谢大家在这个讨论的贡献:)这将在包含mapView的视图控制器去。

 - (void)zoomToFitMapAnnotations { if ([self.mapView.annotations count] == 0) return; int i = 0; MKMapPoint points[[self.mapView.annotations count]]; //build array of annotation points for (id<MKAnnotation> annotation in [self.mapView annotations]) points[i++] = MKMapPointForCoordinate(annotation.coordinate); MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i]; [self.mapView setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect]) animated:YES]; } 

就我而言,我从CLLocation对象开始,为每个对象创build注释。
我只需要放置两个注解,所以我有一个简单的方法来构build点的数组,但是可以很容易地扩展为给定一组CLLocations来构build任意长度的数组。

这是我的实现(不需要创buildMKMapPoints):

 //start with a couple of locations CLLocation *storeLocation = store.address.location.clLocation; CLLocation *userLocation = [LBLocationController sharedController].currentLocation; //build an array of points however you want CLLocationCoordinate2D points[2] = {storeLocation.coordinate, userLocation.coordinate}; //the magic part MKPolygon *poly = [MKPolygon polygonWithCoordinates:points count:2]; [self.mapView setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect])]; 

以下是穆斯塔法回答的SWIFT等价物(确认在:Xcode6.1,SDK 8.2):

  func zoomToFitMapAnnotations() { if self.annotations.count == 0 {return} var topLeftCoordinate = CLLocationCoordinate2D(latitude: -90, longitude: 180) var bottomRightCoordinate = CLLocationCoordinate2D(latitude: 90, longitude: -180) var i = 1 for object in self.annotations { if let annotation = object as? MKAnnotation { topLeftCoordinate.longitude = fmin(topLeftCoordinate.longitude, annotation.coordinate.longitude) topLeftCoordinate.latitude = fmin(topLeftCoordinate.latitude, annotation.coordinate.latitude) bottomRightCoordinate.longitude = fmin(bottomRightCoordinate.longitude, annotation.coordinate.longitude) bottomRightCoordinate.latitude = fmin(bottomRightCoordinate.latitude, annotation.coordinate.latitude) } } var center = CLLocationCoordinate2D(latitude: topLeftCoordinate.latitude - (topLeftCoordinate.latitude - bottomRightCoordinate.latitude) * 0.5, longitude: topLeftCoordinate.longitude - (topLeftCoordinate.longitude - bottomRightCoordinate.longitude) * 0.5) print("\ncenter:\(center.latitude) \(center.longitude)") // Add a little extra space on the sides var span = MKCoordinateSpanMake(fabs(topLeftCoordinate.latitude - bottomRightCoordinate.latitude) * 1.01, fabs(bottomRightCoordinate.longitude - topLeftCoordinate.longitude) * 1.01) print("\nspan:\(span.latitudeDelta) \(span.longitudeDelta)") var region = MKCoordinateRegion(center: center, span: span) region = self.regionThatFits(region) self.setRegion(region, animated: true) } 

您可以使用iOS 7中的“MKMapView”中的新方法

宣言

迅速

 func showAnnotations(_ annotations: [AnyObject]!, animated animated: Bool) 

Objective-C的

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

参数

注释您希望在地图中可见的注释。 如果您希望地图区域更改为animation,则为“是”;如果您希望地图立即显示新区域而不显示animation,则为“否”。

讨论

调用此方法会更新region属性中的值以及潜在的其他属性以反映新的地图区域。

使用Swift,一个多边形和一些额外的填充我使用以下内容:

 func zoomToFit() { var allLocations:[CLLocationCoordinate2D] = [ CLLocationCoordinate2D(latitude: 32.768805, longitude: -117.167119), CLLocationCoordinate2D(latitude: 32.770480, longitude: -117.148385), CLLocationCoordinate2D(latitude: 32.869675, longitude: -117.212929) ] var poly:MKPolygon = MKPolygon(coordinates: &allLocations, count: allLocations.count) self.mapView.setVisibleMapRect(poly.boundingMapRect, edgePadding: UIEdgeInsetsMake(40.0, 40.0, 40.0, 40.0), animated: false) } 

一种可能的解决scheme可能是测量当前位置与所有注释之间的距离,并使用MKCoordinateRegionMakeWithDistance方法来创build比最远注释略大的区域。

这当然会越慢越注释,虽然你添加。

 - (void)zoomToFitMapAnnotations { if ([self.mapview.annotations count] == 0) return; int i = 0; MKMapPoint points[[self.mapview.annotations count]]; //build array of annotation points for (id<MKAnnotation> annotation in [self.mapview annotations]) points[i++] = MKMapPointForCoordinate(annotation.coordinate); MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i]; [self.mapview setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect]) animated:YES]; } 

基于me2 (现在在Swift中)的出色答案,

 func coordinateRegionForCoordinates(coords: [CLLocationCoordinate2D]) -> MKCoordinateRegion { var rect: MKMapRect = MKMapRectNull for coord in coords { let point: MKMapPoint = MKMapPointForCoordinate(coord) rect = MKMapRectUnion(rect, MKMapRectMake(point.x, point.y, 0, 0)) } return MKCoordinateRegionForMapRect(rect) } 

添加了一点if子句来处理1个位置 – 添加到mustufa的cound代码片段。 使用pkclSoft的zoomToAnnotation函数:

 if ([mapView.annotations count] == 1){ MKCoordinateSpan span = {0.027, 0.027}; region.span = span; CLLocationCoordinate2D singleCoordinate = [[mapView.annotations objectAtIndex:0] coordinate]; region.center.latitude = singleCoordinate.latitude; region.center.longitude = singleCoordinate.longitude; } else { // mustufa's code } 

我知道这是一个古老的问题,但是,如果你想显示所有的注释已经在地图上使用这个:

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

我希望这至less是相关的,这是我为Mono(基于pkclSoft的答案)放在一起:

 void ZoomMap (MKMapView map) { var annotations = map.Annotations; if (annotations == null || annotations.Length == 0) return; var points = annotations.OfType<MapAnnotation> () .Select (s => MKMapPoint.FromCoordinate (s.Coordinate)) .ToArray (); map.SetVisibleMapRect(MKPolygon.FromPoints (points).BoundingMapRect, true); } 
 CLLocationCoordinate2D min = CLLocationCoordinate2DMake(99999.0, 99999.0); CLLocationCoordinate2D max = CLLocationCoordinate2DMake(-99999.0, -99999.0); // find max/min.... // zoom to cover area // TODO: Maybe better using a MKPolygon which can calculate its own fitting region. CLLocationCoordinate2D center = CLLocationCoordinate2DMake((max.latitude + min.latitude) / 2.0, (max.longitude + min.longitude) / 2.0); MKCoordinateSpan span = MKCoordinateSpanMake(max.latitude - min.latitude, max.longitude - min.longitude); MKCoordinateRegion region = MKCoordinateRegionMake(center, span); [_mapView setRegion:[_mapView regionThatFits:region] animated:YES]; 

基于me2响应,我为MKMapView添加了一些边界,并跳过用户位置注释:

 @interface MKMapView (ZoomToFitAnnotations) - (void)zoomToFitAnnotations:(BOOL)animated; @end @implementation MKMapView (ZoomToFitAnnotations) - (void)zoomToFitAnnotations:(BOOL)animated { if (self.annotations.count == 0) return; MKMapRect rect = MKMapRectNull; for (id<MKAnnotation> annotation in self.annotations) { if ([annotation isKindOfClass:[MKUserLocation class]] == false) { MKMapPoint point = MKMapPointForCoordinate(annotation.coordinate); rect = MKMapRectUnion(rect, MKMapRectMake(point.x, point.y, 0, 0)); } } MKCoordinateRegion region = MKCoordinateRegionForMapRect(rect); region.span.longitudeDelta *= 2; // Margin region.span.latitudeDelta *= 2; // Margin [self setRegion:region animated:animated]; } @end 

由于我不能评论答案,所以我想给@ me2的答案增加一点便利(因为我认为这是在这里find的最优雅的方法)。

对于我的个人项目,我简单地在MKMapView类中添加了一个类别,以封装常见操作的“可见区域”function:设置为能够查看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(px, py, 0, 0)); } [mapView setVisibleMapRect:r animated:animated]; } @end 

正如你所看到的,到目前为止,我已经添加了2个方法:一个用于将映射的可见区域设置为适合MKMapView实例上所有当前加载的批注的可见区域,另一个将其设置为任何对象数组。 因此,要设置mapView的可见区域,代码将如下所示:

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

我希望它有助于=)

这个代码适用于我,它显示所有与当前位置的引脚,希望这可以帮助你,

 func setCenterForMap() { var mapRect: MKMapRect = MKMapRectNull for loc in mapView.annotations { let point: MKMapPoint = MKMapPointForCoordinate(loc.coordinate) print( "location is : \(loc.coordinate)"); mapRect = MKMapRectUnion(mapRect, MKMapRectMake(point.x,point.y,0,0)) } if (locationManager.location != nil) { let point: MKMapPoint = MKMapPointForCoordinate(locationManager.location!.coordinate) print( "Cur location is : \(locationManager.location!.coordinate)"); mapRect = MKMapRectUnion(mapRect, MKMapRectMake(point.x,point.y,0,0)) } mapView.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsetsMake(40.0, 40.0, 40.0, 40.0), animated: true) } 

考虑这个扩展:

 extension MKCoordinateRegion { init(locations: [CLLocationCoordinate2D], marginMultiplier: Double = 1.1) { let mapRect = locations.reduce(MKMapRect(), { let point = MKMapPointForCoordinate($1) let rect = MKMapRect(origin: point, size: MKMapSize(width: 0.0, height: 0.0)) return MKMapRectUnion($0, rect) }) var coordinateRegion = MKCoordinateRegionForMapRect(mapRect) coordinateRegion.span.latitudeDelta *= marginMultiplier coordinateRegion.span.longitudeDelta *= marginMultiplier self = coordinateRegion } }