Adicionar um mapa ao seu app iOS com o SwiftUI (Swift)

1. Antes de começar

Este codelab ensina como usar o SDK do Maps para iOS com o SwiftUI.

screenshot-iphone-12-black@2x.png

Pré-requisitos

  • Conhecimento básico de Swift
  • Noções básicas de SwiftUI

Atividades deste codelab

  • Ativar e usar o SDK do Maps para iOS para adicionar o Google Maps a um app iOS usando o SwiftUI
  • Adicionar marcadores ao mapa
  • Transmitir o estado de uma visualização do SwiftUI para um objeto GMSMapView e vice-versa.

Pré-requisitos

2. Começar a configuração

Para a etapa a seguir, ative o SDK do Maps para iOS.

Configurar a Plataforma Google Maps

Caso você ainda não tenha uma conta do Google Cloud Platform e um projeto com faturamento ativado, veja como criá-los no guia Primeiros passos com a Plataforma Google Maps.

  1. No Console do Cloud, clique no menu suspenso do projeto e selecione o projeto que você quer usar neste codelab.

  1. Ative as APIs e os SDKs da Plataforma Google Maps necessários para este codelab no Google Cloud Marketplace. Para fazer isso, siga as etapas descritas neste vídeo ou nesta documentação.
  2. Gere uma chave de API na página Credenciais do Console do Cloud. Siga as etapas indicadas neste vídeo ou nesta documentação. Todas as solicitações à Plataforma Google Maps exigem uma chave de API.

3. Fazer o download do código inicial

Veja aqui o código inicial para ajudar você a acompanhar este codelab e começar o mais rápido possível. Se preferir, você pode ir direto para a solução, mas continue lendo se quiser desenvolver por conta própria.

  1. Clone o repositório se você tiver o git instalado.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git

Se preferir, clique no botão a seguir para fazer o download do código-fonte.

  1. Ao receber o código, abra um terminal cd no diretório starter/GoogleMapsSwiftUI.
  2. Execute carthage update --platform iOS para fazer o download do SDK do Maps para iOS.
  3. Por fim, abra o arquivo GoogleMapsSwiftUI.xcodeproj no Xcode.

4. Visão geral do código

No projeto inicial que você salvou, as seguintes classes foram incluídas e implementadas para você:

  • AppDelegate: o UIApplicationDelegate do aplicativo. É aqui que o SDK do Maps para iOS será inicializado.
  • City: uma struct que representa uma cidade (contém um nome e uma coordenada da cidade).
  • MapViewController: um UIKit UIViewController simples contendo um mapa do Google Map (GMSMapView).
  • SceneDelegate: o UIWindowSceneDelegate do aplicativo a partir do qual ContentView é instanciado.

Além disso, as seguintes classes têm implementações parciais que serão concluídas ao final deste codelab:

  • ContentView: a visualização de nível superior do SwiftUI contendo seu app.
  • MapViewControllerBridge: uma classe que cria uma ponte entre uma visualização do UIKit e uma visualização do SwiftUI. Especificamente, essa é a classe que tornará o MapViewController acessível no SwiftUI.

5. Diferenças entre SwiftUI e UIKit

O SwiftUI foi introduzido no iOS 13 como uma alternativa ao UIKit, um framework de UI para desenvolvimento de aplicativos iOS. Em comparação com o UIKit, seu antecessor, o SwiftUI oferece várias vantagens. Para citar alguns:

  • As visualizações são atualizadas automaticamente quando o estado muda. Usando objetos chamados State, qualquer alteração no valor contido fará com que a IU seja atualizada automaticamente.
  • As visualizações em tempo real permitem um desenvolvimento mais rápido. Elas minimizam a necessidade de criar e implantar código em um emulador para gerar alterações visuais, já que uma pré-visualização do SwiftUI pode ser exibida prontamente no Xcode.
  • A fonte da verdade está em Swift. Todas as visualizações no SwiftUI são declaradas em Swift. Portanto, o uso do Interface Builder não é mais necessário.
  • Funciona com o UIKit. A interoperabilidade com o UIKit garante que os apps existentes possam usar o SwiftUI de maneira incremental com as visualizações existentes. Além disso, bibliotecas que ainda não são compatíveis com o SwiftUI, como o SDK do Maps para iOS, podem ser usadas mesmo assim.

Mas também há desvantagens:

  • O SwiftUI só está disponível no iOS 13 ou posterior.
  • A hierarquia de visualização não pode ser examinada em prévias do Xcode.

Estado e fluxo de dados no SwiftUI

O SwiftUI oferece uma nova maneira de criar IU usando uma abordagem declarativa. Você diz a ele como quer exibir a visualização com todos os diferentes estados, e o sistema fará o resto. O SwiftUI atualiza a visualização sempre que o estado contido muda devido a um evento ou uma ação do usuário. Isso é comumente chamado de fluxo de dados unidirecional. Embora as especificidades desse design estejam fora do escopo deste codelab, recomendamos ler mais sobre como isso funciona na documentação de Estado e fluxo de dados da Apple.

Ponte entre o UIKit e o SwiftUI usando UIViewRepresentable ou UIViewControllerRepresentable

Como o SDK do Maps para iOS é criado com base no UIKit e ainda não oferece uma visualização compatível com o SwiftUI, usá-lo no SwiftUI exige conformidade com UIViewRepresentable ou UIViewControllerRepresentable. Esses protocolos permitem que o SwiftUI inclua UIViews e UIViewControllers criados no UIKit, respectivamente. Você pode usar qualquer um deles para adicionar um mapa do Google Maps a uma visualização do SwiftUI, mas na próxima etapa veremos especificamente como usar UIViewControllerRepresentable para incluir um UIViewController contendo um mapa.

6. Adicionar um mapa

Nesta seção, você irá adicionar o Google Maps a uma visualização do SwiftUI.

add-a-map-screenshot@2x.png

Adicionar sua chave de API

A chave de API que você criou em uma etapa anterior precisa ser informada ao SDK do Maps para iOS para associar sua conta ao mapa que será exibido no app.

Para inserir sua chave de API, abra o arquivo AppDelegate.swift e navegue até o método application(_, didFinishLaunchingWithOptions). No momento, o SDK é inicializado usando GMSServices.provideAPIKey() com a string "YOUR_API_KEY". Substitua-a pela sua chave de API. Ao concluir essa etapa, o SDK do Maps para iOS será inicializado quando o aplicativo for iniciado.

Adicionar um mapa do Google Maps usando MapViewControllerBridge

Agora que sua chave de API está sendo informada ao SDK, a próxima etapa é exibir o mapa no app.

O controlador de visualizações MapViewController, incluído no código inicial, contém um GMSMapView na visualização. No entanto, como esse controlador foi criado no UIKit, será necessário fazer uma ponte dessa classe para o SwiftUI para que ela possa ser usada no ContentView. Basta seguir estas etapas:

  1. Abra o arquivo MapViewControllerBridge no Xcode.

Essa classe está em conformidade com o UIViewControllerRepresentable, que é o protocolo necessário para fazer um wrap do UIViewController do UIKit para ser usado como uma visualização do SwiftUI. Em outras palavras, obedecer a esse protocolo permite fazer uma ponte de uma visualização do UIKit para uma visualização do SwiftUI. A conformidade com esse protocolo exige a implementação de dois métodos:

  • makeUIViewController(context): esse método é chamado pelo SwiftUI para criar o UIViewController subjacente. É aqui que você iria instanciar seuUIViewController e transmitir a ele o estado inicial.
  • updateUIViewController(_, context): esse método é chamado pelo SwiftUI sempre que o estado muda. É aqui que você faria qualquer modificação no UIViewController subjacente para reagir em resposta à mudança de estado.
  1. Crie um MapViewController.

Dentro da função makeUIViewController(context), instancie um novo MapViewController e retorne-o como resultado. Depois disso, seu MapViewControllerBridge ficará assim:

MapViewControllerBridge

import GoogleMaps
import SwiftUI

struct MapViewControllerBridge: UIViewControllerRepresentable {

  func makeUIViewController(context: Context) -> MapViewController {
    return MapViewController()
  }

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
  }
}

Usar MapViewControllerBridge no ContentView

Agora que o MapViewControllerBridge está criando uma instância do MapViewController, a próxima etapa é usar essa struct dentro do ContentView para exibir um mapa.

  1. Abra o arquivo ContentView no Xcode.

O ContentView é instanciado no SceneDelegate e contém a visualização de nível superior do aplicativo. O mapa será adicionado de dentro deste arquivo.

  1. Crie um MapViewControllerBridge dentro da propriedade body.

Dentro da propriedade body desse arquivo, um ZStack já foi incluído e implementado. No momento, o ZStack contém uma lista de cidades interativa e arrastável que você vai usar em uma etapa posterior. Por enquanto, dentro do ZStack, crie um MapViewControllerBridge como a primeira visualização filha do ZStack para que um mapa seja exibido no app atrás da lista de cidades. Depois disso, o conteúdo da propriedade body dentro do ContentView ficará assim:

ContentView

var body: some View {

  let scrollViewHeight: CGFloat = 80

  GeometryReader { geometry in
    ZStack(alignment: .top) {
      // Map
      MapViewControllerBridge()

      // Cities List
      CitiesList(markers: $markers) { (marker) in
        guard self.selectedMarker != marker else { return }
        self.selectedMarker = marker
        self.zoomInCenter = false
        self.expandList = false
      }  handleAction: {
        self.expandList.toggle()
      } // ...
    }
  }
}
  1. Agora, execute o app. Você verá o mapa ser carregado na tela do dispositivo com uma lista arrastável de cidades na parte inferior da tela.

7. Adicionar marcadores ao mapa

Na etapa anterior, você adicionou um mapa com uma lista interativa de cidades. Nesta seção, você irá adicionar marcadores a cada cidade da lista.

map-with-markers@2x.png

Marcadores como estado

No momento, o ContentView declara uma propriedade chamada markers, que é uma lista do GMSMarker que representa cada cidade declarada na propriedade estática cities. Essa propriedade é anotada com o wrapper de propriedade do SwiftUI State para indicar que ela deve ser gerenciada pelo SwiftUI. Portanto, se forem detectadas alterações nessa propriedade, como adição ou remoção de um marcador, as visualizações que usarem esse estado serão atualizadas.

ContentView

  static let cities = [
    City(name: "San Francisco", coordinate: CLLocationCoordinate2D(latitude: 37.7576, longitude: -122.4194)),
    City(name: "Seattle", coordinate: CLLocationCoordinate2D(latitude: 47.6131742, longitude: -122.4824903)),
    City(name: "Singapore", coordinate: CLLocationCoordinate2D(latitude: 1.3440852, longitude: 103.6836164)),
    City(name: "Sydney", coordinate: CLLocationCoordinate2D(latitude: -33.8473552, longitude: 150.6511076)),
    City(name: "Tokyo", coordinate: CLLocationCoordinate2D(latitude: 35.6684411, longitude: 139.6004407))
  ]

  /// State for markers displayed on the map for each city in `cities`
  @State var markers: [GMSMarker] = cities.map {
    let marker = GMSMarker(position: $0.coordinate)
    marker.title = $0.name
    return marker
  }

Observe que o ContentView usa a propriedade markers para renderizar a lista de cidades transmitindo-a para a classe CitiesList.

CitiesList

struct CitiesList: View {

  @Binding var markers: [GMSMarker]

  var body: some View {
    GeometryReader { geometry in
      VStack(spacing: 0) {
        // ...
        // List of Cities
        List {
          ForEach(0..<self.markers.count) { id in
            let marker = self.markers[id]
            Button(action: {
              buttonAction(marker)
            }) {
              Text(marker.title ?? "")
            }
          }
        }.frame(maxWidth: .infinity)
      }
    }
  }
}

Transmitir estado para MapViewControllerBridge por Binding

Além da lista de cidades que exibem dados da propriedade markers, transmita essa propriedade para a struct MapViewControllerBridge para que ela possa ser usada para exibir esses marcadores no mapa. Para fazer isso, siga estas etapas:

  1. Declare uma nova propriedade markers dentro do MapViewControllerBridge anotada com @Binding.

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. No MapViewControllerBridge, atualize o método updateUIViewController(_, context) para usar a propriedade markers.

Como mencionado na etapa anterior, o updateUIViewController(_, context) será chamado pelo SwiftUI sempre que o estado mudar. É dentro desse método que queremos atualizar o mapa, então exiba os marcadores em markers. Para fazer isso, você precisará atualizar a propriedade map de cada marcador. Depois de concluir essa etapa, o MapViewControllerBridge ficará assim:

import GoogleMaps
import SwiftUI

struct MapViewControllerBridge: UIViewControllerRepresentable {

  @Binding var markers: [GMSMarker]

  func makeUIViewController(context: Context) -> MapViewController {
    return MapViewController()
  }

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
    // Update the map for each marker
    markers.forEach { $0.map = uiViewController.map }
  }
}
  1. Transmita a propriedade markers do ContentView para o MapViewControllerBridge

Como você adicionou uma nova propriedade no MapViewControllerBridge, agora é necessário que o valor dela seja transmitido no inicializador para o MapViewControllerBridge. Portanto, se você tentar criar o app, perceberá que ele não será compilado. Para corrigir isso, atualize o ContentView onde o MapViewControllerBridge é criado e transmita a propriedade markers da seguinte maneira:

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers)
        // ...
      }
    }
  }
}

O prefixo $ foi usado para transmitir markers para o MapViewControllerBridge, já que ele espera uma propriedade vinculada por Binding. $ é um prefixo reservado para uso com wrappers de propriedade do Swift. Quando aplicado a um estado, ele retornará um Binding.

  1. Execute o app para ver os marcadores exibidos no mapa.

8. Animar para uma cidade selecionada

Na etapa anterior, você adicionou marcadores a um mapa transmitindo o estado de uma visualização do SwiftUI para outra. Nesta etapa, você irá criar uma animação para quando o usuário toca em uma cidade/marcador na lista interativa. Para isso, você irá reagir às mudanças de um estado modificando a posição da câmera no mapa quando a alteração ocorrer. Para saber mais sobre o conceito da câmera no mapa, consulte Câmera e visualização.

animate-city@2x.png

Animar mapa para a cidade selecionada

Para animar o mapa para uma cidade selecionada:

  1. Defina um novo Binding em MapViewControllerBridge.

O ContentView tem uma propriedade de estado chamada selectedMarker, que é inicializada como nula e é atualizada sempre que uma cidade é selecionada na lista. Isso é processado pela visualização buttonAction de CitiesList dentro do ContentView.

ContentView

CitiesList(markers: $markers) { (marker) in
  guard self.selectedMarker != marker else { return }
  self.selectedMarker = marker
  // ...
}

Sempre que selectedMarker mudar, o MapViewControllerBridge precisará estar ciente dessa mudança de estado para animar o mapa para o marcador selecionado. Portanto, defina um novo Binding dentro do MapViewControllerBridge do tipo GMSMarker e nomeie a propriedade selectedMarker.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?
}
  1. Atualize o MapViewControllerBridge para animar o mapa sempre que selectedMarker mudar.

Depois que um novo Binding for declarado, será necessário atualizar a função updateUIViewController_, context) do MapViewControllerBridge para que o mapa seja animado para o marcador selecionado. Para fazer isso, copie o código abaixo:

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
    markers.forEach { $0.map = uiViewController.map }
    selectedMarker?.map = uiViewController.map
    animateToSelectedMarker(viewController: uiViewController)
  }

  private func animateToSelectedMarker(viewController: MapViewController) {
    guard let selectedMarker = selectedMarker else {
      return
    }

    let map = viewController.map
    if map.selectedMarker != selectedMarker {
      map.selectedMarker = selectedMarker
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        map.animate(toZoom: kGMSMinZoomLevel)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
          map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
            map.animate(toZoom: 12)
          })
        }
      }
    }
  }
}

A função animateToSelectedMarker(viewController) irá executar uma sequência de animações no mapa usando a função animate(with) do GMSMapView.

  1. Transmita selectedMarker do ContentView para o MapViewControllerBridge.

Depois que o MapViewControllerBridge tiver o novo Binding declarado, atualize o ContentView para transmitir o selectedMarker para onde o MapViewControllerBridge estiver instanciado.

ContentView

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
        // ...
      }
    }
  }
}

Após concluir esta etapa, o usuário verá uma animação sempre que uma nova cidade for selecionada na lista.

Animar visualização do SwiftUI para enfatizar a cidade

O SwiftUI facilita a animação de visualizações, já que ele processa animações para transições de estado. Para demonstrar isso, você irá adicionar mais animações concentrando a visualização na cidade selecionada após a conclusão da animação do mapa. Para isso, siga os seguintes passos:

  1. Adicione uma clausura de onAnimationEnded ao MapViewControllerBridge.

Como a animação do SwiftUI será realizada após a sequência de animações do mapa que você adicionou antes, declare uma nova clausura chamada onAnimationEnded dentro do MapViewControllerBridge e invoque essa clausura depois de uma latência de 0,5 segundos após a última animação do mapa dentro do método animateToSelectedMarker(viewController).

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
    var onAnimationEnded: () -> ()

    private func animateToSelectedMarker(viewController: MapViewController) {
    guard let selectedMarker = selectedMarker else {
      return
    }

    let map = viewController.map
    if map.selectedMarker != selectedMarker {
      map.selectedMarker = selectedMarker
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        map.animate(toZoom: kGMSMinZoomLevel)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
          map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
            map.animate(toZoom: 12)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
              // Invoke onAnimationEnded() once the animation sequence completes
              onAnimationEnded()
            })
          })
        }
      }
    }
  }
}
  1. Implemente onAnimationEnded no MapViewControllerBridge.

Implemente a clausura onAnimationEnded onde o MapViewControllerBridge estiver instanciado dentro do ContentView. Copie e cole o código a seguir, que adiciona um novo estado chamado zoomInCenter. Ele também modifica a visualização usando clipShape e varia o diâmetro da forma cortada, dependendo do valor de zoomInCenter.

ContentView

struct ContentView: View {
  @State var zoomInCenter: Bool = false
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        let diameter = zoomInCenter ? geometry.size.width : (geometry.size.height * 2)
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: {
          self.zoomInCenter = true
        })
        .clipShape(
           Circle()
             .size(
               width: diameter,
               height: diameter
             )
             .offset(
               CGPoint(
                 x: (geometry.size.width - diameter) / 2,
                 y: (geometry.size.height - diameter) / 2
               )
             )
        )
        .animation(.easeIn)
        .background(Color(red: 254.0/255.0, green: 1, blue: 220.0/255.0))
      }
    }
  }
}
  1. Execute o app para ver os resultados.

9. Enviar um evento para o SwiftUI

Nesta etapa, você irá detectar eventos emitidos pela visualização GMSMapView e enviá-los para o SwiftUI. Mais especificamente, você irá definir um delegado para a visualização de mapa e detectar eventos de movimento da câmera. Dessa forma, quando uma cidade estiver focada e a câmera do mapa se mover devido a um gesto, a visualização de mapa será desfocada, exibindo uma parte maior do mapa.

Como usar os coordenadores do SwiftUI

A GMSMapView emite eventos como mudanças na posição da câmera ou a seleção de um marcador. Esses eventos são detectados pelo protocolo GMSMapViewDelegate. O SwiftUI introduz o conceito de um coordenador, que é usado especificamente para atuar como delegado dos controladores de visualização do UIKit. Portanto, no SwiftUI, um coordenador precisa ser responsável por estar em conformidade com o protocolo GMSMapViewDelegate. Para isso, siga as seguintes etapas:

  1. Crie um coordenador chamado MapViewCoordinator dentro do MapViewControllerBridge.

Crie uma classe aninhada dentro da classe MapViewControllerBridge e chame-a de MapViewCoordinator. Essa classe precisa estar em conformidade com o GMSMapViewDelegate e declarar MapViewControllerBridge como uma propriedade.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    var mapViewControllerBridge: MapViewControllerBridge

    init(_ mapViewControllerBridge: MapViewControllerBridge) {
      self.mapViewControllerBridge = mapViewControllerBridge
    }
  }
}
  1. Implemente makeCoordinator() no MapViewControllerBridge.

Em seguida, implemente o método makeCoordinator() dentro do MapViewControllerBridge e retorne uma instância do MapViewCoodinator que você criou na etapa anterior.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeCoordinator() -> MapViewCoordinator {
    return MapViewCoordinator(self)
  }
}
  1. Defina MapViewCoordinator como delegado da visualização de mapa.

Com o coordenador personalizado criado, a próxima etapa é defini-lo como o delegado da visualização de mapa do controlador. Para fazer isso, atualize a inicialização do controlador de visualização em makeUIViewController(context). O coordenador criado na etapa anterior poderá ser acessado pelo objeto "Context".

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeUIViewController(context: Context) -> MapViewController {
    let uiViewController = MapViewController()
    uiViewController.map.delegate = context.coordinator
    return uiViewController
  }
  1. Adicione uma clausura ao MapViewControllerBridge para que o evento de movimentação da câmera possa ser propagado para cima.

Como o objetivo é atualizar a visualização com as movimentos da câmera, declare uma nova propriedade de fechamento que aceite um booleano dentro do MapViewControllerBridge chamado mapViewWillMove, e invoque essa clausura no método delegado mapView(_, willMove) dentro do MapViewCoordinator. Transmita o valor de gesture para a clausura. Assim, a visualização do SwiftUI só poderá reagir aos eventos de movimento da câmera causados por gestos.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  var mapViewWillMove: (Bool) -> ()
  //...

  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    // ...
    func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
      self.mapViewControllerBridge.mapViewWillMove(gesture)
    }
  }
}
  1. Atualize o ContentView para transmitir um valor de mapWillMove.

Com a nova clausura declarada no MapViewControllerBridge, atualize o ContentView para transmitir um valor para ela. Nessa clausura, alterne o estado zoomInCenter para false se o evento de movimento estiver relacionado a um gesto. Isso mostrará o mapa na visualização completa novamente quando ele for movido com um gesto.

ContentView

struct ContentView: View {
  @State var zoomInCenter: Bool = false
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        let diameter = zoomInCenter ? geometry.size.width : (geometry.size.height * 2)
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: {
          self.zoomInCenter = true
        }, mapViewWillMove: { (isGesture) in
          guard isGesture else { return }
          self.zoomInCenter = false
        })
        // ...
      }
    }
  }
}
  1. Execute o app para ver as alterações.

10. Parabéns

Parabéns por chegar até aqui! Vimos bastante conteúdo até aqui, e esperamos que essas lições permitam que você crie seu próprio app no SwiftUI usando o SDK do Maps para iOS.

O que você aprendeu

  • As diferenças entre SwiftUI e UIKit
  • Como fazer uma ponte entre o SwiftUI e o UIKit usando UIViewControllerRepresentable
  • Como fazer alterações na visualização de mapa com Estado e Binding
  • Como enviar um evento da visualização de mapa para o SwiftUI usando um Coordenador

Qual é a próxima etapa?

  • SDK do Maps para iOS: documentação oficial do SDK do Maps para iOS.
  • SDK do Places para iOS: encontre empresas locais e pontos de interesse ao seu redor.
  • maps-sdk-for-ios-samples: exemplo de código no GitHub que demonstra todos os recursos do SDK do Maps para iOS.
  • SwiftUI: documentação oficial da Apple sobre o SwiftUI.
  • Ajude-nos a criar o conteúdo mais relevante para você respondendo à pergunta abaixo:

Quais outros codelabs você quer ver?

Visualização de dados em mapas Como personalizar o estilo dos meus mapas Como criar interações 3D em mapas

O codelab que você quer ver não está listado acima? Solicite-o criando um novo "Issue" aqui.