1. Prima di iniziare
Questo codelab ti insegna a utilizzare l'SDK Maps per iOS con SwiftUI.
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
- Xcode 11.0 o versioni successive
- Un Account Google con fatturazione abilitata
- SDK Maps per iOS
- Cartolina
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.
- In Cloud Console, fai clic sul menu a discesa del progetto e seleziona il progetto che vuoi utilizzare per questo codelab.
- 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.
- 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.
- 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.
- Dopo aver ricevuto il codice, nel terminale
cd
nel reindirizzamentostarter/GoogleMapsSwiftUI
. - Esegui
carthage update --platform iOS
per scaricare l'SDK Maps per iOS - 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 UIKitUIViewController
contenente una Google Maps (GMSMapView)SceneDelegate
: l'elementoUIWindowSceneDelegate
dell'applicazione da cui è creata un'istanza diContentView
.
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à accessibileMapViewController
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.
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:
- 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'elementoUIViewController
sottostante. Qui puoi creare un'istanza diUIViewController
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.
- 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.
- 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.
- 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()
} // ...
}
}
}
- 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.
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:
- Dichiara una nuova proprietà
markers
inMapViewControllerBridge
con@Binding
MapViewControllerBridge
struct MapViewControllerBridge: : UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
// ...
}
- In
MapViewControllerBridge
, aggiorna il metodoupdateUIViewController(_, 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 }
}
}
- Passa la proprietà
markers
daContentView
aMapViewControllerBridge
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.
- 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.
Anima la mappa nella città selezionata
Per animare la mappa in una città selezionata:
- 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?
}
- Aggiorna
MapViewControllerBridge
per animare la mappa ogni volta cheselectedMarker
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
.
- Passa il
selectedMarker
daContentView
aMapViewControllerBridge
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:
- Aggiungi una chiusura
onAnimationEnded
aMapViewControllerBridge
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()
})
})
}
}
}
}
}
- Implementa
onAnimationEnded
inMapViewControllerBridge
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))
}
}
}
}
- 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:
- Crea un coordinatore chiamato
MapViewCoordinator
all'interno diMapViewControllerBridge
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
}
}
}
- Implementa
makeCoordinator()
inMapViewControllerBridge
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)
}
}
- 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
}
- 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)
}
}
}
- 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
})
// ...
}
}
}
}
- 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
- Differenze tra SwiftUI e UIKit
- Come passare da SwiftUI a UIKit e viceversa usando UIViewControllerRepresentable
- Come apportare modifiche alla visualizzazione mappa con lo stato e l'associazione
- Come inviare un evento dalla visualizzazione mappa a SwiftUI utilizzando un coordinatore
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?
Il codelab non vuoi vedere sopra? Richiedilo qui con un nuovo problema.