2011-08-20 25 views
11

Tôi có một bản đồ có nhiều chú thích, hầu hết chúng đều rất gần nhau. Những gì tôi muốn làm tương tự như ứng dụng Ảnh trên iOS, nơi các chú thích được nhóm lại khi chúng quá gần nhau và bất cứ khi nào bạn thu nhỏ, chúng không được nhóm nếu chúng quá xa nhau.Được nhóm/Ungroup MKAnnotation tùy thuộc vào mức thu phóng (Và giữ cho nó nhanh)

Tôi đã thấy this question nhưng câu trả lời được đưa ra không thực sự là những gì tôi đang tìm kiếm.

Tôi đang tìm thư viện hoặc thuật toán mà tôi có thể tự triển khai.

Trả lời

5

Có giao diện here để xem câu trả lời đầy đủ. Nó chứa cả hai triển khai cho MapKit và Google Maps. Mã được lấy cảm hứng từ video của WWDC 2011 và hoạt động rất tốt trong ứng dụng của tôi.

Tôi đăng mã cho MapKit tại đây, nhưng có một vài nhận xét hữu ích trong câu trả lời khác của tôi.

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

bạn có mẫu cho điều này không? – karthikeyan

10

Một trong các video phiên WWDC 2011 của Apple cho thấy cách thực hiện chính xác điều này. Truy cập https://developer.apple.com/videos/wwdc/2011/ (phải là nhà phát triển đã đăng ký) và cuộn đến video có tiêu đề "Trực quan hóa thông tin địa lý với MapKit". Ý tưởng cơ bản là sử dụng chế độ xem bản đồ ngoài màn hình để giữ tất cả các chú thích của bạn và sao chép chúng vào chế độ xem bản đồ trên màn hình nếu cần, đảm bảo rằng bạn không cố gắng hiển thị quá nhiều cùng một lúc. Nó thậm chí không hoạt hình tiện lợi với các chú thích khi bạn phóng to.

+1

Tôi có thể lấy mã nguồn của bản trình diễn trong video ở đâu? –

+0

Điều đó tôi không biết. – shawkinaw

Các vấn đề liên quan