Agrega un mapa a tu app para iOS (Swift)

1. Antes de comenzar

En este codelab, aprenderás a usar Google Maps Platform para crear apps para iOS en Swift. Crearás una app para iOS que hace lo siguiente:

  • Carga el SDK de Maps para iOS y la Biblioteca de utilidades del SDK de Maps para iOS.
  • Muestra un mapa centrado en Sídney, Australia.
  • Muestra marcadores personalizados de 100 puntos alrededor de Sídney.
  • Implementa el agrupamiento de marcadores en clústeres.
  • Habilita la interacción del usuario a fin de que, cuando se presiona un marcador, se dibuje un círculo sobre el mapa y este vuelva a centrarse.

Mapa con marcadores en una app para iOS

Requisitos previos

  • Conocimientos básicos sobre el desarrollo en Swift y en iOS

Qué aprenderás

  • Cómo cargar el SDK de Maps para iOS y la Biblioteca de utilidades del SDK de Google Maps para iOS
  • Cómo cargar un mapa
  • Cómo usar marcadores, marcadores personalizados y agrupamiento de marcadores en clústeres
  • Cómo trabajar con el sistema de eventos del SDK de Maps para iOS a fin de permitir la interacción del usuario
  • Cómo controlar la cámara del mapa de forma programática
  • Cómo dibujar sobre el mapa

Otros requisitos

Para completar este codelab, necesitarás las siguientes cuentas, servicios y herramientas:

  • Xcode 12.0, o una versión superior, con un SDK objetivo de 12.0 o posterior
  • CocoaPods, que debe estar instalado
  • Una cuenta de Google Cloud Platform con la facturación habilitada (consulta el paso siguiente)
  • Un proyecto en Cloud Console con el SDK de Maps para iOS habilitado (consulta el paso siguiente)

2. Prepárate

Para este paso, debes habilitar el SDK de Maps para iOS.

Configura Google Maps Platform

Si todavía no tienes una cuenta de Google Cloud Platform y un proyecto con la facturación habilitada, consulta la guía Cómo comenzar a utilizar Google Maps Platform para crear una cuenta de facturación y un proyecto.

  1. En Cloud Console, haz clic en el menú desplegable del proyecto y selecciona el proyecto que deseas usar para este codelab.

  1. Habilita las API y los SDK de Google Maps Platform necesarios para este codelab en Google Cloud Marketplace. Para hacerlo, sigue los pasos que se indican en este video o esta documentación.
  2. Genera una clave de API en la página Credenciales de Cloud Console. Puedes seguir los pasos que se indican en este video o esta documentación. Todas las solicitudes a Google Maps Platform requieren una clave de API.

Guía de inicio rápido

Para que puedas comenzar lo más rápido posible, te ofrecemos un código inicial que te ayudará a seguir este codelab.

  1. Si tienes git instalado, clona el repositorio.
git clone https://github.com/googlemaps/codelab-maps-platform-101-swift.git

También puedes hacer clic en Obtener el código para descargar el código fuente.

  1. Después de descargar el código, abre el proyecto StarterApp en el directorio /starter. Este proyecto incluye la estructura de archivos básica que necesitas para completar el codelab. Todo lo que necesitas para este proyecto se encuentra en el directorio /starter/StarterApp.

Para ver toda la solución en ejecución, consulta el código completo en el directorio /solution/SolutionApp.

3. Cómo instalar el SDK de Maps para iOS

El primer paso para usar el SDK de Maps para iOS es instalar las dependencias necesarias. Este proceso consta de dos pasos. El primero es instalar el SDK de Maps para iOS y la Biblioteca de utilidades del SDK de Maps para iOS desde el administrador de dependencias de Cocoapods. El segundo es proporcionar tu clave de API al SDK.

  1. Agrega el SDK de Maps para iOS y la Biblioteca de utilidades del SDK de Maps para iOS a Podfile.

En este codelab, se usa el SDK de Maps para iOS, que proporciona todas las funcionalidades principales de Google Maps, y la Biblioteca de utilidades de Maps para iOS, que incluye una variedad de utilidades para enriquecer el mapa, incluido el agrupamiento de marcadores en clústeres.

Para comenzar, en Xcode (o tu editor de texto preferido) abre Podfile y actualiza el archivo a fin de incluir las dependencias del SDK de Maps para iOS y la Biblioteca de utilidades relacionada debajo del comentario # Pods for StarterApp:

pod 'GoogleMaps', '6.1.0'
pod 'Google-Maps-iOS-Utils', '3.4.0'

Consulta la documentación sobre las versiones del SDK de Maps para iOS a fin de conocer la versión más reciente del SDK y obtener orientación para el mantenimiento.

Tu Podfile debería tener el siguiente contenido:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'

target 'StarterApp' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for StarterApp
  pod 'GoogleMaps', '6.1.0'
  pod 'Google-Maps-iOS-Utils', '3.4.0'
end
  1. Instala los pods del SDK de Maps para iOS y la Biblioteca de utilidades de Maps para iOS.

A fin de instalar las dependencias, ejecuta pod install en el directorio /starter desde la línea de comandos. CocoaPods descarga automáticamente las dependencias y crea StarterApp.xcworkspace.

  1. Una vez que hayas instalado las dependencias, ejecuta open StarterApp.xcworkspace desde el directorio /starter para abrir el archivo en Xcode y, luego, presiona Command+R para ejecutar la app en el simulador de iPhone. Si todo está configurado correctamente, el simulador se iniciará y mostrará una pantalla negra. No te preocupes, está bien que así sea porque todavía no creaste ningún contenido.
  2. Importa el SDK en AppDelegate.swift.

Ahora que tus dependencias están instaladas, es momento de proporcionar tu clave de API al SDK. Primero, a fin de importar el SDK de Maps para iOS como una dependencia, coloca lo siguiente debajo de la sentencia de importación import UIKit:

import GoogleMaps
  1. A fin de pasar la clave de API al SDK para iOS, llama a provideAPIKey en GMSServices dentro de application: didFinishLaunchingWithOptions:
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // Override point for customization after application launch.
    GMSServices.provideAPIKey("YOUR_API_KEY")

    return true
  }

El archivo AppDelegate.swift actualizado ahora debería verse de la siguiente manera:

import UIKit
import GoogleMaps

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // Override point for customization after application launch.
    GMSServices.provideAPIKey("YOUR_API_KEY")

    return true
  }

}

Reemplaza YOUR_API_KEY por la clave de API que creaste en Cloud Console.

Ahora que tus dependencias están instaladas y proporcionaste tu clave de API, ya puedes comenzar a realizar llamadas al SDK de Maps para iOS.

4. Muestra un mapa

Es hora de mostrar tu primer mapa.

La parte más utilizada del SDK de Maps para iOS es la clase GMSMapView, que proporciona muchos de los métodos que te permiten crear y manipular instancias de mapas. A continuación, te indicamos cómo hacerlo.

  1. Abre ViewController.swift.

Aquí realizarás el resto del trabajo de este codelab. Notarás que los eventos de ciclo de vida loadView y viewDidLoad para el controlador de vista ya están incluidos como stubs.

  1. Agrega lo siguiente en la parte superior del archivo para importar el SDK de Maps para iOS:
import GoogleMaps
  1. Declara una variable de instancia de ViewController para almacenar GMSMapView.

La instancia de GMSMapView es el objeto principal con el que trabajarás en todo este codelab. Harás referencia a él y realizarás acciones que lo afectan desde diferentes métodos del ciclo de vida del controlador de vista. Para que esté disponible, actualiza la implementación de ViewController a fin de declarar una variable de instancia en la cual almacenarlo:

class ViewController: UIViewController {

  private var mapView: GMSMapView!

  ...
}
  1. En loadView, crea una instancia de GMSCameraPosition.

GMSCameraPosition define el lugar en el que se centrará el mapa y el nivel de zoom con el que se mostrará. Este código llama al método cameraWithLatitude:longitude:zoom: para centrar el mapa en Sídney, Australia, en una latitud de -33.86 y una longitud de 151.20, con un nivel de zoom de 12:

let camera:GMSCameraPosition = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 12)
  1. En loadView, genera una instancia de GMSMapView a fin de crear una instancia del mapa.

Llama a GMSMapView(frame: CGRect, camera: GMSCameraPosition) para crear esa instancia de mapa. Observa cómo el marco se establece en CGRect.zero, que es una variable global de la biblioteca CGGeometry de iOS que especifica un marco con ancho y altura iguales a 0, ubicado en la posición (0,0) dentro del controlador de vista. La cámara toma la posición que le acabas de establecer.

A continuación, para ver el mapa, establece la vista raíz del controlador de vista en mapView, lo cual hará que se muestre en pantalla completa.

    mapView = GMSMapView(frame: .zero, camera: camera)
    self.view = mapView
  1. Configura GMSMapViewDelegate en el controlador de vista.

Una vez implementado, el delegado de la vista de mapa te permite controlar eventos de las interacciones de usuarios en la instancia de GMSMapView, los cuales necesitarás en pasos posteriores.

Primero, actualiza la interfaz de ViewController a fin de cumplir con el protocolo para GMSMapViewDelegate:

class ViewController: UIViewController, GMSMapViewDelegate

A continuación, agrega esto en la función loadView para establecer GMSMapViewDelegate en ViewController.

    mapView.delegate = self

Ahora, vuelve a cargar la app en el simulador de iOS (Command+R); el mapa debería aparecer tal como se muestra en la Figura 1.

App para iOS que muestra un mapa de Google

Figura 1. App para iOS que muestra un mapa de Google

En resumen, en este paso creaste una instancia de GMSMapView para mostrar un mapa centrado en la ciudad de Sídney, Australia.

Tu archivo ViewController.swift ahora debería verse de la siguiente manera:

import UIKit
import GoogleMaps

class ViewController: UIViewController, GMSMapViewDelegate {

  private var mapView: GMSMapView!

  override func loadView() {

    // Load the map at set latitude/longitude and zoom level
    let camera:GMSCameraPosition = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 11)

    mapView = GMSMapView(frame: .zero, camera: camera)
    self.view = mapView
    mapView.delegate = self
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
  }

}

5. Aplica estilo al mapa (opcional)

Puedes personalizar el estilo de tu mapa con el diseño de mapas basado en Cloud.

Crea un ID de mapa

Si todavía no creaste un ID de mapa con un estilo de mapa asociado, consulta la guía sobre ID de mapa para completar los siguientes pasos:

  1. Crear un ID de mapa
  2. Asociar un ID de mapa a un estilo de mapa

Cómo agregar el ID de mapa a tu app

Para usar el ID de mapa que creaste en el paso anterior, abre el archivo ViewController.swift y, dentro del método loadView, crea un objeto GMSMapID y proporciónale el ID de mapa. Luego, modifica la instanciación de GMSMapView proporcionando el objeto GMSMapID como parámetro.

ViewController.swift

  override func loadView() {

    // Load the map at set latitude/longitude and zoom level
    let camera:GMSCameraPosition = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 11)
    let mapID = GMSMapID(identifier: "YOUR_MAP_ID")

    mapView = GMSMapView(frame: .zero, mapID: mapID, camera: camera)
    self.view = mapView
    mapView.delegate = self
  }

Una vez que completes esto, ejecuta la app para ver tu mapa con el estilo que seleccionaste.

6. Agrega marcadores al mapa

Hay muchas acciones que los desarrolladores realizan con el SDK de Maps para iOS, pero colocar marcadores en el mapa es definitivamente la más popular. Los marcadores muestran puntos específicos en el mapa y son elementos de la IU comunes para controlar la interacción del usuario. Si ya usaste Google Maps, es probable que conozcas el marcador predeterminado, que es el que se ve como un pin rojo en la Figura 2:

Mapa con marcadores rojos

Figura 2. Mapa con marcadores rojos

En este paso, se demuestra cómo usar la clase GMSMarker para colocar marcadores en el mapa.

Ten en cuenta que los marcadores solo se pueden colocar en el mapa una vez que este se haya cargado en el paso anterior, en el evento de ciclo de vida loadView del controlador de vista. Por eso, completa estos pasos en el evento de ciclo de vida viewDidLoad, al cual se llama después de que se hayan cargado la vista y el mapa.

  1. Define un objeto CLLocationCoordinate2D.

CLLocationCoordinate2D es una estructura que está disponible mediante la biblioteca CoreLocation de iOS, la cual define una ubicación geográfica a partir de la latitud y longitud que se establezcan. Para comenzar a crear tu primer marcador, define un objeto CLLocationCoordinate2D y establece la latitud y longitud correspondientes al centro del mapa. Puedes utilizar las propiedades camera.target.latitude y camera.target.longitude para acceder a las coordenadas del centro del mapa desde la vista de mapa.

    // Add a single marker with a custom icon
    let mapCenter = CLLocationCoordinate2DMake(mapView.camera.target.latitude, mapView.camera.target.longitude)
  1. Crea una instancia de GMSMarker.

El SDK de Maps para iOS proporciona la clase GMSMarker. Cada instancia de GMSMarker representa un marcador individual en el mapa. Para crear este marcador, se llama a markerWithPosition: y se le pasa un objeto CLLocationCoordinate2D para indicarle al SDK dónde colocarlo en el mapa

    let marker = GMSMarker(position: mapCenter)
  1. Establece un ícono de marcador personalizado.

El marcador con forma de pin de color rojo predeterminado de Google Maps es genial, pero también lo es un mapa personalizado. Afortunadamente, es muy sencillo usar marcadores personalizados con el SDK de Maps para iOS. Observa que el proyecto StarterApp incluye una imagen llamada "custom_pin.png" para que uses. Si lo deseas, puedes utilizar cualquier otra.

Para establecer el marcador personalizado, configura la propiedad icon del marcador en una instancia de UIImage.

    marker.icon = UIImage(named: "custom_pin.png")
  1. Renderiza el marcador en el mapa.

Se creó tu marcador, pero todavía no está en el mapa. Para ello, configura la propiedad map de la instancia de GMSMarker en una instancia de GMSMapView.

    marker.map = mapView

Ahora, vuelve a cargar la app y verás tu primer mapa con un marcador, como se muestra en la Figura 3.

App para iOS que muestra un mapa de Google Maps con un marcador rojo en el centro

Figura 3. App para iOS con Google Maps y un marcador rojo en el centro

En resumen, en esta sección creaste una instancia de la clase GMSMarker y la aplicaste a la vista de mapa para mostrar un marcador. El evento de ciclo de vida actualizado viewDidLoad en ViewController.swift debería verse de la siguiente manera:

  override func viewDidLoad() {
    super.viewDidLoad()

    // Add a single marker with a custom icon
    let mapCenter = CLLocationCoordinate2DMake(mapView.camera.target.latitude, mapView.camera.target.longitude)
    let marker = GMSMarker(position: mapCenter)

    marker.icon = UIImage(named: "custom_pin.png")
    marker.map = mapView
  }

7. Habilita el agrupamiento de marcadores en clústeres

Si usas muchos marcadores o marcadores que están muy cerca entre ellos, puedes encontrarte con el problema de que se superpongan o se vean demasiado juntos, lo que generará una mala experiencia del usuario. Por ejemplo, si hay dos marcadores que están muy cerca, podrías tener una situación como la que se ve en la Figura 4:

Dos marcadores que están muy cerca entre sí

Figura 4. Dos marcadores que están muy cerca entre sí

Para casos como este resulta útil el agrupamiento de marcadores en clústeres. El agrupamiento de marcadores en clústeres es otra una función que se utiliza comúnmente a fin de agrupar los marcadores cercanos en un mismo ícono que cambia según el nivel de zoom tal como se muestra en la Figura 5:

Ejemplo de marcadores agrupados en clústeres en un solo ícono

Figura 5. Ejemplo de marcadores agrupados en clústeres en un solo ícono

El algoritmo utilizado para el agrupamiento de marcadores en clústeres divide el área visible del mapa en una cuadrícula y, luego, agrupa los íconos que se encuentran en la misma celda. El equipo de Google Maps Platform creó una herramienta de código abierto muy útil llamada Biblioteca de utilidades del SDK de Google Maps para iOS. Entre muchas otras cosas, esta biblioteca administra automáticamente el agrupamiento de marcadores en clústeres por ti. Puedes obtener más información sobre el agrupamiento de marcadores en clústeres en la documentación de Google Maps Platform. También puedes consultar el código fuente de la Biblioteca de utilidades para iOS en GitHub.

  1. Agrega muchos marcadores más al mapa.

Para ver el agrupamiento de marcadores en clústeres en la práctica, tu mapa tiene que tener muchos. A fin de facilitar este proceso, el proyecto inicial incluye un conveniente generador de marcadores en MarkerGenerator.swift.

Para agregar una cantidad específica de marcadores a tu mapa, llama a MarkerGenerator(near:count:).markerArray en el ciclo de vida de viewDidLoad del controlador de vista debajo del código del paso anterior. Este método crea la cantidad de marcadores especificados en count en ubicaciones aleatorias alrededor de las coordenadas especificadas en un objeto CLLocationCoordinate2D. En este caso, simplemente puedes pasarle la variable mapCenter que creaste antes. Los marcadores se muestran en un [GMSMarker].

    // Generate many markers
    let markerArray = MarkerGenerator(near: mapCenter, count: 100).markerArray

Para probar cómo se ven estos marcadores, agrega estas líneas después de la definición de markerArray y, luego, ejecuta la app. Asegúrate de comentar estas líneas antes de continuar con los pasos siguientes, que usan el agrupador de marcadores para administrar la visualización de los marcadores:

    // Comment the following code out if using the marker clusterer
    // to manage markers instead.
    for marker in markerArray {
      marker.map = mapView
    }
  1. Importa la Biblioteca de utilidades del SDK de Google Maps para iOS.

Para agregar la biblioteca de utilidades de Maps para iOS como dependencia a tu proyecto, incluye lo siguiente en la lista de dependencias, en la parte superior de ViewController.swift:

import GoogleMapsUtils
  1. Configura el agrupador de marcadores en clústeres.

Para usar este agrupador, debes proporcionar tres elementos a fin de configurar su funcionamiento: un algoritmo de agrupamiento en clústeres, un generador de íconos y un renderizador. El algoritmo determina el comportamiento que define la forma en que se agrupan los marcadores, como la distancia entre los marcadores que se incluirán en el mismo clúster. El generador de íconos proporciona los íconos de clúster que se usarán en los diferentes niveles de zoom. El renderizador controla la renderización real de los íconos de clúster en el mapa.

Si lo prefieres, puedes escribir todos estos elementos desde cero, pero la biblioteca de utilidades de Maps para iOS proporciona implementaciones predeterminadas para facilitar el proceso. Agrega lo siguiente:

    // Set up the cluster manager with a supplied icon generator and renderer.
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    let iconGenerator = GMUDefaultClusterIconGenerator()
    let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator)
  1. Crea una instancia de GMUClusterManager.

GMUClusterManager es la clase que implementa el agrupamiento de marcadores en clústeres con el algoritmo, el generador de íconos y el renderizador que especificaste. Si deseas crear el renderizador y hacer que esté disponible para la vista de mapa, primero agrega una variable de instancia a la implementación de ViewController para almacenar la instancia del administrador de clústeres:

class ViewController: UIViewController, GMSMapViewDelegate {

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

A continuación, crea la instancia de GMUClusterManager en el evento de ciclo de vida viewDidLoad:

    clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer)
  1. Agrega los marcadores y ejecuta el agrupador de marcadores en clústeres.

Ahora que ya configuraste tu instancia del agrupador, pásale al administrador de clústeres el array de marcadores que se agruparán mediante una llamada a add(items:). Luego, llama a cluster para ejecutar el agrupador.

    clusterManager.setMapDelegate(self)
    clusterManager.add(markerArray)
    clusterManager.cluster()

Vuelve a cargar la app. Ahora deberías ver muchos marcadores, todos correctamente agrupados, como el ejemplo de la Figura 6. Puedes pellizcar la pantalla y acercar o alejar el mapa con diferentes niveles de zoom a fin de ver cómo se adaptan los clústeres de marcadores a estas acciones.

App para iOS con Google Maps y marcadores agrupados en clústeres

Figura 6. App para iOS con Google Maps y marcadores agrupados en clústeres

En resumen, en este paso configuraste una instancia del agrupador de marcadores en clústeres de la Biblioteca de utilidades del SDK de Google Maps para iOS y, luego, la usaste para agrupar 100 marcadores en el mapa. El evento de ciclo de vida viewDidLoad en ViewController.swift debería verse de la siguiente manera:

  override func viewDidLoad() {
    super.viewDidLoad()

    // Add a single marker with a custom icon
    let mapCenter = CLLocationCoordinate2DMake(mapView.camera.target.latitude, mapView.camera.target.longitude)
    let marker = GMSMarker(position: mapCenter)

    marker.icon = UIImage(named: "custom_pin.png")
    marker.map = mapView

    // Generate many markers
    let markerArray = MarkerGenerator(near: mapCenter, count: 100).markerArray
    // Comment the following code out if using the marker clusterer
    // to manage markers instead.
    //    for marker in markerArray {
    //      marker.map = mapView
    //    }

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

    clusterManager.setMapDelegate(self)
    clusterManager.add(markerArray)
    clusterManager.cluster()
  }

8. Agrega interacción del usuario

Ahora tienes un excelente mapa que muestra marcadores y los agrupa en clústeres. En este paso, agregarás algunas acciones para controlar las interacciones del usuario mediante GMSMapViewDelegate, que configuraste con el controlador de vista anteriormente, a fin de mejorar la experiencia del usuario en tu mapa.

El SDK de Maps para iOS proporciona un sistema de eventos completo. Este se implementa a través del delegado de vista de mapa, el cual incluye controladores de eventos que te permiten ejecutar código cuando se producen varias interacciones del usuario. Por ejemplo, el delegado de MapView incluye métodos que te permiten activar la ejecución del código para interacciones tales como cuando el usuario hace clic en el mapa y los marcadores, desplaza lateralmente la vista del mapa, acerca y aleja el mapa, y mucho más.

En este paso, te desplazas lateralmente de manera programática por el mapa para centrar el marcador en el que presiona el usuario.

  1. Implementa un objeto de escucha que se activa cuando se presiona un marcador.

Se llama a mapView(_:didTap:) cada vez que el usuario presiona uno de los marcadores que creaste anteriormente así como cada vez que presiona un clúster de marcadores (de forma interna, los clústeres de marcadores se implementan como una instancia de GMSMarker).

Para implementar el objeto de escucha de eventos, primero hazlo en forma de stub al final de ViewController.swift, antes de la llave de cierre.

  func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    return false
  }

Notarás que el método devuelve false. Esto le indica al SDK para iOS que siga ejecutando la funcionalidad de GMSMarker predeterminada, como mostrar una ventana de información (si está configurada) después de ejecutar el código de tu controlador de eventos.

  1. Establece un control para el evento de presión y anima la cámara para que el mapa vuelva a centrarse cuando se presione un marcador o un clúster de marcadores.

Cuando se llama a mapView(_:didTap:), se pasa la instancia del GMSMarker que se presionó, lo que te permite controlarla en tu código. Puedes usar esta instancia para volver a centrar el mapa mediante una llamada a animate(toLocation:) en la vista de mapa desde el controlador de eventos. Debes pasarle la posición de la instancia del marcador de la propiedad position.

    // Animate to the marker
    mapView.animate(toLocation: marker.position)
  1. Acerca la imagen de un clúster de marcadores cuando se lo presiona.

Un patrón común de UX es acercar la imagen de los clústeres de marcadores cuando se los presiona. Esto permite que los usuarios vean los marcadores que están agrupados en el clúster, ya que este se expandirá en los niveles de zoom más bajos.

Como se señaló antes, el ícono del clúster de marcadores es solo una implementación de GMSMarker con un ícono personalizado. ¿Cómo puedes saber si se presionó un marcador o un clúster de marcadores? Cuando el administrador de clústeres de marcadores crea un nuevo ícono de clúster, implementa la instancia de GMSMarker de manera tal que cumpla con un protocolo llamado GMUCluster.. Puedes usar un condicional para verificar si el marcador que se pasó al controlador de eventos cumple con este protocolo.

Una vez que sepas de forma programática que se presionó un clúster, podrás llamar a animate(toZoom:) en la instancia de vista de mapa y establecer que el zoom sea el nivel de zoom actual más uno. El nivel de zoom actual se encuentra disponible en la instancia de vista de mapa, en la propiedad camera.zoom.

Además, observa que el siguiente código devuelve true. Esto le indica al controlador del evento que finalizó el control del evento y que no debe ejecutar ningún código adicional del controlador. Esto se hace, por ejemplo, para evitar que el objeto GMSMarker subyacente ejecute el resto de su comportamiento predeterminado, como mostrar una ventana de información, lo cual no tendría mucho sentido cuando se presiona un ícono de clúster.

    // If the tap was on a marker cluster, zoom in on the cluster
    if let _ = marker.userData as? GMUCluster {
      mapView.animate(toZoom: mapView.camera.zoom + 1)
      return true
    }

Ahora vuelve a cargar la app y presiona algunos marcadores y clústeres de marcadores. En ambos casos, el mapa se volverá a centrar en el elemento seleccionado. Cuando se presione un clúster de marcadores, el mapa también se acercará un nivel y el clúster de marcadores se expandirá para mostrar los que están agrupados debajo.

En resumen, en este paso, implementaste un objeto de escucha que se activa cuando se presiona un marcador, controlaste el evento para que el mapa se volviera a centrar sobre el elemento presionado e hiciste que la imagen se acercara si ese elemento es un ícono de clúster de marcadores.

El método mapView(_:didTap:) debería verse de la siguiente manera:

  func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    // Animate to the marker
    mapView.animate(toLocation: marker.position)

    // If the tap was on a marker cluster, zoom in on the cluster
    if let _ = marker.userData as? GMUCluster {
      mapView.animate(toZoom: mapView.camera.zoom + 1)
      return true
    }

    return false
  }

9. Dibuja en el mapa

Hasta ahora, creaste un mapa de Sídney que muestra marcadores en 100 puntos aleatorios y controla la interacción del usuario. En el último paso de este codelab, usarás las funciones de dibujo del SDK de Maps para iOS a fin de agregar una característica útil adicional a la experiencia de tu mapa.

Imagina que a este mapa lo utilizarán usuarios que desean explorar la ciudad de Sídney. Una función útil sería visualizar un radio alrededor de un marcador cuando se hace clic en él. Esto permitiría que el usuario vea rápidamente qué otros destinos están muy cerca del marcador en el que hizo clic, a los cuales puede llegar fácilmente a pie.

El SDK para iOS incluye un conjunto de funciones para dibujar formas sobre el mapa, como cuadrados, polígonos, líneas y círculos. En este paso, renderizarás un círculo para mostrar un radio de 800 metros (aproximadamente media milla) alrededor de un marcador cuando se hace clic en él.

  1. Agrega una variable de instancia de circle a la implementación de ViewController.

Esta variable de instancia se usará para guardar el último círculo dibujado, de manera que pueda destruirse antes de que se dibuje otro. Después de todo, no sería muy útil para el usuario y no sería efectivo visualmente si todos los marcadores que se presionaron tuvieran un círculo alrededor.

Para ello, actualiza la implementación de ViewController de la siguiente manera:

class ViewController: UIViewController, GMSMapViewDelegate {

  private var mapView: GMSMapView!
  private var clusterManager: GMUClusterManager!
  private var circle: GMSCircle? = nil
  ...
}
  1. Dibuja el círculo cuando se presiona un marcador.

En la parte inferior del método mapView(_:didTap:), justo encima de la sentencia return false agrega el siguiente código a fin de crear una instancia de la clase GMSCircle del SDK para iOS que dibuje un nuevo círculo de radio de 800 metros. Para eso, llama a GMSCircle(position:radius:) y pásale la posición del marcador presionado, tal como lo hiciste antes a fin de volver a centrar el mapa.

    // Draw a new circle around the tapped marker
    circle = GMSCircle(position: marker.position, radius: 800)
  1. Elige un estilo para el círculo.

De forma predeterminada, GMSCircle dibuja un círculo con un trazo negro y un relleno transparente. Eso funciona para mostrar el radio, pero visualmente no es muy atractivo y es un poco difícil de ver. A continuación, asigna un parámetro UIColor a la propiedad fillColor del círculo para definirle un color de relleno a fin de mejorar su estilo. El código que se muestra aquí agrega un relleno gris con una transparencia del 50%:

    circle?.fillColor = UIColor(red: 0.67, green: 0.67, blue: 0.67, alpha: 0.5)
  1. Renderiza el círculo en el mapa.

Del mismo modo que cuando creaste marcadores antes, notarás que tan solo crear una instancia de GMSCircle no hace que este aparezca en el mapa. Para que se vea, asigna la instancia de vista de mapa a la propiedad map del círculo.

    circle?.map = mapView
  1. Quita los círculos renderizados anteriormente.

Tal como se mencionó antes, no brindaríamos una buena experiencia del usuario si siguiésemos agregando círculos al mapa. Para eliminar el círculo renderizado por un evento de presión anterior, establece la propiedad map de circle en nil, en la parte superior de mapView(_:didTap:).

    // Clear previous circles
    circle?.map = nil

Vuelve a cargar la app y presiona un marcador. Deberías ver que, cada vez que se presiona un marcador, aparece un círculo nuevo y se quita cualquier círculo que se haya renderizado anteriormente, tal como se muestra en la Figura 7.

Un círculo dibujado alrededor del marcador presionado

Figura 7. Un círculo dibujado alrededor del marcador presionado

En resumen, en este paso usaste la clase GMSCircle para renderizar un círculo cada vez que se presiona un marcador.

El método mapView(_:didTap:) debería verse de la siguiente manera:

  func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    // Clear previous circles
    circle?.map = nil

    // Animate to the marker
    mapView.animate(toLocation: marker.position)

    // If the tap was on a marker cluster, zoom in on the cluster
    if let _ = marker.userData as? GMUCluster {
      mapView.animate(toZoom: mapView.camera.zoom + 1)
      return true
    }

    // Draw a new circle around the tapped marker
    circle = GMSCircle(position: marker.position, radius: 800)
    circle?.fillColor = UIColor(red: 0.67, green: 0.67, blue: 0.67, alpha: 0.5)
    circle?.map = mapView
    return false
  }

10. Felicitaciones

Creaste correctamente una app para iOS con un mapa de Google interactivo.

Lo que aprendiste

¿Qué sigue?

  • Explora o bifurca el repositorio de muestras y demostraciones de maps-sdk-for-ios-samples en GitHub para obtener más inspiración.
  • Aprende con más codelabs de Swift que te permitirán crear apps para iOS con Google Maps Platform.
  • Responde la siguiente pregunta para ayudarnos a crear el contenido que te resultaría más útil:

¿Qué otros codelabs te gustaría ver?

Visualización de datos en mapas Más información sobre cómo personalizar el estilo de mis mapas Creación de interacciones 3D en los mapas

¿El codelab que quieres no figura arriba? Crea un nuevo problema aquí para solicitarlo.