1. Prima di iniziare
Questo codelab ti insegna a utilizzare Maps SDK for iOS con SwiftUI.
Prerequisiti
- Conoscenza di base di Swift
- Familiarità di base 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.
- Passare lo stato tra un oggetto SwiftUI e un oggetto
GMSMapView
.
Che cosa ti serve
- Xcode 11.0 o versioni successive
- Un Account Google con la fatturazione abilitata
- Maps SDK for iOS
- Cartagine
2. Configurazione
Per il seguente passaggio di attivazione, abilita Maps SDK for iOS.
Configurare Google Maps Platform
Se non hai ancora un account Google Cloud Platform e un progetto con la fatturazione abilitata, consulta la guida Guida introduttiva a Google Maps Platform per creare un account di fatturazione e un progetto.
- Nella console Cloud, 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 i passaggi descritti in questo video o in questa documentazione.
- Genera una chiave API nella pagina Credenziali di Cloud Console. Puoi seguire i passaggi descritti in questo video o in questa documentazione. Tutte le richieste a Google Maps Platform richiedono una chiave API.
3. Scarica il codice di avvio
Per iniziare il più rapidamente possibile, ecco un codice iniziale che ti aiuterà a seguire questo codelab. Puoi passare direttamente alla soluzione, ma se vuoi seguire tutti i passaggi per crearla da solo, 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.
- Una volta ricevuto il codice, in un terminale
cd
nella directorystarter/GoogleMapsSwiftUI
. - Esegui
carthage update --platform iOS
per scaricare Maps SDK for iOS - Infine, apri il file
GoogleMapsSwiftUI.xcodeproj
in Xcode.
4. Panoramica del codice
Nel progetto iniziale che hai scaricato, sono state fornite e implementate le seguenti classi:
AppDelegate
: ilUIApplicationDelegate
dell'applicazione. È qui che verrà inizializzato Maps SDK for iOS.City
: una struttura che rappresenta una città (contiene un nome e le coordinate della città).MapViewController
: un UIKit con ambito ridottoUIViewController
contenente una mappa di Google (GMSMapView)SceneDelegate
: l'UIWindowSceneDelegate
dell'applicazione da cui viene istanziatoContentView
.
Inoltre, le seguenti classi hanno implementazioni parziali e verranno completate da te entro la fine di questo codelab:
ContentView
: la visualizzazione SwiftUI di primo livello che contiene la tua app.MapViewControllerBridge
: una classe che collega una visualizzazione UIKit a una visualizzazione SwiftUI. Nello specifico, questa è la classe che renderàMapViewController
accessibile in SwiftUI.
5. SwiftUI e UIKit
SwiftUI è stato introdotto in iOS 13 come framework UI alternativo a UIKit per lo sviluppo di applicazioni per iOS. Rispetto al suo predecessore UIKit, SwiftUI offre una serie di vantaggi. Per citarne alcuni:
- Le visualizzazioni si aggiornano automaticamente quando lo stato cambia. Utilizzando oggetti chiamati State, qualsiasi modifica al valore sottostante che contiene causerà l'aggiornamento automatico dell'interfaccia utente.
- Le anteprime live consentono uno sviluppo più rapido. Le anteprime live riducono al minimo la necessità di creare e implementare codice in un emulatore per visualizzare le modifiche visive, in quanto l'anteprima della visualizzazione SwiftUI è facilmente visibile in Xcode.
- La fonte di riferimento è in Swift. Tutte le viste in SwiftUI sono dichiarate in Swift, quindi non è più necessario utilizzare Interface Builder.
- Interopera con UIKit. L'interoperabilità con UIKit garantisce che le app esistenti possano utilizzare SwiftUI in modo incrementale con le visualizzazioni esistenti. Inoltre, le librerie che non supportano ancora SwiftUI, come l'SDK Maps per iOS, possono comunque essere utilizzate in SwiftUI.
Ci sono anche alcuni svantaggi:
- SwiftUI è disponibile solo su iOS 13 o versioni successive.
- La gerarchia delle visualizzazioni non può essere esaminata nelle anteprime di Xcode.
Stato e flusso di dati di SwiftUI
SwiftUI offre un nuovo modo di creare UI utilizzando un approccio dichiarativo: indichi a SwiftUI l'aspetto che vuoi che abbia la tua visualizzazione insieme a tutti i diversi stati, e il sistema 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 chiamato flusso di dati unidirezionale. Sebbene i dettagli di questa progettazione non rientrino nell'ambito di questo codelab, ti consigliamo di leggere come funziona nella documentazione di Apple su State and Data Flow.
Eseguire il bridging di UIKit e SwiftUI utilizzando UIViewRepresentable o UIViewControllerRepresentable
Poiché l'SDK Maps per iOS è basato su UIKit e non fornisce una visualizzazione compatibile con SwiftUI, il suo utilizzo in SwiftUI richiede la conformità a UIViewRepresentable
o UIViewControllerRepresentable
. Questi protocolli consentono a SwiftUI di includere rispettivamente UIView
e UIViewController
creati con UIKit. Anche se puoi utilizzare uno dei due protocolli per aggiungere una mappa di Google a una visualizzazione SwiftUI, nel passaggio successivo vedremo come utilizzare un UIViewControllerRepresentable
per includere un UIViewController
contenente una mappa.
6. Aggiungere una mappa
In questa sezione aggiungerai Google Maps a una visualizzazione SwiftUI.
Aggiungere la chiave API
La chiave API creata in un passaggio precedente deve essere fornita a Maps SDK for iOS per associare il tuo account alla mappa che verrà visualizzata nell'app.
Per fornire la chiave API, apri il file AppDelegate.swift
e vai al metodo application(_, didFinishLaunchingWithOptions)
. L'SDK viene inizializzato utilizzando GMSServices.provideAPIKey()
con la stringa "YOUR_API_KEY". Sostituisci questa stringa con la tua chiave API. Il completamento di questo passaggio inizializzerà l'SDK 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 consiste nel visualizzare la mappa nell'app.
Il controller di visualizzazione fornito nel codice iniziale, MapViewController
, contiene un GMSMapView
nella visualizzazione. Tuttavia, poiché questo controller di visualizzazione è stato creato in UIKit, dovrai eseguire il bridging di questa classe in SwiftUI in modo che possa essere utilizzata all'interno di ContentView
. Per farlo:
- Apri il file
MapViewControllerBridge
in Xcode.
Questa classe è conforme a UIViewControllerRepresentable, il protocollo necessario per eseguire il wrapping di un UIViewController
UIKit in modo che possa essere utilizzato come visualizzazione SwiftUI. In altre parole, l'adeguamento a questo protocollo facilita il bridging di 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'UIViewController
sottostante. È qui che istanzieraiUIViewController
e gli passerai il suo stato iniziale.updateUIViewController(_, context)
: questo metodo viene chiamato da SwiftUI ogni volta che lo stato cambia. È qui che apporti le modifiche all'intentUIViewController
sottostante per reagire alla modifica dello stato.
- Crea un
MapViewController
All'interno della funzione makeUIViewController(context)
, crea un'istanza di un nuovo MapViewController
e restituiscila come risultato. Dopo averlo fatto, 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 consiste nell'utilizzare questa struct all'interno di ContentView
per visualizzare una mappa.
- Apri il file
ContentView
in Xcode.
ContentView
viene istanziato in SceneDelegate
e contiene la visualizzazione dell'applicazione di primo livello. La mappa verrà aggiunta da 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
. ZStack
contiene un elenco interattivo e trascinabile di città che utilizzerai in un passaggio successivo. Per il momento, all'interno di ZStack
crea un MapViewControllerBridge
come prima visualizzazione figlio di ZStack
in modo che venga visualizzata una mappa nell'app dietro la visualizzazione dell'elenco delle città. In questo modo, i contenuti della proprietà body
all'interno di ContentView
dovrebbero essere simili a questi:
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()
} // ...
}
}
}
- Ora esegui l'app. Dovresti vedere la mappa caricata sullo schermo del dispositivo insieme a un elenco trascinabile di città nella 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 indicatori per ogni città dell'elenco.
Marcatori come stato
ContentView
dichiara una proprietà chiamata markers
, che è un elenco di GMSMarker
che rappresentano ogni città dichiarata nella proprietà statica cities
. Tieni presente che questa proprietà è annotata con il wrapper di proprietà SwiftUI State per indicare che deve essere gestita da SwiftUI. Pertanto, se vengono rilevate modifiche a questa proprietà, ad esempio l'aggiunta o la rimozione di un indicatore, le visualizzazioni che utilizzano questo stato verranno aggiornate.
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
}
Tieni presente che ContentView
utilizza la proprietà markers
per eseguire il rendering dell'elenco delle città passandola alla 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)
}
}
}
}
Passa lo stato a MapViewControllerBridge utilizzando @Binding
Oltre all'elenco delle città che mostrano i dati della proprietà markers
, passa questa proprietà alla struttura MapViewControllerBridge
in modo che possa essere utilizzata per visualizzare i relativi indicatori sulla mappa. Per farlo, segui questi passaggi:
- Dichiara una nuova proprietà
markers
all'interno diMapViewControllerBridge
annotata con@Binding
MapViewControllerBridge
struct MapViewControllerBridge: : UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
// ...
}
- In
MapViewControllerBridge
, aggiorna il metodoupdateUIViewController(_, context)
per utilizzare la proprietàmarkers
Come accennato 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 in modo da visualizzare i marcatori in markers
. Per farlo, devi aggiornare la proprietà map
di ogni indicatore. Dopo aver completato questo passaggio, il tuo 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 passato nell'inizializzatore per MapViewControllerBridge
. Pertanto, se provi a creare l'app, noterai che non verrà compilata. Per risolvere il problema, aggiorna ContentView
in cui viene creato MapViewControllerBridge
e inserisci la proprietà markers
nel seguente modo:
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers)
// ...
}
}
}
}
Nota che il prefisso $
è stato utilizzato per passare markers
a MapViewControllerBridge
, poiché prevede una proprietà associata. $
è un prefisso riservato per l'utilizzo con i wrapper delle proprietà Swift. Se applicato a uno stato, restituisce un Binding.
- Esegui l'app per visualizzare i segnaposto sulla mappa.
8. Animare fino a una città selezionata
Nel passaggio precedente, hai aggiunto indicatori a una mappa passando lo stato da una visualizzazione SwiftUI all'altra. In questo passaggio, animerai una città o un indicatore dopo che è stato toccato nell'elenco interattivo. Per eseguire l'animazione, reagisci alle modifiche a uno stato modificando la posizione della videocamera della mappa quando si verifica la modifica. Per scoprire di più sul concetto di videocamera della mappa, consulta Videocamera e visualizzazione.
Animare la mappa sulla città selezionata
Per animare la mappa in modo che mostri una città selezionata:
- Definisci una nuova associazione in
MapViewControllerBridge
ContentView
ha una proprietà State chiamata selectedMarker
che viene inizializzata su nil e viene aggiornata ogni volta che viene selezionata una città nell'elenco. Questa operazione viene gestita dalla visualizzazione CitiesList
buttonAction
all'interno di ContentView
.
ContentView
CitiesList(markers: $markers) { (marker) in
guard self.selectedMarker != marker else { return }
self.selectedMarker = marker
// ...
}
Ogni volta che selectedMarker
cambia, MapViewControllerBridge
deve essere a conoscenza di questa modifica dello stato in modo da poter animare la mappa fino al marker selezionato. Definisci quindi un nuovo Binding all'interno di MapViewControllerBridge
di tipo GMSMarker
e assegna alla proprietà il nome selectedMarker
.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var selectedMarker: GMSMarker?
}
- Aggiorna
MapViewControllerBridge
per animare la mappa ogni volta cheselectedMarker
cambia
Una volta dichiarato un nuovo Binding, devi aggiornare la funzione MapViewControllerBridge
di updateUIViewController_, context)
in modo che la mappa si animi fino al marker 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 della mappa utilizzando la funzione animate(with)
di GMSMapView
.
- Pass
ContentView
'sselectedMarker
toMapViewControllerBridge
Una volta che MapViewControllerBridge
ha dichiarato il nuovo Binding, aggiorna ContentView
per passare a selectedMarker
dove viene istanziato MapViewControllerBridge
.
ContentView
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
// ...
}
}
}
}
Il completamento di questo passaggio ora anima la mappa ogni volta che viene selezionata una nuova città nell'elenco.
Animare la visualizzazione SwiftUI per mettere in evidenza la città
SwiftUI semplifica il processo di animazione delle visualizzazioni, in quanto gestisce l'esecuzione delle animazioni per le transizioni di stato. Per dimostrarlo, aggiungerai altre animazioni concentrando la visualizzazione sulla città selezionata al termine dell'animazione della mappa. Per farlo, segui questi passaggi:
- Aggiungere una chiusura
onAnimationEnded
aMapViewControllerBridge
Poiché l'animazione SwiftUI verrà eseguita dopo la sequenza di animazione della mappa aggiunta in precedenza, dichiara una nuova chiusura chiamata onAnimationEnded
all'interno di 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 onAnimationEnded
in cui MapViewControllerBridge
viene istanziato all'interno di ContentView
. Copia e incolla il seguente codice che aggiunge un nuovo stato chiamato zoomInCenter
e modifica anche la visualizzazione utilizzando clipShape
e varia il diametro della forma ritagliata a seconda del valore di 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))
}
}
}
}
- Esegui l'app per vedere le animazioni.
9. Invia un evento a SwiftUI
In questo passaggio, ascolterai gli eventi emessi da GMSMapView
e li invierai a SwiftUI. In particolare, imposterai un delegato per la visualizzazione mappa e ascolterai gli eventi di spostamento della videocamera in modo che, quando una città è messa a fuoco e la videocamera della mappa si sposta da un gesto, la visualizzazione mappa si sfoca per consentirti di vedere più dettagli della mappa.
Utilizzare i coordinatori SwiftUI
GMSMapView
genera eventi come modifiche alla posizione della videocamera o quando viene toccato un indicatore. Il meccanismo per l'ascolto di questi eventi avviene tramite il protocollo GMSMapViewDelegate. SwiftUI introduce il concetto di un coordinatore, che viene utilizzato specificamente per fungere da delegato per i controller di visualizzazione UIKit. Pertanto, nel mondo di SwiftUI, un coordinatore deve occuparsi di rispettare il protocollo GMSMapViewDelegate
. Per farlo, segui questi passaggi:
- Crea un coordinatore denominato
MapViewCoordinator
all'interno diMapViewControllerBridge
Crea una classe nidificata all'interno della classe MapViewControllerBridge
e chiamala MapViewCoordinator
. Questa classe deve essere conforme a 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
Successivamente, implementa il metodo makeCoordinator()
all'interno di MapViewControllerBridge
e restituisci un'istanza di MapViewCoodinator
che hai creato nel passaggio precedente.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator(self)
}
}
- Imposta
MapViewCoordinator
come delegato della visualizzazione mappa
Una volta creato il coordinatore personalizzato, il passaggio successivo consiste nell'impostarlo come delegato per la visualizzazione della mappa del controller di visualizzazione. 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
in modo che l'evento di movimento della videocamera possa essere propagato verso l'alto
Poiché l'obiettivo è aggiornare la visualizzazione con i movimenti della videocamera, dichiara una nuova proprietà di chiusura che accetta un valore booleano all'interno di MapViewControllerBridge
chiamata mapViewWillMove
e richiama questa chiusura nel metodo delegato mapView(_, willMove)
all'interno di MapViewCoordinator
. Passa il valore di gesture
alla chiusura in modo che la visualizzazione SwiftUI possa reagire solo agli eventi di movimento della videocamera correlati ai gesti.
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
per inserire un valore per questa nuova chiusura. All'interno della chiusura, imposta lo stato zoomInCenter
su false
se l'evento di movimento è correlato a un gesto. In questo modo, la mappa viene visualizzata di nuovo a schermo intero quando viene spostata con un 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
})
// ...
}
}
}
}
- Esegui l'app per vedere le nuove modifiche.
10. Complimenti
Congratulazioni per aver raggiunto questo traguardo. Hai fatto molta strada e ci auguriamo che le lezioni che hai imparato ti permettano ora di creare la tua app SwiftUI utilizzando Maps SDK for iOS.
Che cosa hai imparato
- Differenze tra SwiftUI e UIKit
- Come creare un ponte tra SwiftUI e UIKit utilizzando UIViewControllerRepresentable
- Come apportare modifiche alla visualizzazione della mappa con State e Binding
- Come inviare un evento dalla visualizzazione della mappa a SwiftUI utilizzando un coordinatore
Passaggi successivi
- Maps SDK for iOS
- documentazione ufficiale di Maps SDK for iOS
- Places SDK for iOS: trova attività locali e punti d'interesse nelle vicinanze
- maps-sdk-for-ios-samples
- codice di esempio su GitHub che mostra tutte le funzionalità dell'SDK Maps per iOS.
- SwiftUI: documentazione ufficiale di Apple su SwiftUI
- Aiutaci a creare i contenuti che ritieni più utili rispondendo al seguente sondaggio:
Quali altri codelab vorresti vedere?
Non riesci a trovare il codelab che ti interessa di più? Richiedilo con un nuovo problema qui.