【问题标题】:Zooming MKMapView to fit annotation pins?缩放 MKMapView 以适应注释图钉?
【发布时间】:2011-06-08 12:21:58
【问题描述】:

我正在使用 MKMapView 并在地图上添加了一些注释图钉,大约 5-10 公里的区域。当我运行应用程序时,我的地图开始缩小以显示整个世界,缩放地图以使图钉适合视图的最佳方法是什么?

编辑: 我最初的想法是使用 MKCoordinateRegionMake 并从我的注释中计算坐标中心、longitudeDelta 和 latitudeDelta。我很确定这会起作用,但我只是想检查一下我没有遗漏任何明显的东西。

代码添加,顺便说一句:FGLocation 是一个符合MKAnnotation 的类,locationFake 是这些对象的NSMutableArray。随时欢迎评论....

- (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;
}

【问题讨论】:

标签: ios objective-c iphone cocoa-touch mkmapview


【解决方案1】:

这是我找到的对我有用的here

(编辑:我已经使用@Micah 的建议更新了解决方案,将 pointRect 增加了 0.1,以确保 rect 最终不会变得无限小!)

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];

 

您还可以通过将第一行替换为以下内容来更新它以包含 userLocation 引脚:

MKMapPoint annotationPoint = MKMapPointForCoordinate(mapView.userLocation.coordinate);
MKMapRect zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);

【讨论】:

  • 确实不错。不过,您不需要检查 isNull 。 MKMapRectUnion 为你做这件事。来自文档:“如果任一矩形为空,则此方法返回另一个矩形。”
  • 非常好的解决方案!!!这是添加一些填充的额外一点点:double inset = -zoomRect.size.width * 0.1; [self.mapView setVisibleMapRect:MKMapRectInset(zoomRect, inset, inset) 动画:YES];
  • 太棒了!潜在的补充:如果你想排除“当前位置注释”,只需在 for 循环中添加一个 if 语句: if (![annotation isKindOfClass:[MKUserLocation class]]) { // Do stuff here }
  • @CraigB 的填充解决方案非常好,但是当路径是垂直的时它不能很好地工作,例如从南到北的移动,来解决这个问题使用 double inset = MIN(-zoomRect.size.width * 0.1, -zoomRect.size.height * 0.1);
  • 填充增强:double insetWidth = -zoomRect.size.width * 0.2;双 insetHeight = -zoomRect.size.height * 0.2; MKMapRect insetRect = MKMapRectInset(zoomRect, insetWidth, insetHeight);然后使用这个新的 insertRect
【解决方案2】:

你说得对。

找出您的最大和最小纬度和经度,应用一些简单的算术,然后使用MKCoordinateRegionMake

对于 iOS 7 及更高版本,使用showAnnotations:animated:,来自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);

【讨论】:

  • 适用于 iOS 7 及更高版本(参考 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);
  • 这很好用,但有时当我放大(在地图中)然后尝试将其居中(使用调用此方法的按钮)时,它似乎不起作用。
  • 请务必注意,showAnnotations 也会将注释添加到地图中,即使该位置的注释已经存在。
  • @EnekoAlonso 您可以通过在showAnnotations(_ annotations:animated) 之后立即调用removeAnnotations(_ annotations:) 来解决此问题
  • 另外值得注意的是,虽然 showAnnotations 将区域设置为显示注释,但仍会调整区域以匹配纵横比;这会经常排除一些注释。另请注意,showAnnotations 是此处提供的唯一正确解决方案;其他答案都没有尝试处理跨越国际日期变更线的注释。
【解决方案3】:

Apple 为 IOS 7 添加了一种新方法,以简化生活。

[mapView showAnnotations:yourAnnotationArray animated:YES];

您可以轻松地从存储在地图视图中的数组中提取:

yourAnnotationArray = mapView.annotations;

并快速调整相机!

mapView.camera.altitude *= 1.4;

除非用户安装了 iOS 7+ 或 OS X 10.9+,否则这将不起作用。查看自定义动画here

【讨论】:

  • 我不确定这是否是因为我的实现中的其他一些因素,但我发现 showAnnotations 不像手动实现那样接近缩放/适合注释,所以我坚持使用手册。
  • 尝试将相机高度乘以 1 的一小部分,例如 mapView.camera.altitude *= .85;更近的视口
  • 我还发现这对于选择当前可见地图区域之外的注释很有用。默认情况下,MapView 不选择不可见的注释。在调用 selectAnnotation 之前,使用不可见注释数组调用 showAnnotations,地图应更新其可视区域。
【解决方案4】:

我使用这个代码并且工作正常:

-(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];
}

【讨论】:

  • 不起作用:▿2元素▿0:cllocationcoords2d - 纬度:46.969995730376894 - 经度:-109.2494943434474▿1:cllocationcoords2d - 纬度:63.23212154333072 - 经度:174.136661126533 span>
【解决方案5】:

在 Swift 中使用

mapView.showAnnotations(annotationArray, animated: true)

在目标c中

[mapView showAnnotations:annotationArray animated:YES];

【讨论】:

  • 如果mapView上已经设置了注解,可以直接引用:mapView.showAnnotations(mapView.annotations, animated: true)
【解决方案6】:

我已经转换了 Rafael Moreira 的答案。功劳归于他。 对于那些寻找 Swift 版本的人,这里是代码:

 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)
}

【讨论】:

    【解决方案7】:

    我创建了一个扩展来使用一些代码快速显示所有注释。如果即使在最大缩放级别下也无法显示所有注释,这将不会显示所有注释。

    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)
        }
    }
    

    【讨论】:

    • 我设法通过更改 UIEdgeInsetsMake 参数获得了更好的结果,30 到 100 之间的值对我有好处。我正在使用 iPhone SE i)S 10.2 模拟器进行测试。示例代码:setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(100, 100, 100, 100), animated: true)。请注意,此代码适用于 Swift 3 和 XCode 8.2.1。
    【解决方案8】:

    Swift 3 这是适合地图中所有注释的正确方法。

    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)
    
        }
    

    【讨论】:

    • @ArshadShaik 您的suggested edit 已被拒绝,如果您想为 Swift 4.2 提供新的答案,请随意,但将其添加为答案,而不是通过将其编辑到其他用户的帖子中。
    【解决方案9】:

    @jowie 的解决方案效果很好。一个问题,如果一张地图只有一个注释,你最终会得到一张完全缩小的地图。我在 rect make size 中添加了 0.1 以确保 setVisibleMapRect 有可以缩放的对象。

    MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
    

    【讨论】:

      【解决方案10】:

      如果您正在寻找iOS 8 及更高版本,最简单的方法是在调用func showAnnotations(annotations: [MKAnnotation], animated: Bool) 之前设置地图视图的var layoutMargins: UIEdgeInsets { get set }

      例如(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)
      }
      

      【讨论】:

        【解决方案11】:

        在 for 循环中添加了这个 If 循环,以从这个方法中排除用户位置 pin(在我的情况下是必需的,也许是其他情况)

        if (![annotation isKindOfClass:[MKUserLocation class]] ) {
        
        //Code Here...
        
        }
        

        【讨论】:

          【解决方案12】:

          对于 iOS 7 及更高版本(参考 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 的评论

          你只需调用:

           [yourMapView showAnnotations:@[yourAnnotation] animated:YES];
          

          【讨论】:

          • 仅供参考,其中包含 NS_AVAILABLE 文本,因为在 2011 年 1 月,在设备上安装 iOS 7 的可能性不大,并且 NS_AVAILABLE 保护应用程序免于构建失败或崩溃。
          【解决方案13】:
              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)
          

          // 为 swift 5 编辑

          【讨论】:

            【解决方案14】:

            在 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)
            

            【讨论】:

              【解决方案15】:

              感谢 jowie,我已将旧类别更新为更优雅的解决方案。分享完整的、几乎可以复制粘贴的解决方案

              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
              

              希望它对某人有所帮助,再次感谢乔伊!

              【讨论】:

                【解决方案16】:
                 - (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];
                
                }
                

                【讨论】:

                  【解决方案17】:

                  正如 Abhishek Bedi 在评论中指出的那样,对于 iOS7 前进,最好的方法是:

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

                  对于我的个人项目(iOS7 之前),我只是在 MKMapView 类上添加了一个类别来封装“可见区域”功能,以实现一个非常常见的操作:将其设置为能够查看当前加载的所有注释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(p.x, p.y, 0, 0));
                      }
                  
                      [mapView setVisibleMapRect:r animated:animated];
                  
                  }
                  
                  @end
                  

                  如您所见,到目前为止,我已经添加了 2 种方法:一种用于将地图的可见区域设置为适合 MKMapView 实例上所有当前加载的注释的区域,另一种用于将其设置为任何数组的方法的对象。 因此,要设置 mapView 的可见区域,代码将非常简单:

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

                  希望对你有帮助=)

                  【讨论】:

                    【解决方案18】:

                    此页面上的所有答案假设地图占据全屏。我实际上有一个 HUD 显示器(即分散在顶部和底部的按钮),它在地图顶部提供信息.. 所以页面上的算法会正确显示图钉,但其中一些会出现在 under HUD 显示按钮。

                    我的解决方案将地图放大以在屏幕的子集中显示注释,并适用于不同的屏幕尺寸(即 3.5" 与 4.0" 等):

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

                    这是我在代码中所做的(注意:我使用 NSConstraints 和一些辅助方法来使我的代码在不同的屏幕尺寸下工作.. 虽然代码非常可读.. 我的回答 here 更好地解释了它。 . 它基本上是相同的工作流程:)

                    // 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];
                    

                    这是获取适合区域的代码:

                    - (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;
                    }
                    

                    【讨论】:

                      【解决方案19】:

                      我对 Rafael 的 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];
                      }
                      

                      【讨论】:

                        【解决方案20】:

                        根据上述答案,您可以使用通用方法缩放地图以同时适合所有注释和叠加层。

                        -(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;
                        }
                        

                        然后:

                        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];
                        

                        【讨论】:

                          【解决方案21】:

                          只是分享我对此的看法:

                          如果您在情节提要中使用 xCode > 6 和“推断”屏幕尺寸(请参阅文件检查器上的“模拟指标”),请调用

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

                          viewDidLoad 中将导致 4 英寸 iPhone 上的缩放级别过大,因为地图的布局仍然与故事板中更宽屏幕的大小相同。

                          您可以将您的电话转至showAnnotations...viewDidAppear。然后地图的大小已经调整为 iPhone 4 的小屏幕了。

                          或者将文件检查器中“模拟指标”下的“推断”值更改为 iphone 4 英寸。

                          【讨论】:

                            【解决方案22】:

                            您可以选择要与注释一起显示的形状。

                            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)
                                }
                              }
                            }
                            

                            【讨论】:

                              【解决方案23】:

                              2021 年 Swift 5+

                              // Position the map such that the provided array of annotations are all visible to the fullest extent possible.
                                  @available(iOS 7.0, *)
                                  open func showAnnotations(_ annotations: [MKAnnotation], animated: Bool)
                              

                              所以你可以:

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

                              【讨论】:

                                【解决方案24】:

                                @"我不确定这是否是因为我的实现中的其他一些因素,但我发现 showAnnotations 不像手动实现那样接近缩放/拟合注释,所以我已经坚持使用手册。– Ted Avery 4 月 17 日 0:35"

                                我遇到了同样的问题,但后来我尝试了两次 showAnnotations(如下所示),但由于某种原因,它成功了。

                                [mapView showAnnotations:yourAnnotationArray Animation:YES]; [mapView showAnnotations:yourAnnotationArray 动画:YES];

                                【讨论】:

                                  【解决方案25】:

                                  iOS 7 兼容的方式是使用以下方式。首先调用showAnnotation 以获得一个包含所有注释的矩形。然后创建和UIEdgeInset,顶部插入引脚高度。因此,您可以确保在地图上显示整个图钉。

                                  [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];
                                  

                                  【讨论】:

                                    【解决方案26】:

                                    将其相应地放入您的代码中:

                                      - (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
                                        {
                                        id<MKAnnotation> mp = [annotationView annotation];
                                            MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate] ,250,250);
                                    
                                           [mv setRegion:region animated:YES];
                                    
                                    }
                                    

                                    【讨论】:

                                      猜你喜欢
                                      • 2015-07-08
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2011-02-22
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2010-12-08
                                      相关资源
                                      最近更新 更多