2011-08-20 11 views
11

私は多くの注釈を持つマップビューを持っています。それらのほとんどはお互いに非常に近いです。私がやりたいことは、iOSの写真アプリに似ています.iOSのアノテーションは、お互いが近すぎるとグループ化され、ズームするたびに離れすぎるとグループ化されません。ズームレベルに応じてMKAnnotationをグループ化/グループ解除します(速くしてください)

私はすでにthis questionを見ましたが、答えは実際に私が探していたものではありません。

自分で実装できるライブラリまたはアルゴリズムを探しています。

答えて

5

完全な答えを確認するには、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]; 
} 
+0

これのサンプルはありますか? – karthikeyan

10

AppleのWWDC 2011セッションビデオの1つに、これを正確に行う方法が示されています。 https://developer.apple.com/videos/wwdc/2011/(開発者登録が必要)に移動し、「MapKitを使って地理的に情報を視覚化する」というビデオにスクロールします。基本的なアイデアは、オフスクリーンマップビューを使用してすべての注釈を保持し、必要に応じて画面上のマップビューにコピーして、一度に多くの注釈を表示しないようにすることです。あなたがズームするにつれてアノテーションを使って素晴らしいアニメーションを作成することさえできます。

+1

ビデオのデモのソースコードはどこで入手できますか? –

+0

私はそれが分かりません。 – shawkinaw

関連する問題