ios 定位 MKMapView 以一次显示多个注释
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1336370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Positioning MKMapView to show multiple annotations at once
提问by jbrennan
I've got several annotations I want to add to my MKMapView (it could 0-n items, where n is generally around 5). I can add the annotations fine, but I want to resize the map to fit all annotations onscreen at once, and I'm not sure how to do this.
我有几个注释要添加到我的 MKMapView(它可以是 0-n 个项目,其中 n 通常约为 5)。我可以很好地添加注释,但我想调整地图的大小以一次适合屏幕上的所有注释,但我不确定如何执行此操作。
I've been looking at -regionThatFits:
but I'm not quite sure what to do with it. I'll post some code to show what I've got so far. I think this should be a generally straightforward task but I'm feeling a bit overwhelmed with MapKit so far.
我一直在看,-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];
}
Notice, this all happens as I receive a location update... I don't know if that's an appropriate place to do this. If not, where would be a better place? -viewDidLoad
?
请注意,这一切都是在我收到位置更新时发生的……我不知道这是否适合执行此操作。如果没有,哪里会更好?-viewDidLoad
?
Thanks in advance.
提前致谢。
采纳答案by Code Commander
As of iOS7 you can use showAnnotations:animated:
从 iOS7 开始,您可以使用showAnnotations:animated:
[mapView showAnnotations:annotations animated:YES];
回答by Mustafa
The linkposted by Jim is now dead, but i was able to find the code (which I had bookmarked somewhere). Hope this helps.
Jim 发布的链接现已失效,但我能够找到代码(我已在某处添加了书签)。希望这可以帮助。
- (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];
}
回答by me2
Why so complicated?
为什么这么复杂?
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(p.x, p.y, 0, 0));
}
return MKCoordinateRegionForMapRect(r);
}
回答by Donald Byrd
I have done something similiar to this to zoom out (or in) to an area that included a point annotation and the current location. You could expand this by looping through your annotations.
我已经做了一些类似的事情来缩小(或放大)到一个包含点注释和当前位置的区域。您可以通过循环注释来扩展它。
The basic steps are:
基本步骤是:
- Calculate the min lat/long
- Calculate the max lat/long
- Create CLLocation objects for these two points
- Calculate distance between points
- Create region using center point
between points and distance converted
to degrees
- Pass region into MapView to adjust
- Use adjusted region to set MapView region
- 计算最小纬度/经度
- 计算最大纬度/经度
- 为这两个点创建 CLLocation 对象
- 计算点之间的距离
- 使用点之间的中心点和转换为度数的距离创建区域
- 将区域传入 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];
}
回答by PKCLsoft
I have a different answer. I was going to do implement the zoom-to-fit algorithm myself, but i figured that Apple musthave a way to do what we wanted without so much work. Using the API doco quickly showed that I could use MKPolygon to do what was needed:
我有不同的答案。我打算自己实现缩放以适应算法,但我认为 Apple必须有一种方法可以在没有这么多工作的情况下做我们想做的事情。使用 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];
}
Hope this helps.
希望这可以帮助。
回答by Manish Ahuja
you can also do it this way..
你也可以这样做..
// 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;
}
回答by nh32rg
Based on the information and suggestions from everyone I came up with the following. Thanks for everyone in this discussion for contributing :) This would go in the view Controller that contains the mapView.
根据大家的信息和建议,我想出了以下内容。感谢这个讨论中的每个人的贡献:) 这将进入包含 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];
}
回答by jacobsimeon
In my case, I am starting with CLLocation objects and creating annotations for each of them.
I only need to place two annotations, so I have a simple approach to building the array of points, but it could easily be expanded to build an array with an arbitrary length given a set of CLLocations.
就我而言,我从 CLLocation 对象开始并为每个对象创建注释。
我只需要放置两个注释,所以我有一个简单的方法来构建点数组,但是可以很容易地扩展它以构建一个给定一组 CLLocations 的任意长度的数组。
Here's my implementation (doesn't require creating MKMapPoints):
这是我的实现(不需要创建 MKMapPoints):
//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])];
回答by Lindsay Thurmond
Using Swift, a polygon, and some extra padding I used the following:
使用 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)
}
回答by Paul Lehn
I know this is an old question but, if you want to display all the annotations ALREADY ON the map use this:
我知道这是一个老问题,但是,如果您想在地图上显示所有注释,请使用以下命令:
mapView.showAnnotations(mapView.annotations, animated: true)