1. Prima di iniziare
Questo codelab ti insegna a creare un'app di mappe 3D in SwiftUI utilizzando l'SDK Maps 3D per iOS.
Scoprirai:
- Come controllare la fotocamera per visualizzare le posizioni e volare sulla mappa.
- Come aggiungere indicatori e modelli
- Come disegnare linee e poligoni
- Come gestire i clic degli utenti sugli indicatori di luogo.
Prerequisiti
- Un progetto della Console Google con la fatturazione abilitata
- Una chiave API, eventualmente limitata all'SDK Maps 3D per iOS.
- Conoscenza di base dello sviluppo per iOS con SwiftUI.
In questo lab proverai a:
- Configura Xcode e importa l'SDK utilizzando Swift Package Manager
- Configurare l'app per utilizzare una chiave API
- Aggiungere una mappa 3D di base all'app
- Controllare la videocamera per volare verso e intorno a posizioni specifiche
- Aggiungere indicatori, linee, poligoni e modelli alla mappa
Che cosa ti serve
- Xcode 15 o versioni successive.
2. Configurazione
Per il passaggio di attivazione successivo, dovrai abilitare l'SDK Maps 3D per iOS.
Configurare Google Maps Platform
Se non hai ancora un account Google Cloud e un progetto con la fatturazione abilitata, consulta la guida Introduzione 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 nel 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 la procedura descritta in questo video o in questa documentazione. Tutte le richieste a Google Maps Platform richiedono una chiave API.
Attivare l'SDK Maps 3D per iOS
Puoi trovare l'SDK Maps 3D per iOS utilizzando il link del menu Google Maps Platform > API e servizi nella console.
Fai clic su Abilita per attivare l'API nel progetto selezionato.
3. Creare un'app SwiftUI di base
Nota: puoi trovare il codice della soluzione per ogni passaggio nel repository dell'app di esempio di codelab su GitHub .
Crea una nuova app in Xcode.
Il codice per questo passaggio è disponibile nella cartella GoogleMaps3DDemo su GitHub.
Apri Xcode e crea una nuova app. Specifica SwiftUI.
Chiama la tua app GoogleMaps3DDemo
con un nome del pacchetto com.example.GoogleMaps3DDemo
.
Importa la libreria GoogleMaps3D nel progetto
Aggiungi l'SDK al progetto utilizzando Swift Package Manager.
Nel progetto o nello spazio di lavoro Xcode, vai a File > Aggiungi dipendenze del pacchetto. Inserisci https://github.com/googlemaps/ios-maps-3d-sdk come URL, premi Invio per importare il pacchetto e fai clic su "Aggiungi pacchetto".
Nella finestra Scegli i prodotti del pacchetto, verifica che GoogleMaps3D
venga aggiunto al target principale designato. Al termine, fai clic su Aggiungi pacchetto.
Per verificare l'installazione, vai al riquadro Generale del target. In Frameworks, librerie e contenuti incorporati, dovresti vedere i pacchetti installati. Puoi anche visualizzare la sezione Dipendenze del pacchetto di Project Navigator per verificare il pacchetto e la relativa versione.
Aggiungi la tua chiave API
Puoi codificare la chiave API nell'app, ma questa non è una buona prassi. L'aggiunta di un file di configurazione ti consente di mantenere segreta la chiave API ed evita di inserirla nel controllo del codice sorgente.
Crea un nuovo file di configurazione nella cartella principale del progetto
In Xcode, assicurati di visualizzare la finestra Esplora progetti. Fai clic con il tasto destro del mouse sulla directory principale del progetto e seleziona "Nuovo file da modello". Scorri fino a visualizzare "File delle impostazioni di configurazione". Seleziona questa opzione e fai clic su "Avanti". Assegna al file il nome Config.xcconfig
e assicurati che sia selezionata la cartella principale del progetto. Fai clic su "Crea" per creare il file.
Nell'editor, aggiungi una riga al file di configurazione come segue: MAPS_API_KEY = YOUR_API_KEY
Sostituisci YOUR_API_KEY
con la tua chiave API.
Aggiungi questa impostazione a Info.plist
.
Per farlo, seleziona la directory principale del progetto e fai clic sulla scheda "Informazioni".
Aggiungi una nuova proprietà denominata MAPS_API_KEY
con un valore $(MAPS_API_KEY)
.
Il codice dell'app di esempio contiene un file Info.plist
che specifica questa proprietà.
Aggiungere una mappa
Apri il file denominato GoogleMaps3DDemoApp.swift
. Si tratta del punto di ingresso e della navigazione principale della tua app.
Chiama ContentView()
, che mostra un messaggio Hello World.
Apri ContentView.swift
nell'editor.
Aggiungi un'istruzione import
per GoogleMaps3D
.
Elimina il codice all'interno del blocco di codice var body: some View {}
. Dichiara un nuovo Map()
all'interno di body
.
La configurazione minima necessaria per inizializzare un Map
è un MapMode
. Questo valore può assumere due valori:
.hybrid
- immagini satellitari con strade ed etichette oppure.satellite
: solo immagini satellitari.
Scegli .hybrid
.
Il file ContentView.swift
dovrebbe avere il seguente aspetto.
import GoogleMaps3D
import SwiftUI
@main
struct ContentView: View {
var body: some View {
Map(mode: .hybrid)
}
}
Imposta la chiave API.
La chiave API deve essere impostata prima dell'inizializzazione della mappa.
Per farlo, imposta Map.apiKey
nel gestore eventi init()
di qualsiasi View
contenente una mappa. Puoi anche impostarlo in GoogleMaps3DDemoApp.swift
prima che chiami ContentView()
.
In GoogleMaps3DDemoApp.swift
, imposta Map.apiKey
nel gestore di eventi onAppear
di WindowGroup
.
Recupera la chiave API dal file di configurazione
Utilizza Bundle.main.infoDictionary
per accedere all'impostazione MAPS_API_KEY
che hai creato nel file di configurazione.
import GoogleMaps3D
import SwiftUI
@main
struct GoogleMaps3DDemoApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.onAppear {
guard let infoDictionary: [String: Any] = Bundle.main.infoDictionary else {
fatalError("Info.plist not found")
}
guard let apiKey: String = infoDictionary["MAPS_API_KEY"] as? String else {
fatalError("MAPS_API_KEY not set in Info.plist")
}
Map.apiKey = apiKey
}
}
}
Crea ed esegui l'app per verificare che venga caricata correttamente. Dovresti vedere una mappa del globo.
4. Usare una videocamera per controllare la visualizzazione mappa
Creare un oggetto dello stato della videocamera
Le visualizzazioni mappa 3D sono controllate dalla classe Camera
. In questo passaggio imparerai a specificare la posizione, l'altitudine, la direzione, l'inclinazione, il roll e l'intervallo per personalizzare la visualizzazione mappa.
Crea una classe Helpers per memorizzare le impostazioni della videocamera
Aggiungi un nuovo file vuoto denominato MapHelpers.swift
. Nel nuovo file, importa GoogleMaps3D
e aggiungi un'estensione alla classe Camera
. Aggiungi una variabile denominata sanFrancisco
. Inizializza questa variabile come nuovo oggetto Camera
. Individua la videocamera in latitude: 37.39, longitude: -122.08
.
import GoogleMaps3D
extension Camera {
public static var sanFrancisco: Camera = .init(latitude: 37.39, longitude: -122.08)
}
Aggiungere una nuova visualizzazione all'app
Crea un nuovo file denominato CameraDemo.swift
. Aggiungi al file la struttura di base di una nuova visualizzazione SwiftUI.
Aggiungi una variabile @State
denominata camera
di tipo Camera
. Inizializzalo con la videocamera sanFrancisco
che hai appena definito.
L'utilizzo di @State
ti consente di associare la mappa allo stato della videocamera e di utilizzarla come fonte attendibile.
@State var camera: Camera = .sanFrancisco
Modifica la chiamata alla funzione Map()
in modo da includere una proprietà camera
. Utilizza il binding dello stato della videocamera $camera
per inizializzare la proprietà camera
nell'oggetto @State
della videocamera (.sanFrancisco
).
import SwiftUI
import GoogleMaps3D
struct CameraDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
}
}
}
Aggiungere un'interfaccia utente di navigazione di base all'app
Aggiungi un NavigationView
all'entry point principale dell'app, GoogleMaps3DDemoApp.swift
.
In questo modo, gli utenti potranno vedere un elenco di demo e fare clic su ciascuna per aprirla.
Modifica GoogleMaps3DDemoApp.swift
per aggiungere un nuovo NavigationView
.
Aggiungi un List
contenente due dichiarazioni NavigationLink
.
Il primo NavigationLink
deve aprirsi ContentView()
con una Text
descrizione Basic Map
.
Il secondo NavigationLink
dovrebbe aprire CameraDemo()
.
...
NavigationView {
List {
NavigationLink(destination: ContentView()) {
Text("Basic Map")
}
NavigationLink(destination: CameraDemo()) {
Text("Camera Demo")
}
}
}
...
Aggiungere un'anteprima Xcode
Le anteprime sono una potente funzionalità di Xcode che ti consente di visualizzare e interagire con la tua app mentre apporti modifiche.
Per aggiungere un'anteprima, apri CameraDemo.swift
. Aggiungi un blocco di codice #Preview {}
all'esterno di struct
.
#Preview {
CameraDemo()
}
Apri o aggiorna il riquadro di anteprima in Xcode. La mappa dovrebbe mostrare San Francisco.
Configurare le viste 3D personalizzate
Puoi specificare parametri aggiuntivi per controllare la videocamera:
heading
: l'orientamento in gradi da nord verso cui puntare la fotocamera.tilt
: l'angolo di inclinazione in gradi, dove 0 è direttamente sopra la testa e 90 è orizzontale.roll
: l'angolo di roll attorno al piano verticale della fotocamera, in gradirange
: la distanza in metri della fotocamera dalla posizione di latitudine e longitudinealtitude
: l'altezza della fotocamera sopra il livello del mare
Se non fornisci nessuno di questi parametri aggiuntivi, verranno utilizzati i valori predefiniti.
Per fare in modo che la visualizzazione della fotocamera mostri più dati 3D, imposta i parametri iniziali in modo da mostrare una visualizzazione più ravvicinata e inclinata.
Modifica Camera
che hai definito in MapHelpers.swift
in modo da includere i valori per altitude
, heading
, tilt
, roll
e range
public static var sanFrancisco: Camera = .init(
latitude: 37.7845812,
longitude: -122.3660241,
altitude: 585,
heading: 288.0,
tilt: 75.0,
roll: 0.0,
range: 100)
Crea ed esegui l'app per vedere ed esplorare la nuova visualizzazione 3D.
5. Animazioni di base della fotocamera
Finora hai utilizzato la fotocamera per specificare una singola posizione con inclinazione, altitudine, rotta e raggio. In questo passaggio imparerai a spostare la visualizzazione della videocamera animando queste proprietà da uno stato iniziale a uno nuovo.
Vola verso una località
Utilizzerai il metodo Map.flyCameraTo()
per animare la fotocamera dalla posizione iniziale a una nuova posizione.
Il metodo flyCameraTo()
accetta una serie di parametri:
- un
Camera
che rappresenta la stazione di arrivo. duration
: la durata dell'animazione in secondi.trigger
: un oggetto osservabile che attiverà l'animazione quando cambia stato.completion
: il codice che verrà eseguito al termine dell'animazione.
Definisci una località di destinazione
Apri il file MapHelpers.swift
.
Definisci un nuovo oggetto fotocamera per mostrare Seattle.
public static var seattle: Camera = .init(latitude:
47.6210296,longitude: -122.3496903, heading: 149.0, tilt: 77.0, roll: 0.0, range: 4000)
Aggiungi un pulsante per attivare l'animazione.
Apri il CameraDemo.swift
. Dichiara una nuova variabile booleana all'interno di struct
.
Chiamalo animate
con un valore iniziale di false
.
@State private var animate: Bool = false
Aggiungi un Button
sotto il VStack
. Button
avvierà l'animazione della mappa.
Assegna al Button
un Text
appropriato, ad esempio "Inizia a volare".
import SwiftUI
import GoogleMaps3D
struct CameraDemo: View {
@State var camera:Camera = .sanFrancisco
@State private var animate: Bool = false
var body: some View {
VStack{
Map(camera: $camera, mode: .hybrid)
Button("Start Flying") {
}
}
}
}
Nella chiusura del pulsante, aggiungi il codice per attivare/disattivare lo stato della variabile animate
.
Button("Start Flying") {
animate.toggle()
}
Avvia l'animazione.
Aggiungi il codice per attivare l'animazione flyCameraTo()
quando cambia lo stato della variabile animate
.
var body: some View {
VStack{
Map(camera: $camera, mode: .hybrid)
.flyCameraTo(
.seattle,
duration: 5,
trigger: animate,
completion: { }
)
Button("Start Flying") {
animate.toggle()
}
}
}
Volare intorno a una località
È possibile volare intorno a una località utilizzando il metodo Map.flyCameraAround()
. Questo metodo accetta diversi parametri:
- un
Camera
che definisce la posizione e la visualizzazione. duration
in secondi.rounds
: il numero di volte in cui ripetere l'animazione.trigger
: un oggetto osservabile che attiverà l'animazione.callback
: il codice che verrà eseguito quando viene eseguita l'animazione.
Definisci una nuova variabile @State
denominata flyAround
, con un valore iniziale di false
.
Al termine, aggiungi una chiamata a flyCameraAround()
immediatamente dopo la chiamata al metodo flyCameraTo()
.
La durata del sorvolo deve essere relativamente lunga in modo che la visualizzazione cambi senza interruzioni.
Assicurati di attivare l'animazione flyCameraAround()
modificando lo stato dell'oggetto trigger al termine di flyCameraTo()
.
Il codice dovrebbe avere il seguente aspetto.
import SwiftUI
import GoogleMaps3D
struct CameraDemo: View {
@State var camera:Camera = .sanFrancisco
@State private var animate: Bool = false
@State private var flyAround: Bool = false
var body: some View {
VStack{
Map(camera: $camera, mode: .hybrid)
.flyCameraTo(
.seattle,
duration: 5,
trigger: animate,
completion: { flyAround = true }
)
.flyCameraAround(
.seattle,
duration: 15,
rounds: 0.5,
trigger: flyAround,
callback: { }
)
Button("Start Flying") {
animate.toggle()
}
}
}
}
#Preview {
CameraDemo()
}
Visualizza l'anteprima o esegui l'app per verificare che la videocamera voli intorno alla destinazione al termine dell'animazione flyCameraTo()
.
6. Aggiungi un indicatore alla mappa.
In questo passaggio imparerai a disegnare un indicatore sulla mappa.
Dovrai creare un oggetto Marker
e aggiungerlo alla mappa. L'SDK utilizzerà un'icona predefinita per l'indicatore. Infine, dovrai regolare l'altitudine dell'indicatore e altre proprietà per modificarne la visualizzazione.
Crea una nuova visualizzazione SwiftUI per la demo di Marker.
Aggiungi un nuovo file Swift al progetto. Chiamalo MarkerDemo.swift
.
Aggiungi il contorno di una vista SwiftUI e inizializza la mappa come hai fatto in CameraDemo
.
import SwiftUI
import GoogleMaps3D
struct MarkerDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
}
}
}
Inizializzare un oggetto Marker
Dichiara una nuova variabile indicatore denominata mapMarker
. Nella parte superiore del blocco di codice struct
in MarkerDemo.swift
.
Inserisci la definizione nella riga sotto la dichiarazione camera
. Questo codice di esempio inizializza tutte le proprietà disponibili.
@State var mapMarker: Marker = .init(
position: .init(
latitude: 37.8044862,
longitude: -122.4301493,
altitude: 0.0),
altitudeMode: .absolute,
collisionBehavior: .required,
extruded: false,
drawsWhenOccluded: true,
sizePreserved: true,
zIndex: 0,
label: "Test"
)
Aggiungi l'indicatore alla mappa.
Per disegnare l'indicatore, aggiungilo a una chiusura chiamata quando viene creata la mappa.
struct MarkerDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
mapMarker
}
}
}
}
Aggiungi un nuovo NavigationLink
a GoogleMaps3DDemoApp.swift
con una destinazione MarkerDemo()
e Text
descrivendolo come "Marker Demo".
...
NavigationView {
List {
NavigationLink(destination: Map()) {
Text("Basic Map")
}
NavigationLink(destination: CameraDemo()) {
Text("Camera Demo")
}
NavigationLink(destination: MarkerDemo()) {
Text("Marker Demo")
}
}
}
...
Visualizza l'anteprima ed esegui l'app
Aggiorna l'anteprima o esegui l'app per visualizzare l'indicatore.
Indicatori estrusi
I marker possono essere posizionati sopra il suolo o la mesh 3D utilizzando altitude
e altitudeMode
.
Copia la dichiarazione mapMarker
in MarkerDemo.swift
in una nuova variabile Marker
denominata extrudedMarker
.
Imposta un valore diverso da zero per altitude
, 50 è sufficiente.
Modifica altitudeMode
in .relativeToMesh
e imposta extruded
su true
. Utilizza latitude
e longitude
nello snippet di codice qui per posizionare l'indicatore sulla cima di un grattacielo.
@State var extrudedMarker: Marker = .init(
position: .init(
latitude: 37.78980534,
longitude: -122.3969349,
altitude: 50.0),
altitudeMode: .relativeToMesh,
collisionBehavior: .required,
extruded: true,
drawsWhenOccluded: true,
sizePreserved: true,
zIndex: 0,
label: "Extruded"
)
Esegui di nuovo l'app o visualizzane l'anteprima. L'indicatore deve essere visualizzato sopra un edificio 3D.
7. Aggiungi un modello alla mappa.
Un Model
può essere aggiunto nello stesso modo di un Marker
. Avrai bisogno di un file modello a cui è possibile accedere tramite URL o aggiunto come file locale nel progetto. Per questo passaggio utilizzeremo un file locale che puoi scaricare dal repository GitHub per questo codelab.
Aggiungere un file modello al progetto
Crea una nuova cartella nel progetto Xcode denominata Models
.
Scarica il modello dal repository di app di esempio di GitHub. Aggiungilo al progetto trascinandolo nella nuova cartella nella visualizzazione del progetto Xcode.
Assicurati di impostare il target come target principale per la tua app.
Controlla le impostazioni Fase di compilazione > Copia risorse del bundle per il tuo progetto. Il file del modello deve essere nell'elenco delle risorse copiate nel bundle. Se non è presente, fai clic su "+" per aggiungerlo.
Aggiungi il modello all'app.
Crea un nuovo file SwiftUI denominato ModelDemo.swift
.
Aggiungi istruzioni import
per SwiftUI
e GoogleMaps3D
come nei passaggi precedenti.
Dichiara un Map
all'interno di un VStack
nel tuo body
.
import SwiftUI
import GoogleMaps3D
struct ModelDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
}
}
}
}
Recupera il percorso del modello dal tuo bundle. Aggiungi il codice per questo elemento all'esterno di struct
.
private let fileUrl = Bundle.main.url(forResource: "balloon", withExtension: "glb")
Dichiara una variabile per il modello all'interno della struttura.
Fornisci un valore predefinito nel caso in cui fileUrl
non venga fornito.
@State var balloonModel: Model = .init(
position: .init(
latitude: 37.791376,
longitude: -122.397571,
altitude: 300.0),
url: URL(fileURLWithPath: fileUrl?.relativePath ?? ""),
altitudeMode: .absolute,
scale: .init(x: 5, y: 5, z: 5),
orientation: .init(heading: 0, tilt: 0, roll: 0)
)
3. Utilizza il modello con la tua mappa.
Come per l'aggiunta di un Marker
, fornisci il riferimento al tuo Model
nella dichiarazione Map
.
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
balloonModel
}
}
}
Visualizza l'anteprima ed esegui l'app
Aggiungi un nuovo NavigationLink
a GoogleMaps3DDemoApp.swift
, con destinazione ModelDemo()
e Text
"Model Demo".
...
NavigationLink(destination: ModelDemo()) {
Text("Model Demo")
}
...
Aggiorna l'anteprima o esegui l'app per visualizzare il modello.
8. Disegna una linea e un poligono sulla mappa.
In questo passaggio imparerai ad aggiungere linee e forme poligonali alla mappa 3D.
Per semplicità, definirai le forme come array di oggetti LatLngAltitude
. In un'applicazione reale, i dati potrebbero essere caricati da un file, da una chiamata API o da un database.
Crea alcuni oggetti forma per gestire i dati delle forme.
Aggiungi una nuova definizione di Camera
a MapHelpers.swift
che esamini il centro di San Francisco.
public static var downtownSanFrancisco: Camera = .init(latitude: 37.7905, longitude: -122.3989, heading: 25, tilt: 71, range: 2500)
Aggiungi un nuovo file al progetto denominato ShapesDemo.swift
. Aggiungi un struct
denominato ShapesDemo
che implementa il protocollo View
e aggiungi un body
.
struct ShapesDemo: View {
@State var camera: Camera = .downtownSanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
}
}
}
}
Le classi che utilizzerai per gestire i dati delle forme sono Polyline
e Polygon
. Apri ShapesDemo.swift
e aggiungili a struct
come segue.
var polyline: Polyline = .init(coordinates: [
LatLngAltitude(latitude: 37.80515638571346, longitude: -122.4032569467164, altitude: 0),
LatLngAltitude(latitude: 37.80337073509504, longitude: -122.4012878349353, altitude: 0),
LatLngAltitude(latitude: 37.79925208843463, longitude: -122.3976697250461, altitude: 0),
LatLngAltitude(latitude: 37.7989102378512, longitude: -122.3983408725656, altitude: 0),
LatLngAltitude(latitude: 37.79887832784348, longitude: -122.3987094864192, altitude: 0),
LatLngAltitude(latitude: 37.79786443410338, longitude: -122.4066878788802, altitude: 0),
LatLngAltitude(latitude: 37.79549248916587, longitude: -122.4032992702785, altitude: 0),
LatLngAltitude(latitude: 37.78861484290265, longitude: -122.4019489189814, altitude: 0),
LatLngAltitude(latitude: 37.78618687561075, longitude: -122.398969592545, altitude: 0),
LatLngAltitude(latitude: 37.7892310309145, longitude: -122.3951458683092, altitude: 0),
LatLngAltitude(latitude: 37.7916358762409, longitude: -122.3981969390652, altitude: 0)
])
.stroke(GoogleMaps3D.Polyline.StrokeStyle(
strokeColor: UIColor(red: 0.09803921568627451, green: 0.403921568627451, blue: 0.8235294117647058, alpha: 1),
strokeWidth: 10.0,
outerColor: .white,
outerWidth: 0.2
))
.contour(GoogleMaps3D.Polyline.ContourStyle(isGeodesic: true))
var originPolygon: Polygon = .init(outerCoordinates: [
LatLngAltitude(latitude: 37.79165766856578, longitude: -122.3983762901255, altitude: 300),
LatLngAltitude(latitude: 37.7915324439261, longitude: -122.3982171091383, altitude: 300),
LatLngAltitude(latitude: 37.79166617650914, longitude: -122.3980478493319, altitude: 300),
LatLngAltitude(latitude: 37.79178986470217, longitude: -122.3982041104199, altitude: 300),
LatLngAltitude(latitude: 37.79165766856578, longitude: -122.3983762901255, altitude: 300 )
],
altitudeMode: .relativeToGround)
.style(GoogleMaps3D.Polygon.StyleOptions(fillColor:.green, extruded: true) )
var destinationPolygon: Polygon = .init(outerCoordinates: [
LatLngAltitude(latitude: 37.80515661739527, longitude: -122.4034307490334, altitude: 300),
LatLngAltitude(latitude: 37.80503794515428, longitude: -122.4032633416024, altitude: 300),
LatLngAltitude(latitude: 37.80517850164195, longitude: -122.4031056058006, altitude: 300),
LatLngAltitude(latitude: 37.80529346901115, longitude: -122.4032622466595, altitude: 300),
LatLngAltitude(latitude: 37.80515661739527, longitude: -122.4034307490334, altitude: 300 )
],
altitudeMode: .relativeToGround)
.style(GoogleMaps3D.Polygon.StyleOptions(fillColor:.red, extruded: true) )
Tieni presente i parametri di inizializzazione utilizzati.
altitudeMode: .relativeToGround
viene utilizzato per estrudere i poligoni a un'altezza specifica sopra il suolo.altitudeMode: .clampToGround
viene utilizzato per fare in modo che il polilinea segua la forma della superficie terrestre.- gli stili vengono impostati sugli oggetti
Polygon
collegando una chiamata di metodo astyleOptions()
dopo la chiamata a.init()
Aggiungi le forme alla mappa
Come nei passaggi precedenti, le forme possono essere aggiunte direttamente alla chiusura Map
. Crea il Map
all'interno di un VStack
.
...
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
polyline
originPolygon
destinationPolygon
}
}
}
...
Visualizza l'anteprima ed esegui l'app
Aggiungi il codice di anteprima e ispeziona l'app nel riquadro Anteprima di Xcode.
#Preview {
ShapesDemo()
}
Per eseguire l'app, aggiungi un nuovo NavigationLink
a GoogleMaps3DDemoApp.swift
che apra la nuova visualizzazione demo.
...
NavigationLink(destination: ShapesDemo()) {
Text("Shapes Demo")
}
...
Esegui l'app ed esplora le forme che hai aggiunto.
9. Gestire gli eventi di tocco sugli indicatori di luogo
In questo passaggio imparerai a rispondere ai tocchi dell'utente sui segnaposto.
Nota: per visualizzare gli indicatori dei luoghi sulla mappa, devi impostare MapMode
su .hybrid
.
La gestione del tocco richiede l'implementazione del metodo Map.onPlaceTap
.
L'evento onPlaceTap
fornisce un oggetto PlaceTapInfo
da cui puoi ottenere l'ID posizione dell'indicatore di luogo toccato.
Puoi utilizzare l'ID luogo per cercare ulteriori dettagli utilizzando l'SDK Places o l'API Places.
Aggiungere una nuova visualizzazione Swift
Aggiungi il codice seguente a un nuovo file Swift denominato PlaceTapDemo.swift
.
import GoogleMaps3D
import SwiftUI
struct PlaceTapDemo: View {
@State var camera: Camera = .sanFrancisco
@State var isPresented = false
@State var tapInfo: PlaceTapInfo?
var body: some View {
Map(camera: $camera, mode: .hybrid)
.onPlaceTap { tapInfo in
self.tapInfo = tapInfo
isPresented.toggle()
}
.alert(
"Place tapped - \(tapInfo?.placeId ?? "nil")",
isPresented: $isPresented,
actions: { Button("OK") {} }
)
}
}
#Preview {
PlaceTapDemo()
}
Visualizza l'anteprima ed esegui l'app
Apri il riquadro di anteprima per visualizzare l'anteprima dell'app.
Per eseguire l'app, aggiungi un nuovo NavigationLink
a GoogleMaps3DDemoApp.swift
.
...
NavigationLink(destination: PlaceTapDemo()) {
Text("Place Tap Demo")
}
...
10. (Facoltativo) Per saperne di più
Animazioni della fotocamera avanzata
Alcuni casi d'uso richiedono un'animazione fluida lungo una sequenza o un elenco di posizioni o stati della videocamera, ad esempio un simulatore di volo o la riproduzione di una passeggiata o una corsa.
In questo passaggio imparerai a caricare un elenco di località da un file e ad animare ogni località in sequenza.
Carica un file contenente una sequenza di località.
Scarica flightpath.json
dal repository di app di esempio di GitHub.
Crea una nuova cartella nel progetto Xcode denominata JSON
.
Trascina flightpath.json
nella cartella JSON
in Xcode.
Imposta il target principale della tua app. Verifica che le impostazioni delle risorse del pacchetto di copia del progetto includano questo file.
Crea due nuovi file Swift nella tua app denominati FlightPathData.swift
e FlightDataLoader.swift
.
Copia il seguente codice nella tua app. Questo codice crea strutture e classi che leggono un file locale denominato "flighpath.json" e lo decodificano come JSON.
Le strutture FlightPathData
e FlightPathLocation
rappresentano la struttura di dati nel file JSON come oggetti Swift.
La classe FlightDataLoader
legge i dati dal file e li decodifica. Adotta il protocollo ObservableObject
per consentire all'app di osservare le modifiche ai suoi dati.
I dati analizzati vengono esposti tramite una proprietà pubblicata.
FlightPaths.swift
import GoogleMaps3D
struct FlightPathData: Decodable {
let flight: [FlightPathLocation]
}
struct FlightPathLocation: Decodable {
let timestamp: Int64
let latitude: Double
let longitude: Double
let altitude: Double
let bearing: Double
let speed: Double
}
FlightDataLoader.swift
import Foundation
public class FlightDataLoader : ObservableObject {
@Published var flightPathData: FlightPathData = FlightPathData(flight:[])
@Published var isLoaded: Bool = false
public init() {
load("flightpath.json")
}
public func load(_ path: String) {
if let url = Bundle.main.url(forResource: path, withExtension: nil){
if let data = try? Data(contentsOf: url){
let jsondecoder = JSONDecoder()
do{
let result = try jsondecoder.decode(FlightPathData.self, from: data)
flightPathData = result
isLoaded = true
}
catch {
print("Error trying to load or parse the JSON file.")
}
}
}
}
}
Anima la videocamera in ogni posizione
Per animare la fotocamera tra una sequenza di passaggi, utilizzerai un KeyframeAnimator
.
Ogni Keyframe
verrà creato come CubicKeyframe
, in modo che le modifiche dello stato della videocamera siano animate in modo fluido.
L'utilizzo di flyCameraTo()
causerebbe il "rimbalzo" della visualizzazione tra ogni località.
Innanzitutto, dichiara una videocamera chiamata "innsbruck" in MapHelpers.swift
.
public static var innsbruck: Camera = .init(
latitude: 47.263,
longitude: 11.3704,
altitude: 640.08,
heading: 237,
tilt: 80.0,
roll: 0.0,
range: 200)
Ora configura una nuova visualizzazione in un nuovo file denominato FlyAlongRoute.swift
.
Importa SwiftUI
e GoogleMaps3D
. Aggiungi un Map
e un Button
all'interno di un VStack
. Imposta Button
per attivare/disattivare lo stato della variabile booleana animation
.
Dichiara un oggetto State
per FlightDataLoader
, che caricherà il file JSON al momento dell'inizializzazione.
import GoogleMaps3D
import SwiftUI
struct FlyAlongRoute: View {
@State private var camera: Camera = .innsbruck
@State private var flyToDuration: TimeInterval = 5
@State var animation: Bool = true
@StateObject var flightData: FlightDataLoader = FlightDataLoader()
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
Button("Fly Along Route"){
animation.toggle()
}
}
}
}
Crea i fotogrammi chiave
La procedura di base consiste nel creare una funzione che restituisce un nuovo frame nella sequenza di animazione. Ogni nuovo frame definisce lo stato successivo della fotocamera che l'animatore deve animare. Una volta creata questa funzione, chiamala con ogni posizione del file in sequenza.
Aggiungi due funzioni alla struttura FlyAlongRoute
. La funzione makeKeyFrame
restituisce un CubicKeyframe
con uno stato della videocamera. La funzione makeCamera
prende un passaggio nella sequenza di dati di volo e restituisce un oggetto Camera
che lo rappresenta.
func makeKeyFrame(step: FlightPathLocation) -> CubicKeyframe<Camera> {
return CubicKeyframe(
makeCamera(step: step),
duration: flyToDuration
)
}
func makeCamera(step: FlightPathLocation) -> Camera {
return .init(
latitude: step.latitude,
longitude: step.longitude,
altitude: step.altitude,
heading: step.bearing,
tilt: 75,
roll: 0,
range: 200
)
}
Mettere insieme l'animazione
Chiama keyframeAnimator
dopo l'inizializzazione di Map
e imposta i valori iniziali.
Avrai bisogno di uno stato iniziale della videocamera in base alla prima posizione nel percorso di volo.
L'animazione deve essere attivata in base allo stato di una variabile in modifica.
I contenuti di keyframeAnimator
devono essere una mappa.
L'elenco effettivo dei fotogrammi chiave viene generato eseguendo un ciclo in ogni posizione del percorso di volo.
VStack {
Map(camera: $camera, mode: .hybrid)
.keyframeAnimator(
initialValue: makeCamera(step: flightData.flightPathData.flight[0]),
trigger: animation,
content: { view, value in
Map(camera: .constant(value), mode: .hybrid)
},
keyframes: { _ in
KeyframeTrack(content: {
for i in 1...flightData.flightPathData.flight.count-1 {
makeKeyFrame(step: flightData.flightPathData.flight[i])
}
})
}
)
}
Visualizza l'anteprima ed esegui l'app.
Apri il riquadro di anteprima per visualizzare l'anteprima della visualizzazione.
Aggiungi un nuovo NavigationLink
con destinazione FlightPathDemo()
a GoogleMaps3DDemoApp.swift
ed esegui l'app per provarlo.
11. Complimenti
Hai creato un'applicazione che
- Aggiunge una mappa 3D di base alla tua app.
- Aggiunge indicatori, linee, poligoni e modelli alla mappa.
- Implementa il codice per controllare la fotocamera in modo da volare sulla mappa e intorno a posizioni specifiche.
Che cosa hai imparato
- Come aggiungere il pacchetto
GoogleMaps3D
a un'app Xcode SwiftUI. - Come inizializzare una mappa 3D con una chiave API e una visualizzazione predefinita.
- Come aggiungere indicatori, modelli 3D, linee e poligoni alla mappa.
- Come controllare la videocamera per animare il movimento in un'altra posizione.
- Come gestire gli eventi di clic sugli indicatori di luogo.
Passaggi successivi
- Consulta la guida per gli sviluppatori per ulteriori dettagli su cosa puoi fare con l'SDK Maps 3D per iOS.
- Aiutaci a creare i contenuti che ritieni più utili rispondendo al seguente sondaggio: