Aggiungere una mappa alla tua app per iOS con SwiftUI (Swift)

1. Prima di iniziare

Questo codelab ti insegna a utilizzare l'SDK Maps per iOS con SwiftUI.

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

Prerequisiti

  • Conoscenza di base di Swift
  • Familiarità con SwiftUI

In questo lab proverai a:

  • Attiva e utilizza Maps SDK for iOS per aggiungere Google Maps a un'app per iOS utilizzando SwiftUI.
  • Aggiungi indicatori alla mappa.
  • Passa lo stato da una vista SwiftUI a un oggetto GMSMapView e viceversa.

Che cosa ti serve

2. Configura

Per il passaggio di attivazione seguente, attiva l'SDK Maps per iOS.

Configurare Google Maps Platform

Se non hai ancora un account Google Cloud Platform e un progetto con la fatturazione abilitata, consulta la guida Utilizzo di Google Maps Platform per creare un account di fatturazione e un progetto.

  1. In Cloud Console, fai clic sul menu a discesa del progetto e seleziona il progetto che vuoi utilizzare per questo codelab.

  1. Abilita le API e gli SDK di Google Maps Platform richiesti per questo codelab in Google Cloud Marketplace. Per farlo, segui la procedura descritta in questo video o in questa documentazione.
  2. Genera una chiave API nella pagina Credentials di Cloud Console. Puoi seguire la procedura descritta in questo video o in questa documentazione. Tutte le richieste a Google Maps Platform richiedono una chiave API.

3. Scarica codice di avvio

Per iniziare il più rapidamente possibile, ecco un codice di avvio che ti aiuterà a seguire questo codelab. Ti invitiamo a passare alla soluzione, ma se vuoi seguire tutti i passaggi per crearla da sola, continua a leggere.

  1. Clona il repository se hai installato git.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git

In alternativa, puoi fare clic sul seguente pulsante per scaricare il codice sorgente.

  1. Dopo aver ricevuto il codice, nel terminale cd nel reindirizzamento starter/GoogleMapsSwiftUI.
  2. Esegui carthage update --platform iOS per scaricare l'SDK Maps per iOS
  3. Infine, apri il file GoogleMapsSwiftUI.xcodeproj in Xcode.

4. Panoramica del codice

Nel progetto iniziale che hai scaricato, ti sono stati forniti e implementati i seguenti corsi:

  • AppDelegate: UIApplicationDelegate dell'applicazione. Qui verrà inizializzato l'SDK di Maps per iOS.
  • City: una struttura che rappresenta una città (contiene un nome e una coordinata della città).
  • MapViewController: un semplice UIKit UIViewController contenente una Google Maps (GMSMapView)
  • SceneDelegate: l'elemento UIWindowSceneDelegate dell'applicazione da cui è creata un'istanza di ContentView.

Inoltre, le seguenti classi hanno implementazioni parziali e verranno completate entro la fine di questo codelab:

  • ContentView: la visualizzazione SwiftUI di primo livello contenente l'app.
  • MapViewControllerBridge: una classe che collega una vista UIKit a una vista SwiftUI. Nello specifico, questa è la classe che renderà accessibile MapViewController in SwiftUI.

5. Utilizzo di SwiftUI e UIKit

SwiftUI è stata introdotta in iOS 13 come framework UI alternativo di UIKit per lo sviluppo di applicazioni iOS. Rispetto al suo predecessore UIKit, SwiftUI offre una serie di vantaggi. Per citarne alcune:

  • Le visualizzazioni si aggiornano automaticamente quando lo stato cambia. Utilizzando oggetti chiamati Stato, qualsiasi modifica al valore sottostante che contiene causerà l'aggiornamento automatico dell'interfaccia utente.
  • Le anteprime in tempo reale consentono uno sviluppo più rapido. Le anteprime dal vivo riducono al minimo la necessità di creare ed eseguire il deployment del codice in un emulatore per visualizzare le modifiche visive, poiché un'anteprima della visualizzazione SwiftUI è facilmente visibile su Xcode.
  • La fonte dei dati è in Swift. Tutte le visualizzazioni in SwiftUI sono dichiarate in Swift, perciò non è più necessario utilizzare il Generatore di interfacce.
  • Interazione con UIKit. L'interoperabilità con UIKit garantisce che le app esistenti possano utilizzare in modo incrementale SwiftUI con le loro viste esistenti. Inoltre, le librerie che non supportano ancora SwiftUI, come Maps SDK for iOS, possono essere utilizzate in SwiftUI.

Esistono anche alcuni svantaggi:

  • SwiftUI è disponibile solo su iOS 13 o versioni successive.
  • La gerarchia di visualizzazione non può essere esaminata nelle anteprime di Xcode.

SwiftUI State e flusso di dati

SwiftUI offre un nuovo modo per creare un'interfaccia utente utilizzando un approccio dichiarativo: spiega a SwiftUI come vuoi che la tua vista venga vista insieme a tutti i diversi stati e l'interfaccia farà il resto. SwiftUI gestisce l'aggiornamento della visualizzazione ogni volta che lo stato sottostante cambia a causa di un evento o di un'azione dell'utente. Questo design è comunemente riferito al flusso di dati unidirezionale. Sebbene le specifiche di questo design non rientrino nell'ambito di questo codelab, ti consigliamo di approfondire l'argomento nella documentazione di Apple sullo stato e sul flusso di dati di Apple.

Collegamento di UIKit e SwiftUI mediante UIViewRepresentable o UIViewControllerRepresentable

Poiché l'SDK di Maps per iOS è basato su UIKit e non fornisce ancora una vista compatibile con SwiftUI, l'utilizzo in SwiftUI richiede la conformità a UIViewRepresentable o UIViewControllerRepresentable. Questi protocolli consentono a SwiftUI di includere rispettivamente UIView e UIViewController creati dallo UIKit. Puoi utilizzare uno dei due protocolli per aggiungere una mappa Google a una vista SwiftUI, ma nel prossimo passaggio vedremo come utilizzare UIViewControllerRepresentable per includere un elemento UIViewController contenente una mappa.

6. Aggiungere una mappa

In questa sezione aggiungerai Google Maps a una vista SwiftUI.

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

Aggiungi la tua chiave API

La chiave API creata in un passaggio precedente deve essere fornita all'SDK di Maps per iOS per associare il tuo account alla mappa che verrebbe visualizzata nell'app.

Per fornire la tua chiave API, apri il file AppDelegate.swift e vai al metodo application(_, didFinishLaunchingWithOptions). Attualmente, l'SDK viene inizializzato tramite GMSServices.provideAPIKey() con la stringa "YOUR_API_KEY". Sostituisci tale stringa con la chiave API. Completando questo passaggio, verrà inizializzato l'SDK di Maps per iOS all'avvio dell'applicazione.

Aggiungere una mappa Google utilizzando MapViewControllerBridge

Ora che la chiave API viene fornita all'SDK, il passaggio successivo è mostrare la mappa nell'app.

Il controller di visualizzazione fornito nel codice di avvio, MapViewController contiene attualmente un GMSMapView nella sua vista. Tuttavia, poiché questo controller di visualizzazione è stato creato in UIKit, dovrai collegare questa classe a SwiftUI in modo che possa essere utilizzata in ContentView. Per farlo:

  1. Apri il file MapViewControllerBridge in Xcode.

Questa classe è conforme all'elemento UIViewControllerRepresentable, ovvero il protocollo necessario per aggregare un UIKit UIViewController, in modo da poterlo utilizzare come vista SwiftUI. In altre parole, la conformità a questo protocollo ti consente di collegare una vista UIKit a una vista SwiftUI. Per rispettare questo protocollo è necessario implementare due metodi:

  • makeUIViewController(context): questo metodo viene chiamato da SwiftUI per creare l'elemento UIViewController sottostante. Qui puoi creare un'istanza di UIViewController e trasmetterla allo stato iniziale.
  • updateUIViewController(_, context): questo metodo viene chiamato SwiftUI ogni volta che lo stato cambia. Qui puoi apportare eventuali modifiche all'UIViewController sottostante per reagire alla modifica dello stato.
  1. Crea un MapViewController

All'interno della funzione makeUIViewController(context), crea un'istanza di un nuovo elemento MapViewController e, di conseguenza, restituiscilo. Dopodiché, il tuo MapViewControllerBridge dovrebbe avere il seguente aspetto:

MapViewControllerBridge

import GoogleMaps
import SwiftUI

struct MapViewControllerBridge: UIViewControllerRepresentable {

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

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

Utilizzare MapViewControllerBridge in ContentView

Ora che MapViewControllerBridge sta creando un'istanza di MapViewController, il passaggio successivo è utilizzare questa struttura in ContentView per visualizzare una mappa.

  1. Apri il file ContentView in Xcode.

L'istanza di ContentView è creata in SceneDelegate e contiene la visualizzazione di applicazione di primo livello. La mappa verrà aggiunta dall'interno di questo file.

  1. Crea un MapViewControllerBridge all'interno della proprietà body.

All'interno della proprietà body di questo file, è già stato fornito e implementato un ZStack. L'elemento ZStack contiene attualmente un elenco interattivo e trascinabile di città che utilizzerai in un passaggio successivo. Per ora, all'interno di ZStack crea una MapViewControllerBridge come prima vista secondaria della ZStack in modo che venga visualizzata una mappa nell'app dietro all'elenco delle città. In questo modo, i contenuti della proprietà body all'interno di ContentView dovrebbero avere il seguente aspetto:

Visualizzazione dei contenuti

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. Ora procedi ed esegui l'app. Ora dovresti vedere il carico della mappa nella schermata del tuo dispositivo, insieme a un elenco trascinabile di città verso la parte inferiore dello schermo.

7. Aggiungere indicatori alla mappa

Nel passaggio precedente, hai aggiunto una mappa insieme a un elenco interattivo che mostra un elenco di città. In questa sezione aggiungerai gli indicatori per ogni città dell'elenco.

mappa-con-indicatori@2x.png

Indicatori come Stato

Attualmente ContentView dichiara una proprietà denominata markers, che è un elenco di GMSMarker che rappresenta ogni città dichiarata nella proprietà statica cities. Nota che questa proprietà è annotata con il stato del wrapper proprietà SwiftUI, per indicare che deve essere gestita da SwiftUI. Pertanto, se vengono rilevate modifiche con questa proprietà, ad esempio se aggiungi o rimuovi un indicatore, le viste che utilizzano questo stato verranno aggiornate.

Visualizzazione dei contenuti

  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
  }

Tieni presente che ContentView utilizza la proprietà markers per visualizzare l'elenco delle città passandolo alla classe CitiesList.

Elenco città

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)
      }
    }
  }
}

Passaggio stato a MapViewControllerBridge tramite associazione

Oltre all'elenco di città che mostrano i dati della proprietà markers, passa questa proprietà alla struttura MapViewControllerBridge in modo che possa essere utilizzata per mostrare sulla mappa gli indicatori. A tale scopo, procedi nel seguente modo:

  1. Dichiara una nuova proprietà markers in MapViewControllerBridge con @Binding

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. In MapViewControllerBridge, aggiorna il metodo updateUIViewController(_, context) per utilizzare la proprietà markers

Come indicato nel passaggio precedente, updateUIViewController(_, context) verrà chiamato da SwiftUI ogni volta che lo stato cambia. È all'interno di questo metodo che vogliamo aggiornare la mappa, pertanto visualizza gli indicatori in markers. A tale scopo, devi aggiornare la proprietà map di ogni indicatore. Dopo aver completato questo passaggio, il MapViewControllerBridge dovrebbe avere il seguente aspetto:

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. Passa la proprietà markers da ContentView a MapViewControllerBridge

Poiché hai aggiunto una nuova proprietà in MapViewControllerBridge, ora è necessario che il valore di questa proprietà venga trasmesso nell'inizializzazionetore per MapViewControllerBridge. Pertanto, se provi a creare l'app, tieni presente che non verrà compilato. Per risolvere il problema, aggiorna ContentView a cui viene creato il MapViewControllerBridge e trasmettilo nella proprietà markers, in questo modo:

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

Nota che è stato utilizzato il prefisso $ per passare da markers a MapViewControllerBridge perché prevede una proprietà associata. $ è un prefisso riservato da utilizzare con i wrapper proprietà Swift. Se applicato a uno stato, restituisce un'associazione.

  1. Esegui l'app per visualizzare gli indicatori visualizzati sulla mappa.

8. Animazione in una città selezionata

Nel passaggio precedente, hai aggiunto gli indicatori a una mappa passando dallo stato di una vista SwiftUI a un'altra. In questo passaggio, ti verrà mostrata un'animazione in base a una città o un indicatore dopo essere stata toccata nell'elenco di elementi interattivi. Per eseguire l'animazione, reagirai ai cambiamenti di uno Stato modificando la posizione della fotocamera della mappa quando si verifica il cambiamento. Per scoprire di più sul concetto della fotocamera della mappa, vedi Videocamera e vista.

animazione-città@2x.png

Anima la mappa nella città selezionata

Per animare la mappa in una città selezionata:

  1. Definisci una nuova associazione in MapViewControllerBridge

ContentView ha una proprietà Stato denominata selectedMarker inizializzata con zero e viene aggiornata ogni volta che viene selezionata una città nell'elenco. Ciò viene gestito dalla visualizzazione CitiesList di buttonAction all'interno di ContentView.

Visualizzazione dei contenuti

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

Ogni volta che selectedMarker cambia, MapViewControllerBridge è a conoscenza di questa modifica dello stato, in modo che possa animare la mappa fino all'indicatore selezionato. Pertanto, definisci una nuova associazione all'interno di MapViewControllerBridge di tipo GMSMarker e denomina la proprietà selectedMarker.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?
}
  1. Aggiorna MapViewControllerBridge per animare la mappa ogni volta che selectedMarker cambia

Una volta dichiarata una nuova associazione, devi aggiornare la funzione updateUIViewController_, context) di MapViewControllerBridge in modo che la mappa si annulli all'indicatore selezionato. Per farlo, copia il seguente codice:

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)
          })
        }
      }
    }
  }
}

La funzione animateToSelectedMarker(viewController) eseguirà una sequenza di animazioni mappa utilizzando la funzione animate(with) di GMSMapView.

  1. Passa il selectedMarker da ContentView a MapViewControllerBridge

Una volta dichiarata l'associazione di MapViewControllerBridge, vai avanti e aggiorna ContentView in modo che passi nella sezione selectedMarker in cui è creata l'istanza di MapViewControllerBridge.

Visualizzazione dei contenuti

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

Se completi questo passaggio, verrà animata la mappa ogni volta che viene selezionata una nuova città nell'elenco.

Animazione di SwiftUI per mettere in evidenza la città

SwiftUI semplifica l'animazione delle viste perché gestisce l'esecuzione di animazioni per le transizioni di stato. Per dimostrarlo, aggiungerai altre animazioni concentrando la vista sulla città selezionata al termine dell'animazione della mappa. A tale scopo, procedi nel seguente modo:

  1. Aggiungi una chiusura onAnimationEnded a MapViewControllerBridge

Poiché l'animazione SwiftUI verrà eseguita dopo la sequenza di animazione della mappa che hai aggiunto in precedenza, dichiara una nuova chiusura chiamata onAnimationEnded entro MapViewControllerBridge e richiama questa chiusura dopo un ritardo di 0,5 secondi dopo l'ultima animazione della mappa all'interno del metodo 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. Implementa onAnimationEnded in MapViewControllerBridge

Implementa la chiusura di onAnimationEnded in cui viene creata un'istanza di MapViewControllerBridge entro ContentView. Copia e incolla il seguente codice, che aggiunge un nuovo stato, zoomInCenter, e modifica anche la vista utilizzando clipShape, variando il diametro della forma ritagliata in base al valore di zoomInCenter.

Visualizzazione dei contenuti

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. Vai avanti ed esegui l'app per vedere le animazioni.

9. Inviare un evento a SwiftUI

In questo passaggio, ascolti gli eventi emessi da GMSMapView e li invii a SwiftUI. In particolare, imposterai una persona delegata alla visualizzazione mappa e ascolti gli eventi di movimento della videocamera in modo che, quando una città viene messa a fuoco e si sposta da un gesto, la visualizzazione mappa verrà disattivata, in modo da poter vedere meglio la mappa.

Utilizzo dei coordinatori di SwiftUI

GMSMapView emette eventi come le modifiche alla posizione della fotocamera o il tocco di un indicatore. Il meccanismo di ascolto di questi eventi è attraverso il protocollo GMSMapViewDelegato. SwiftUI introduce il concetto di coordinatore, utilizzato specificamente per agire come delegato per i controller di visualizzazione UIKit. Pertanto, nel mondo di SwiftUI, un coordinatore deve essere responsabile della conformità al protocollo GMSMapViewDelegate. Per farlo, completa i seguenti passaggi:

  1. Crea un coordinatore chiamato MapViewCoordinator all'interno di MapViewControllerBridge

Crea una classe nidificata all'interno della classe MapViewControllerBridge e chiamala MapViewCoordinator. Questa classe deve essere conforme alle GMSMapViewDelegate e deve dichiarare MapViewControllerBridge come proprietà.

MapViewControllerBridge

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

    init(_ mapViewControllerBridge: MapViewControllerBridge) {
      self.mapViewControllerBridge = mapViewControllerBridge
    }
  }
}
  1. Implementa makeCoordinator() in MapViewControllerBridge

Implementa quindi il metodo makeCoordinator() in MapViewControllerBridge e restituisci un'istanza di MapViewCoodinator che hai creato nel passaggio precedente.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeCoordinator() -> MapViewCoordinator {
    return MapViewCoordinator(self)
  }
}
  1. Imposta il MapViewCoordinator come delegato della visualizzazione mappa

Dopo aver creato il coordinatore personalizzato, il passaggio successivo consiste nel impostarlo come delegato per la visualizzazione mappa del controller della vista. Per farlo, aggiorna l'inizializzazione del controller di visualizzazione in makeUIViewController(context). Il coordinatore creato nel passaggio precedente sarà accessibile dall'oggetto Context.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeUIViewController(context: Context) -> MapViewController {
    let uiViewController = MapViewController()
    uiViewController.map.delegate = context.coordinator
    return uiViewController
  }
  1. Aggiungi una chiusura a MapViewControllerBridge per consentire la propagazione dell'evento nella videocamera

Poiché l'obiettivo è aggiornare la vista con lo spostamento della fotocamera, dichiara una nuova proprietà di chiusura che accetta un valore booleano all'interno di MapViewControllerBridge chiamato mapViewWillMove e richiama questa chiusura nel metodo di delega mapView(_, willMove) all'interno di MapViewCoordinator. Trasmetti il valore di gesture alla chiusura in modo che la vista SwiftUI possa reagire solo agli eventi di spostamento della videocamera correlati al gesto.

MapViewControllerBridge

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

  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    // ...
    func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
      self.mapViewControllerBridge.mapViewWillMove(gesture)
    }
  }
}
  1. Aggiorna ContentView per passare un valore per mapWillMove

Con la nuova chiusura dichiarata il giorno MapViewControllerBridge, aggiorna ContentView in modo che passi un valore per la nuova chiusura. Nella chiusura, attiva lo stato zoomInCenter su false se l'evento di spostamento è correlato a un gesto. In questo modo la mappa verrà nuovamente visualizzata completamente e interamente quando viene spostata da un gesto.

Visualizzazione dei contenuti

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. Esegui l'app per vedere le nuove modifiche.

10. Complimenti

Congratulazioni per aver raggiunto questa destinazione! Hai trattato molti aspetti e speriamo che le lezioni apprese ti consentano di creare la tua app SwiftUI utilizzando l'SDK Maps per iOS.

Che cosa hai imparato

Passaggi successivi

  • SDK Maps per iOS: documentazione ufficiale sull'SDK Maps per iOS.
  • SDK Places per iOS: trova attività commerciali locali e punti di interesse nelle vicinanze
  • maps-sdk-for-ios-samples: codice di esempio su GitHub che mostra tutte le funzionalità all'interno dell'SDK Maps per iOS.
  • SwiftUI: documentazione ufficiale su Apple SwiftUI
  • Aiutaci a creare i contenuti che troverai più utili rispondendo alla domanda di seguito:

Quali altri codelab vorresti vedere?

Visualizzazione dei dati sulle mappe Ulteriori informazioni sullo stile delle mappe Creazione di interazioni 3D nelle mappe

Il codelab non vuoi vedere sopra? Richiedilo qui con un nuovo problema.