【问题标题】:Grouped/Ungroup MKAnnotation depending on the zoom level (And keep it fast)根据缩放级别分组/取消组合MKAnnotation(并保持快速)
【发布时间】:2011-08-20 13:59:33
【问题描述】:

我有一个有很多注释的地图视图,其中大部分都非常接近。我想要做的类似于 iOS 上的照片应用程序,其中注释在彼此太近时被分组,并且每当您缩小时,如果它们相距太远,它们就会取消分组。

我已经看过this question,但给出的答案并不是我真正想要的。

我正在寻找可以自己实现的库或算法。

【问题讨论】:

    标签: ios mapkit mkannotation


    【解决方案1】:

    Apple 的 WWDC 2011 会议视频之一展示了如何做到这一点。转至https://developer.apple.com/videos/wwdc/2011/(必须是注册开发者)并滚动到标题为“使用 MapKit 在地理上可视化信息”的视频。基本思想是使用屏幕外地图视图来保存所有注释,并根据需要将它们复制到屏幕地图视图中,确保您不会一次显示太多。它甚至可以在您缩放时使用注释制作漂亮的动画。

    【讨论】:

      【解决方案2】:

      查看here 以查看完整答案。它包含 MapKit 和 Google Maps 的实现。该代码受 WWDC 2011 视频的启发,在我的应用程序中运行良好。

      无论如何,我在这里发布了 MapKit 的代码,但在我的其他答案中有一些有用的评论。

      - (void)didZoom:(UIGestureRecognizer*)gestureRecognizer {
          if (gestureRecognizer.state == UIGestureRecognizerStateEnded){
              [self updateVisibleAnnotations];
          }
      }
      - (void)updateVisibleAnnotations {
          static float marginFactor = 2.0f;
          static float bucketSize = 50.0f;
          MKMapRect visibleMapRect = [self.mapView visibleMapRect];
          MKMapRect adjustedVisibleMapRect = MKMapRectInset(visibleMapRect, -marginFactor * visibleMapRect.size.width, -marginFactor * visibleMapRect.size.height);
      
          CLLocationCoordinate2D leftCoordinate = [self.mapView convertPoint:CGPointZero toCoordinateFromView:self.view];
          CLLocationCoordinate2D rightCoordinate = [self.mapView convertPoint:CGPointMake(bucketSize, 0) toCoordinateFromView:self.view];
          double gridSize = MKMapPointForCoordinate(rightCoordinate).x - MKMapPointForCoordinate(leftCoordinate).x;
          MKMapRect gridMapRect = MKMapRectMake(0, 0, gridSize, gridSize);
      
          double startX = floor(MKMapRectGetMinX(adjustedVisibleMapRect) / gridSize) * gridSize;
          double startY = floor(MKMapRectGetMinY(adjustedVisibleMapRect) / gridSize) * gridSize;
          double endX = floor(MKMapRectGetMaxX(adjustedVisibleMapRect) / gridSize) * gridSize;
          double endY = floor(MKMapRectGetMaxY(adjustedVisibleMapRect) / gridSize) * gridSize;
      
          gridMapRect.origin.y = startY;
          while(MKMapRectGetMinY(gridMapRect) <= endY) {
              gridMapRect.origin.x = startX;
              while (MKMapRectGetMinX(gridMapRect) <= endX) {
                  NSSet *allAnnotationsInBucket = [self.allAnnotationMapView annotationsInMapRect:gridMapRect];
                  NSSet *visibleAnnotationsInBucket = [self.mapView annotationsInMapRect:gridMapRect];
      
                  NSMutableSet *filteredAnnotationsInBucket = [[allAnnotationsInBucket objectsPassingTest:^BOOL(id obj, BOOL *stop) {
                      BOOL isPointMapItem = [obj isKindOfClass:[PointMapItem class]];
                      BOOL shouldBeMerged = NO;
                      if (isPointMapItem) {
                          PointMapItem *pointItem = (PointMapItem *)obj;
                          shouldBeMerged = pointItem.shouldBeMerged;
                      }
                      return shouldBeMerged;
                  }] mutableCopy];
                  NSSet *notMergedAnnotationsInBucket = [allAnnotationsInBucket objectsPassingTest:^BOOL(id obj, BOOL *stop) {
                      BOOL isPointMapItem = [obj isKindOfClass:[PointMapItem class]];
                      BOOL shouldBeMerged = NO;
                      if (isPointMapItem) {
                          PointMapItem *pointItem = (PointMapItem *)obj;
                          shouldBeMerged = pointItem.shouldBeMerged;
                      }
                      return isPointMapItem && !shouldBeMerged;
                  }];
                  for (PointMapItem *item in notMergedAnnotationsInBucket) {
                      [self.mapView addAnnotation:item];
                  }
      
                  if(filteredAnnotationsInBucket.count > 0) {
                      PointMapItem *annotationForGrid = (PointMapItem *)[self annotationInGrid:gridMapRect usingAnnotations:filteredAnnotationsInBucket];
                      [filteredAnnotationsInBucket removeObject:annotationForGrid];
                      annotationForGrid.containedAnnotations = [filteredAnnotationsInBucket allObjects];
                      [self.mapView addAnnotation:annotationForGrid];
                      //force reload of the image because it's not done if annotationForGrid is already present in the bucket!!
                      MKAnnotationView* annotationView = [self.mapView viewForAnnotation:annotationForGrid];
                      NSString *imageName = [AnnotationsViewUtils imageNameForItem:annotationForGrid selected:NO];
                      UILabel *countLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 2, 8, 8)];
                      [countLabel setFont:[UIFont fontWithName:POINT_FONT_NAME size:10]];
                      [countLabel setTextColor:[UIColor whiteColor]];
                      [annotationView addSubview:countLabel];
                      imageName = [AnnotationsViewUtils imageNameForItem:annotationForGrid selected:NO];
                      annotationView.image = [UIImage imageNamed:imageName];
      
                      if (filteredAnnotationsInBucket.count > 0){
                          [self.mapView deselectAnnotation:annotationForGrid animated:NO];
                      }
                      for (PointMapItem *annotation in filteredAnnotationsInBucket) {
                          [self.mapView deselectAnnotation:annotation animated:NO];
                          annotation.clusterAnnotation = annotationForGrid;
                          annotation.containedAnnotations = nil;
                          if ([visibleAnnotationsInBucket containsObject:annotation]) {
                              CLLocationCoordinate2D actualCoordinate = annotation.coordinate;
                              [UIView animateWithDuration:0.3 animations:^{
                                  annotation.coordinate = annotation.clusterAnnotation.coordinate;
                              } completion:^(BOOL finished) {
                                  annotation.coordinate = actualCoordinate;
                                  [self.mapView removeAnnotation:annotation];
                              }];
                          }
                      }
                  }
                  gridMapRect.origin.x += gridSize;
              }
              gridMapRect.origin.y += gridSize;
          }
      }
      
      - (id<MKAnnotation>)annotationInGrid:(MKMapRect)gridMapRect usingAnnotations:(NSSet *)annotations {
          NSSet *visibleAnnotationsInBucket = [self.mapView annotationsInMapRect:gridMapRect];
          NSSet *annotationsForGridSet = [annotations objectsPassingTest:^BOOL(id obj, BOOL *stop) {
              BOOL returnValue = ([visibleAnnotationsInBucket containsObject:obj]);
              if (returnValue) {
                  *stop = YES;
              }
              return returnValue;
          }];
      
          if (annotationsForGridSet.count != 0) {
              return [annotationsForGridSet anyObject];
          }
          MKMapPoint centerMapPoint = MKMapPointMake(MKMapRectGetMinX(gridMapRect), MKMapRectGetMidY(gridMapRect));
          NSArray *sortedAnnotations = [[annotations allObjects] sortedArrayUsingComparator:^(id obj1, id obj2) {
              MKMapPoint mapPoint1 = MKMapPointForCoordinate(((id<MKAnnotation>)obj1).coordinate);
              MKMapPoint mapPoint2 = MKMapPointForCoordinate(((id<MKAnnotation>)obj2).coordinate);
      
              CLLocationDistance distance1 = MKMetersBetweenMapPoints(mapPoint1, centerMapPoint);
              CLLocationDistance distance2 = MKMetersBetweenMapPoints(mapPoint2, centerMapPoint);
      
              if (distance1 < distance2) {
                  return NSOrderedAscending;
              }
              else if (distance1 > distance2) {
                  return NSOrderedDescending;
              }
              return NSOrderedSame;
          }];
          return [sortedAnnotations objectAtIndex:0];
      } 
      

      【讨论】:

      • 你有这个样品吗?
      猜你喜欢
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 2017-06-19
      • 2018-10-09
      • 2016-05-07
      • 1970-01-01
      相关资源
      最近更新 更多