如何在iOS中的Google Map上执行聚类 [英] How to perform clustering on google map in iOS

查看:47
本文介绍了如何在iOS中的Google Map上执行聚类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们如何在iOS的Google地图上使用GMS标记的聚类.如果有人有代码,请先分享.谢谢

How we can use clustering of GMS marker on google map in iOS.if anyone have code then please share.Thank you in advance

推荐答案

子类化UIMapView.CAClusterAnnotation-集群.CACatchAnnotation-单数.

Subclass a UIMapView. CAClusterAnnotation - clustered. CACatchAnnotation - singular.

.h

#import <MapKit/MapKit.h>

@interface CAMapView : MKMapView <MKMapViewDelegate>

@property (nonatomic) BOOL shouldCluster;

- (void)performClustering;

@end

.m

#import "CAMapView.h"
#import "CASpotClusterAnnotation.h"
#import "CACatchClusterAnnotation.h"
#include <math.h>

@interface CAMapView ()

@property (nonatomic) MKCoordinateSpan previousSpan;
@property (nonatomic) NSInteger previousCount;
@property (strong, nonatomic) NSMutableArray *allAnnotations;

@end

@implementation CAMapView

#pragma mark - Annotations
- (void)addAnnotation:(id<MKAnnotation>)annotation {
  [_allAnnotations addObject:annotation];
  [self performClustering];
}

- (void)removeAnnotation:(id<MKAnnotation>)annotation {
  [_allAnnotations removeObject:annotation];
  [self performClustering];
}

- (void)addAnnotations:(NSArray *)annotations {
  [_allAnnotations setArray:annotations];
  [self performClustering];
}

- (void)removeAnnotations:(NSArray *)annotations {
  [_allAnnotations removeAllObjects];
  [self performClustering];
}

- (CLLocationDistance)currentVisibleMapDistance {
  MKMapRect mRect = self.visibleMapRect;
  MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect));
  MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect));
  return MKMetersBetweenMapPoints(eastMapPoint, westMapPoint);
}

- (NSArray *)clustersWithAnnotations:(NSArray *)annotations {
  NSMutableArray *resultArray = [@[] mutableCopy];
  NSMutableArray *usedAnnotations = [@[] mutableCopy];

  BOOL hasIntersections = NO;

  for (id<MKAnnotation> annotation in annotations) {
    if ([usedAnnotations containsObject:annotation]) continue;
    [usedAnnotations addObject:annotation];

    NSMutableArray *clusterAnnotations = nil;
    CGRect activeRect = CGRectZero;
    CGPoint annotationPoint = [self convertCoordinate:annotation.coordinate
                                        toPointToView:self];
    if (![annotation isKindOfClass:[CAClusterAnnotation class]]) {
      clusterAnnotations = [NSMutableArray arrayWithArray:@[annotation]];
      activeRect = CGRectMake(annotationPoint.x,
                              annotationPoint.y,
                              20.0f,
                              20.0f);
    }
    else {
      CGSize size = [[CAClusterAnnotation fontAndSizeWithAnnotationsCount:[(CAClusterAnnotation *)annotation annotations].count][@"size"] CGSizeValue];
      activeRect = CGRectMake(annotationPoint.x,
                              annotationPoint.y,
                              size.width,
                              size.height);
    }

    for (id<MKAnnotation> anAnnotation in annotations) {
      if ([usedAnnotations containsObject:anAnnotation]) continue;
      CGPoint point = [self convertCoordinate:anAnnotation.coordinate
                                toPointToView:self];
      CGRect rect = CGRectZero;
      if ([anAnnotation isKindOfClass:[CAClusterAnnotation class]]) {
        CGSize size = [[CAClusterAnnotation fontAndSizeWithAnnotationsCount:[(CAClusterAnnotation *)anAnnotation annotations].count][@"size"] CGSizeValue];
        rect = CGRectMake(point.x,
                          point.y,
                          size.width,
                          size.height);
      }
      else {
        rect = CGRectMake(point.x,
                          point.y,
                          20.0f,
                          20.0f);
      }

      if (CGRectIntersectsRect(activeRect, rect)) {
        hasIntersections = YES;
        [usedAnnotations addObject:anAnnotation];
        if ([annotation isKindOfClass:[CAClusterAnnotation class]]) {
          if ([anAnnotation isKindOfClass:[CAClusterAnnotation class]]) {
            [((CAClusterAnnotation *)annotation).annotations addObjectsFromArray:[(CAClusterAnnotation *)anAnnotation annotations]];
          }
          else {
            [((CAClusterAnnotation *)annotation).annotations addObject:anAnnotation];
          }
        }
        else {
          if ([anAnnotation isKindOfClass:[CAClusterAnnotation class]]) {
            [clusterAnnotations addObjectsFromArray:[(CAClusterAnnotation *)anAnnotation annotations]];
          }
          else {
            [clusterAnnotations addObject:anAnnotation];
          }
        }
      }
    }

    if (clusterAnnotations) {
      if (clusterAnnotations.count == 1) {
        [resultArray addObject:[clusterAnnotations lastObject]];
      }
      else {
        if ([[annotations lastObject] isKindOfClass:[CACatch class]]) {
          CACatchClusterAnnotation *clusterAnnotation = [CACatchClusterAnnotation new];
          clusterAnnotation.annotations = clusterAnnotations;
          [resultArray addObject:clusterAnnotation];
        }
        else {
          CASpotClusterAnnotation *clusterAnnotation = [CASpotClusterAnnotation new];
          clusterAnnotation.annotations = clusterAnnotations;
          [resultArray addObject:clusterAnnotation];
        }
      }
    }
    else {
      [resultArray addObject:annotation];
    }
  }

  if (!hasIntersections)
    return resultArray;
  else
    return [self clustersWithAnnotations:resultArray];
}

- (void)performClustering {

  for (id<MKAnnotation> annotation in self.annotations) {
    if ([annotation isKindOfClass:[MKUserLocation class]]) {
      _locationBtn.selected = (fabs([annotation coordinate].latitude - self.centerCoordinate.latitude) < .0001f
                               && fabs([annotation coordinate].longitude - self.centerCoordinate.longitude) < .0001f);
      break;
    }
  }

  if (fabs(_previousSpan.latitudeDelta) > .0001f
      && fabs(_previousSpan.longitudeDelta) > .0001f) {
    if (fabs(self.region.span.longitudeDelta - _previousSpan.longitudeDelta) < .00001f) {
      self.previousSpan = self.region.span;
      if (_previousCount && _allAnnotations.count) {
        return;
      }
    }
  }

  for (id<MKAnnotation> annotation in self.selectedAnnotations) {
    [self deselectAnnotation:annotation animated:NO];
  }

  self.previousSpan = self.region.span;
  self.previousCount = _allAnnotations.count;

  for (id<MKAnnotation> annotation in self.annotations) {
    if ([annotation isKindOfClass:[MKUserLocation class]]) continue;
    [super removeAnnotation:annotation];
  }

  if (!_shouldCluster) {
    if (_allAnnotations.count) {
      [super addAnnotations:_allAnnotations];
    }
    return;
  }

  if (!_allAnnotations.count) return;

  NSMutableArray *buffer = [@[] mutableCopy];

  [buffer addObjectsFromArray:[self clustersWithAnnotations:_allAnnotations]];

  [super addAnnotations:buffer];
}

@end

编辑: CACatchClusterAnnotation CASpotClusterAnnotation 都是 CAClusterAnnotation 的子类,您需要使用它们,我用这两个来区分集群注释的类型.情况只有一种.该代码具有很多体系结构上的缺陷,但是我没有时间修复它们,尽管它足以供您使用.

EDIT: CACatchClusterAnnotation and CASpotClusterAnnotation are both subclasses of CAClusterAnnotation, which you need to use, I used those two to distinguish the type of cluster annotation, in your case it's only one type. The code has a lot of architectural flaws, but I don't have any time to fix them, it should be sufficient for you to work with though.

CAClusterAnnotation.h

CAClusterAnnotation.h

#import <Foundation/Foundation.h>

@interface CAClusterAnnotation : NSObject <MKAnnotation>

// <MKAnnotation> conformation properties
@property (copy, nonatomic) NSString *title;
@property (nonatomic) CLLocationCoordinate2D coordinate;

// Annotations setter that will update |coordinate|
@property (strong, nonatomic) NSMutableArray *annotations;

@end

CAClusterAnnotation.m

CAClusterAnnotation.m

#import "CAClusterAnnotation.h"

@implementation CAClusterAnnotation

- (void)setAnnotations:(NSMutableArray *)annotations {
  _annotations = annotations;

  MKMapRect r = MKMapRectNull;
  for (NSUInteger i=0; i < _annotations.count; ++i) {
    MKMapPoint p = MKMapPointForCoordinate([_annotations[i] coordinate]);
    r = MKMapRectUnion(r, MKMapRectMake(p.x, p.y, 0, 0));
  }
  self.coordinate = MKCoordinateRegionForMapRect(r).center;
}

+ (NSDictionary *)fontAndSizeWithAnnotationsCount:(NSInteger)count {
  UIFont *font = [UIFont fontWithName:CAFontNameDefaultRegular size:12.0f];
  UIImage *img = [UIImage imageNamed:@"spotlist_map_other_spot_icon"];
  NSString *catchesNumberStr = (count > 999) ? @"999+" : [NSString stringWithFormat:@"%d", count];
  CGSize size = CGSizeMake([catchesNumberStr sizeWithFont:font].width + 6.0f, img.size.height);
  size.width = MAX(size.width, img.size.width);
  return @{@"font" : font, @"size" : [NSValue valueWithCGSize:size]};
}

@end

在管理 MKMapView .m文件的视图控制器中,您需要实现至少两种方法-一种呈现注释,另一种在需要时执行聚类:

In the view controller that manages your MKMapView .m file, you need to implement at least two methods - one to render your annotations, another one to perform clustering whenever it's needed:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
  MKAnnotationView *annotationView = nil;

  if ([annotation isKindOfClass:[CACatch class]]) {
    NSString *catchIdentifier = @"catch";
    annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:catchIdentifier];
    if (!annotationView) {
      annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:catchIdentifier];
      annotationView.image = [UIImage imageNamed:@"icon"];
    }
  }
  else if ([annotation isKindOfClass:[CAClusterAnnotation class]]) {
    static NSString *catchIdentifier = @"catchCluster";
    annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:catchIdentifier];
    if (!annotationView) {
      annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:catchIdentifier];
    }

    NSInteger catchesCount = [(CACatchClusterAnnotation *)annotation annotations].count;
    NSDictionary *fontAndSize = [CAClusterAnnotation fontAndSizeWithAnnotationsCount:catchesCount];

    UIImage *img = [UIImage imageNamed:@"cluster_icon"];
    NSString *catchesNumberStr = (catchesCount > 999) ? @"999+" : [NSString stringWithFormat:@"%d", catchesCount];
    CGSize size = [fontAndSize[@"size"] CGSizeValue];

    UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, MAX(size.width, img.size.width), size.height)];
    imgView.backgroundColor = [UIColor clearColor];
    imgView.opaque = NO;
    imgView.image = [img resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f)];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, imgView.frame.size.width, imgView.frame.size.height - 2.0f)];
    label.backgroundColor = [UIColor clearColor];
    label.font = fontAndSize[@"font"];
    label.textColor = [UIColor whiteColor];
    label.text = catchesNumberStr;
    label.textAlignment = NSTextAlignmentCenter;
    [imgView addSubview:label];

    UIGraphicsBeginImageContextWithOptions(imgView.bounds.size, imgView.opaque, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    annotationView.image = img;
  }
  else if ([annotation isKindOfClass:[MKUserLocation class]]) {
    static NSString *userIdentifier = @"user";
    annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:userIdentifier];
    if (!annotationView) {
      annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:userIdentifier];
      annotationView.canShowCallout = YES;
    }
    annotationView.image = [UIImage imageNamed:@"current_location_icon"];
  }

  return annotationView;
}

- (void)mapView:(CAMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
  [mapView performClustering];
}

这篇关于如何在iOS中的Google Map上执行聚类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆