一切就绪!

着手开发前,请先阅读我们的开发者文档

激活 Google Maps SDK for iOS

为帮助您起步,我们将引导您在 Google Developers Console 中先完成几项任务:

  1. 创建或选择项目
  2. 激活 Google Maps SDK for iOS
  3. 创建相应密钥
继续

标记聚类

此页面介绍了 Google Maps SDK for iOS 的实用程序内容库中提供的标记聚类实用程序。

通过将标记聚类,即使在地图上放置大量标记,也不会使地图变得难以查看。标记聚类实用程序可帮助您管理不同缩放比例的多个标记。

当用户在高缩放比例下查看地图时,各个标记会显示在地图上。当用户缩小时,这些标记会聚拢形成聚类,以方便地图的查看。

快速入门

运行 pod try Google-Maps-iOS-Utils 可以使用随实用程序内容库提供的演示版应用。演示版应用提供了标记聚类实用程序的示例实现。

如需完整代码示例,请参阅 GitHub 上的 ObjCDemoAppSwiftDemoApp

下面的屏幕截图显示了标记聚类的默认样式:

一幅采用默认样式并包含聚类标记的地图

下面是一个自定义标记聚类的示例:

一幅包含自定义聚类标记的地图

先决条件和说明

标记聚类实用程序是 Google Maps SDK for iOS Utility Library 的一部分。如果您尚未安装该内容库,请按照安装指南操作,然后再阅读本页面的其余内容。

为获得最佳性能,建议的最大标记数量为 10,000。

添加简单的标记聚类器

要表示您想要在地图上显示的标记,请在您的 ViewController 中实现 GMUClusterItem 协议。下面的代码将定义一个景点,即 POIItem 类,表示标记将以聚类形式在地图上管理:

Swift

/// Point of Interest Item which implements the GMUClusterItem protocol.
class POIItem: NSObject, GMUClusterItem {
  var position: CLLocationCoordinate2D
  var name: String!

  init(position: CLLocationCoordinate2D, name: String) {
    self.position = position
    self.name = name
  }
}

Objective-C

#import "ViewController.h"

#import <Google-Maps-iOS-Utils/GMUMarkerClustering.h>
#import <GoogleMaps/GoogleMaps.h>

// Point of Interest Item which implements the GMUClusterItem protocol.
@interface POIItem : NSObject<GMUClusterItem>

@property(nonatomic, readonly) CLLocationCoordinate2D position;
@property(nonatomic, readonly) NSString *name;

- (instancetype)initWithPosition:(CLLocationCoordinate2D)position name:(NSString *)name;

@end

要使用聚类管理器,请实例化 GMUClusterManager 对象,并向其传递 GMSMapViewGMUClusterAlgorithmGMUClusterRenderer。内容库包含聚类算法和渲染器的默认实现。下面的代码将使用 GMUNonHierarchicalDistanceBasedAlgorithmGMUDefaultClusterRenderer(包含在实用程序内容库中)创建一个聚类管理器:

Swift

class ViewController: UIViewController, GMUClusterManagerDelegate,
    GMSMapViewDelegate {

  private var mapView: GMSMapView!
  private var clusterManager: GMUClusterManager!

  override func viewDidLoad() {
    super.viewDidLoad()

    // Set up the cluster manager with the supplied icon generator and
    // renderer.
    let iconGenerator = GMUDefaultClusterIconGenerator()
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    let renderer = GMUDefaultClusterRenderer(mapView: mapView,
                                clusterIconGenerator: iconGenerator)
    clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm,
                                                      renderer: renderer)

    // Generate and add random items to the cluster manager.
    generateClusterItems()

    // Call cluster() after items have been added to perform the clustering
    // and rendering on map.
    clusterManager.cluster()
  }
}

Objective-C

@implementation ViewController {
  GMSMapView *_mapView;
  GMUClusterManager *_clusterManager;
}

- (void)loadView {
  GMSCameraPosition *camera =
      [GMSCameraPosition cameraWithLatitude:kCameraLatitude longitude:kCameraLongitude zoom:10];
  _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
  self.view = _mapView;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  // Set up the cluster manager with a supplied icon generator and renderer.
  id<GMUClusterAlgorithm> algorithm =
      [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];
  id<GMUClusterIconGenerator> iconGenerator =
      [[GMUDefaultClusterIconGenerator alloc] init];
  id<GMUClusterRenderer> renderer =
      [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView
                                    clusterIconGenerator:iconGenerator];
  _clusterManager =
      [[GMUClusterManager alloc] initWithMap:_mapView
                                   algorithm:algorithm
                                    renderer:renderer];

  // Generate and add random items to the cluster manager.
  [self generateClusterItems];

  // Call cluster() after items have been added
  // to perform the clustering and rendering on map.
  [_clusterManager cluster];
}

通过调用 clusterManager:addItem:,以 GMUClusterItem 对象形式将您的标记获取到聚类中。下面的代码将在地图摄像头的视野范围内随机生成聚类项 (POI),并将其获取到聚类管理器中:

Swift

/// Randomly generates cluster items within some extent of the camera and
/// adds them to the cluster manager.
private func generateClusterItems() {
  let extent = 0.2
  for index in 1...kClusterItemCount {
    let lat = kCameraLatitude + extent * randomScale()
    let lng = kCameraLongitude + extent * randomScale()
    let name = "Item \(index)"
    let item =
        POIItem(position: CLLocationCoordinate2DMake(lat, lng), name: name)
    clusterManager.addItem(item)
  }
}

/// Returns a random value between -1.0 and 1.0.
private func randomScale() -> Double {
  return Double(arc4random()) / Double(UINT32_MAX) * 2.0 - 1.0
}

Objective-C

// Randomly generates cluster items within some extent of the camera and
// adds them to the cluster manager.
- (void)generateClusterItems {
  const double extent = 0.2;
  for (int index = 1; index <= kClusterItemCount; ++index) {
    double lat = kCameraLatitude + extent * [self randomScale];
    double lng = kCameraLongitude + extent * [self randomScale];
    NSString *name = [NSString stringWithFormat:@"Item %d", index];
    id<GMUClusterItem> item =
        [[POIItem alloc] initWithPosition:CLLocationCoordinate2DMake(lat, lng)
                                     name:name];
    [_clusterManager addItem:item];
  }
}

// Returns a random value between -1.0 and 1.0.
- (double)randomScale {
  return (double)arc4random() / UINT32_MAX * 2.0 - 1.0;
}

处理标记和聚类上的事件

使用地图委托:一般而言,在使用 Google Maps SDK for iOS 时,要侦听地图上的事件,您必须实现 GMSMapViewDelegate 协议。默认情况下,在使用 GMUClusterManager 时,您的地图委托会照常运行。您可以侦听地图事件,但您无法侦听类型安全的聚类管理器事件。当用户点按标记、各个聚类项或聚类时,API 将触发 mapView:didTapMarker: 并将额外的聚类数据添加到 marker.userData 属性中。您可以使用 conformsToProtocol 检查用户点按的对象。

使用聚类管理器委托:如果您想要侦听聚类管理器上类型安全的事件,您必须实现 GMUClusterManagerDelegateGMSMapViewDelegate。通常,您需要在显示地图的视图控制器中实现这两种协议。然后,调用 clusterManager.setDelegate:mapDelegate: 以设置聚类管理器委托和地图委托,如下面的代码示例所示:

Swift

class ViewController: UIViewController, GMUClusterManagerDelegate, GMSMapViewDelegate {

  private var mapView: GMSMapView!
  private var clusterManager: GMUClusterManager!

  override func viewDidLoad() {
    super.viewDidLoad()

    // ... Rest of code omitted for easy reading.

    // Register self to listen to both GMUClusterManagerDelegate and
    // GMSMapViewDelegate events.
    clusterManager.setDelegate(self, mapDelegate: self)
  }

  // MARK: - GMUClusterManagerDelegate

  func clusterManager(clusterManager: GMUClusterManager, didTapCluster cluster: GMUCluster) {
    let newCamera = GMSCameraPosition.cameraWithTarget(cluster.position,
      zoom: mapView.camera.zoom + 1)
    let update = GMSCameraUpdate.setCamera(newCamera)
    mapView.moveCamera(update)
  }

  // MARK: - GMUMapViewDelegate

  func mapView(mapView: GMSMapView, didTapMarker marker: GMSMarker) -> Bool {
    if let poiItem = marker.userData as? POIItem {
      NSLog("Did tap marker for cluster item \(poiItem.name)")
    } else {
      NSLog("Did tap a normal marker")
    }
    return false
  }
}

Objective-C

@interface ViewController ()<GMUClusterManagerDelegate, GMSMapViewDelegate>
@end

@implementation ViewController {
  GMSMapView *_mapView;
  GMUClusterManager *_clusterManager;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  // ... Rest of code omitted for easy reading.

  // Register self to listen to both GMUClusterManagerDelegate and
  // GMSMapViewDelegate events.
  [_clusterManager setDelegate:self mapDelegate:self];
}

#pragma mark GMUClusterManagerDelegate

- (void)clusterManager:(GMUClusterManager *)clusterManager didTapCluster:(id<GMUCluster>)cluster {
  GMSCameraPosition *newCamera =
      [GMSCameraPosition cameraWithTarget:cluster.position zoom:_mapView.camera.zoom + 1];
  GMSCameraUpdate *update = [GMSCameraUpdate setCamera:newCamera];
  [_mapView moveCamera:update];
}

#pragma mark GMSMapViewDelegate

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
  POIItem *poiItem = marker.userData;
  if (poiItem != nil) {
    NSLog(@"Did tap marker for cluster item %@", poiItem.name);
  } else {
    NSLog(@"Did tap a normal marker");
  }
  return NO;
}

现在,聚类管理器将拦截您在 clusterManager 上实现的任何事件。它会将任何剩余事件转发到地图委托(如果提供)。请注意,标准标记的事件(即,不是由聚类渲染器生成的标记)将始终转发到地图委托。

使用 GMUClusterManagerDelegate 时,您可以侦听以下事件:

  • clusterManager:didTapCluster: 将在用户点按标记的聚类时调用。
  • clusterManager:didTapClusterItem: 将在用户点按各个聚类项(标记)时调用。

定制标记聚类

您可以为 GMUClusterRendererGMUClusterIconGeneratorGMUClusterAlgorithm 提供自定义实现。您可以将您的自定义实现建立在实用程序内容库中所含这些协议的示例实现,或者也可以通过实现协议的方式编码一个完全自定义实现。

发送以下问题的反馈:

此网页
Google Maps SDK for iOS
Google Maps SDK for iOS
需要帮助?请访问我们的支持页面