1. Avant de commencer
Cet atelier de programmation vous explique comment créer une application Maps 3D dans SwiftUI à l'aide du SDK Maps 3D pour iOS.
Vous allez découvrir comment :
- Contrôler la caméra pour afficher des lieux et effectuer un survol de la carte
- Ajouter des repères et des modèles
- Tracer des lignes et des polygones
- Gérer les clics des utilisateurs sur les repères de lieu
Prérequis
- Un projet Google Console avec la facturation activée
- Une clé API, éventuellement limitée au SDK Maps 3D pour iOS.
- Connaissances de base en développement iOS avec SwiftUI.
Objectifs de l'atelier
- Configurer Xcode et importer le SDK à l'aide de Swift Package Manager
- Configurer votre application pour utiliser une clé API
- Ajouter une carte 3D de base à votre application
- Contrôler la caméra pour voler vers des emplacements spécifiques et les contourner
- Ajouter des repères, des lignes, des polygones et des modèles à votre carte
Prérequis
- Xcode 15 ou version ultérieure
2. Configuration
Pour l'étape d'activation suivante, vous devez activer le SDK Maps 3D pour iOS.
Configurer Google Maps Platform
Si vous ne disposez pas encore d'un compte Google Cloud Platform et d'un projet pour lequel la facturation est activée, consultez le guide Premiers pas avec Google Maps Platform pour savoir comment créer un compte de facturation et un projet.
- Dans Cloud Console, cliquez sur le menu déroulant des projets, puis sélectionnez celui que vous souhaitez utiliser pour cet atelier de programmation.
- Activez les API et les SDK Google Maps Platform requis pour cet atelier de programmation dans Google Cloud Marketplace. Pour ce faire, suivez les étapes indiquées dans cette vidéo ou dans cette documentation.
- Générez une clé API sur la page Identifiants de Cloud Console. Vous pouvez suivre la procédure décrite dans cette vidéo ou dans cette documentation. Toutes les requêtes envoyées à Google Maps Platform nécessitent une clé API.
Activer le SDK Maps 3D pour iOS
Pour trouver le SDK Maps 3D pour iOS, utilisez le lien de menu Google Maps Platform > API et services dans la console.
Cliquez sur "Activer" pour activer l'API dans le projet sélectionné.
3. Créer une application SwiftUI de base
Remarque: Vous trouverez le code de solution pour chaque étape dans le dépôt de l'application exemple de l'atelier de programmation sur GitHub .
Créez une application dans Xcode.
Le code de cette étape se trouve dans le dossier GoogleMaps3DDemo sur GitHub.
Ouvrez Xcode et créez une application. Spécifiez SwiftUI.
Appelez votre application GoogleMaps3DDemo
, avec un nom de package com.example.GoogleMaps3DDemo
.
Importer la bibliothèque GoogleMaps3D dans votre projet
Ajoutez le SDK à votre projet à l'aide de Swift Package Manager.
Dans votre projet ou espace de travail Xcode, accédez à File > Add Package Dependencies (Fichier > Ajouter des dépendances de package). Saisissez https://github.com/googlemaps/ios-maps-3d-sdk comme URL, appuyez sur Entrée pour importer le package, puis cliquez sur "Ajouter un package".
Dans la fenêtre "Choisir les produits du package", vérifiez que GoogleMaps3D
sera ajouté à votre cible principale désignée. Une fois cette étape terminée, cliquez sur "Ajouter un package".
Pour vérifier votre installation, accédez au volet "Général" de votre cible. Dans "Frameworks, bibliothèques et contenu intégré", vous devriez voir les packages installés. Vous pouvez également consulter la section "Dépendances de paquets" du Project Navigator pour vérifier le paquet et sa version.
Ajouter votre clé API
Vous pouvez coder en dur votre clé API dans l'application, mais ce n'est pas une bonne pratique. Ajouter un fichier de configuration vous permet de garder votre clé API secrète et d'éviter de la vérifier dans le contrôle des versions.
Créer un fichier de configuration dans le dossier racine du projet
Dans Xcode, assurez-vous d'afficher la fenêtre de l'explorateur de projets. Effectuez un clic droit sur la racine du projet, puis sélectionnez "New File from Template" (Nouveau fichier à partir d'un modèle). Faites défiler la page jusqu'à "Fichier de paramètres de configuration". Sélectionnez cette option, puis cliquez sur "Suivant". Attribuez un nom au fichier (Config.xcconfig
) et assurez-vous que le dossier racine du projet est sélectionné. Cliquez sur "Créer" pour créer le fichier.
Dans l'éditeur, ajoutez une ligne au fichier de configuration comme suit: MAPS_API_KEY = YOUR_API_KEY
Remplacez YOUR_API_KEY
par votre clé API.
Ajoutez ce paramètre à Info.plist
.
Pour ce faire, sélectionnez la racine du projet, puis cliquez sur l'onglet "Infos".
Ajoutez une propriété appelée MAPS_API_KEY
avec une valeur de $(MAPS_API_KEY)
.
L'exemple de code d'application contient un fichier Info.plist
qui spécifie cette propriété.
Ajouter une carte
Ouvrez le fichier nommé GoogleMaps3DDemoApp.swift
. Il s'agit du point d'entrée et de la navigation principale de votre application.
Il appelle ContentView()
, qui affiche un message Hello World.
Ouvrez ContentView.swift
dans l'éditeur.
Ajoutez une instruction import
pour GoogleMaps3D
.
Supprimez le code dans le bloc de code var body: some View {}
. Déclarez un nouvel élément Map()
dans body
.
La configuration minimale requise pour initialiser un Map
est un MapMode
. Il existe deux valeurs possibles:
.hybrid
: images satellite avec routes et libellés, ou.satellite
: images satellite uniquement.
.hybrid
peut vous aider.
Votre fichier ContentView.swift
devrait se présenter comme suit.
import GoogleMaps3D
import SwiftUI
@main
struct ContentView: View {
var body: some View {
Map(mode: .hybrid)
}
}
Définissez votre clé API.
La clé API doit être définie avant l'initialisation de la carte.
Pour ce faire, définissez Map.apiKey
dans le gestionnaire d'événements init()
de tout View
contenant une carte. Vous pouvez également le définir dans GoogleMaps3DDemoApp.swift
avant qu'il n'appelle ContentView()
.
Dans GoogleMaps3DDemoApp.swift
, définissez Map.apiKey
dans le gestionnaire d'événements onAppear
de WindowGroup
.
Récupérer votre clé API à partir du fichier de configuration
Utilisez Bundle.main.infoDictionary
pour accéder au paramètre MAPS_API_KEY
que vous avez créé dans votre fichier de configuration.
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
}
}
}
Créez et exécutez votre application pour vérifier qu'elle se charge correctement. Une carte du globe devrait s'afficher.
4. Utiliser une caméra pour contrôler la vue de la carte
Créer un objet d'état de la caméra
Les vues de carte 3D sont contrôlées par la classe Camera
. Au cours de cette étape, vous allez apprendre à spécifier l'emplacement, l'altitude, l'orientation, l'inclinaison, le roulis et la portée pour personnaliser la vue de la carte.
Créer une classe Helpers pour stocker les paramètres de l'appareil photo
Ajoutez un fichier vide appelé MapHelpers.swift
. Dans votre nouveau fichier, importez GoogleMaps3D
et ajoutez une extension à la classe Camera
. Ajoutez une variable appelée sanFrancisco
. Initialisez cette variable en tant que nouvel objet Camera
. Placez la caméra à latitude: 37.39, longitude: -122.08
.
import GoogleMaps3D
extension Camera {
public static var sanFrancisco: Camera = .init(latitude: 37.39, longitude: -122.08)
}
Ajouter une vue à votre application
Créez un fichier appelé CameraDemo.swift
. Ajoutez au fichier la structure de base d'une nouvelle vue SwiftUI.
Ajoutez une variable @State
appelée camera
, de type Camera
. Initialisez-la sur la caméra sanFrancisco
que vous venez de définir.
L'utilisation de @State
vous permet de lier la carte à l'état de la caméra et de l'utiliser comme source fiable.
@State var camera: Camera = .sanFrancisco
Modifiez l'appel de fonction Map()
pour inclure une propriété camera
. Utilisez la liaison d'état de l'appareil photo $camera
pour initialiser la propriété camera
sur votre objet @State
de l'appareil photo (.sanFrancisco
).
import SwiftUI
import GoogleMaps3D
struct CameraDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
}
}
}
Ajouter une UI de navigation de base à votre application
Ajoutez un NavigationView
au point d'entrée principal de l'application, GoogleMaps3DDemoApp.swift
.
Les utilisateurs pourront ainsi voir une liste de démonstrations et cliquer sur chacune d'elles pour les ouvrir.
Modifiez GoogleMaps3DDemoApp.swift
pour ajouter un NavigationView
.
Ajoutez un List
contenant deux déclarations NavigationLink
.
Le premier NavigationLink
doit ouvrir ContentView()
avec une description Text
Basic Map
.
Le deuxième NavigationLink
doit ouvrir CameraDemo()
.
...
NavigationView {
List {
NavigationLink(destination: ContentView()) {
Text("Basic Map")
}
NavigationLink(destination: CameraDemo()) {
Text("Camera Demo")
}
}
}
...
Ajouter un aperçu Xcode
Les aperçus sont une fonctionnalité Xcode puissante qui vous permet de voir et d'interagir avec votre application lorsque vous y apportez des modifications.
Pour ajouter un aperçu, ouvrez CameraDemo.swift
. Ajoutez un bloc de code #Preview {}
en dehors du struct
.
#Preview {
CameraDemo()
}
Ouvrez ou actualisez le volet d'aperçu dans Xcode. La carte devrait afficher San Francisco.
Configurer des vues 3D personnalisées
Vous pouvez spécifier des paramètres supplémentaires pour contrôler la caméra:
heading
: azimut en degrés à partir du nord vers lequel pointer la caméra.tilt
: angle d'inclinaison en degrés, où 0 correspond à une vue directement au-dessus et 90 à une vue horizontale.roll
: angle de roulis autour du plan vertical de la caméra, en degrésrange
: distance en mètres de la caméra par rapport à la latitude et à la longitudealtitude
: hauteur de la caméra au-dessus du niveau de la mer
Si vous ne fournissez aucun de ces paramètres supplémentaires, des valeurs par défaut seront utilisées.
Pour que la vue de la caméra affiche plus de données 3D, définissez les paramètres initiaux pour afficher une vue plus rapprochée et inclinée.
Modifiez le Camera
que vous avez défini dans MapHelpers.swift
pour inclure des valeurs pour altitude
, heading
, tilt
, roll
et 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)
Compilez et exécutez l'application pour voir et explorer la nouvelle vue 3D.
5. Animations de base de l'appareil photo
Jusqu'à présent, vous avez utilisé la caméra pour spécifier un seul emplacement avec une inclinaison, une altitude, un cap et une portée. À cette étape, vous allez apprendre à déplacer la vue de la caméra en animant ces propriétés d'un état initial à un nouvel état.
S'envoler vers un lieu
Vous allez utiliser la méthode Map.flyCameraTo()
pour animer la caméra de l'emplacement initial vers un nouvel emplacement.
La méthode flyCameraTo()
utilise un certain nombre de paramètres:
- un
Camera
représentant l'emplacement de fin. duration
: durée de l'animation, en secondes.trigger
: objet observable qui déclenche l'animation lorsque son état change.completion
: code qui sera exécuté à la fin de l'animation.
Définir un lieu de destination
Ouvrez votre fichier MapHelpers.swift
.
Définissez un nouvel objet de caméra pour afficher Seattle.
public static var seattle: Camera = .init(latitude:
47.6210296,longitude: -122.3496903, heading: 149.0, tilt: 77.0, roll: 0.0, range: 4000)
Ajoutez un bouton pour déclencher l'animation.
Ouvrez votre CameraDemo.swift
. Déclarez une nouvelle variable booléenne dans struct
.
Appelez-la animate
avec une valeur initiale de false
.
@State private var animate: Bool = false
Ajoutez un Button
sous VStack
. Button
lance l'animation de la carte.
Attribuez à Button
un Text
approprié, tel que "Démarrer le vol".
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") {
}
}
}
}
Dans la fermeture du bouton, ajoutez du code pour inverser l'état de la variable animate
.
Button("Start Flying") {
animate.toggle()
}
Lancez l'animation.
Ajoutez le code pour déclencher l'animation flyCameraTo()
lorsque l'état de la variable animate
change.
var body: some View {
VStack{
Map(camera: $camera, mode: .hybrid)
.flyCameraTo(
.seattle,
duration: 5,
trigger: animate,
completion: { }
)
Button("Start Flying") {
animate.toggle()
}
}
}
Survoler un lieu
Vous pouvez effectuer un survol d'un emplacement à l'aide de la méthode Map.flyCameraAround()
. Cette méthode utilise plusieurs paramètres:
- un
Camera
définissant l'emplacement et la vue. duration
en secondes.rounds
: nombre de répétitions de l'animation.trigger
: objet observable qui déclenchera l'animation.callback
: code qui s'exécutera lorsque l'animation s'exécutera.
Définissez une nouvelle variable @State
appelée flyAround
, avec une valeur initiale de false
.
Ensuite, ajoutez un appel à flyCameraAround()
immédiatement après l'appel de la méthode flyCameraTo()
.
La durée du survol doit être relativement longue pour que le changement de vue soit fluide.
Veillez à déclencher l'animation flyCameraAround()
en modifiant l'état de l'objet déclencheur lorsque flyCameraTo()
est terminé.
Le code doit se présenter comme suit.
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()
}
Prévisualisez ou exécutez l'application pour voir que la caméra fait le tour de la destination une fois l'animation flyCameraTo()
terminée.
6. Ajoutez un repère à votre carte.
Au cours de cette étape, vous allez apprendre à dessiner un repère sur la carte.
Vous allez créer un objet Marker
et l'ajouter à votre carte. Le SDK utilisera une icône par défaut pour le repère. Enfin, vous allez ajuster l'altitude du repère et d'autres propriétés pour modifier son affichage.
Créez une vue SwiftUI pour votre démonstration de repères.
Ajoutez un fichier Swift à votre projet. Nommez-le MarkerDemo.swift
.
Ajoutez le contour d'une vue SwiftUI et initialisez la carte comme vous l'avez fait dans votre CameraDemo
.
import SwiftUI
import GoogleMaps3D
struct MarkerDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
}
}
}
Initialiser un objet Marker
Déclarez une nouvelle variable de repère appelée mapMarker
. En haut du bloc de code struct
dans MarkerDemo.swift
.
Placez la définition sur la ligne sous votre déclaration camera
. Cet exemple de code initialise toutes les propriétés disponibles.
@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"
)
Ajoutez le repère à votre carte.
Pour dessiner le repère, ajoutez-le à une route fermée appelée lors de la création de la carte.
struct MarkerDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
mapMarker
}
}
}
}
Ajoutez un NavigationLink
à GoogleMaps3DDemoApp.swift
avec une destination de MarkerDemo()
et Text
en le décrivant comme "Démo du repère".
...
NavigationView {
List {
NavigationLink(destination: Map()) {
Text("Basic Map")
}
NavigationLink(destination: CameraDemo()) {
Text("Camera Demo")
}
NavigationLink(destination: MarkerDemo()) {
Text("Marker Demo")
}
}
}
...
Prévisualiser et exécuter votre application
Actualisez l'aperçu ou exécutez votre application pour voir le repère.
Repères extrudés
Vous pouvez placer des repères au-dessus du sol ou du maillage 3D à l'aide de altitude
et altitudeMode
.
Copiez la déclaration mapMarker
dans MarkerDemo.swift
dans une nouvelle variable Marker
appelée extrudedMarker
.
Définissez une valeur non nulle pour altitude
. 50 est suffisant.
Remplacez altitudeMode
par .relativeToMesh
et définissez extruded
sur true
. Utilisez latitude
et longitude
dans l'extrait de code ci-dessous pour placer le repère au sommet d'un gratte-ciel.
@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"
)
Exécutez ou prévisualisez à nouveau l'application. Le repère doit apparaître au sommet d'un bâtiment 3D.
7. Ajoutez un modèle à votre carte.
Vous pouvez ajouter un Model
de la même manière qu'un Marker
. Vous aurez besoin d'un fichier de modèle accessible par URL ou ajouté en tant que fichier local dans votre projet. Pour cette étape, nous allons utiliser un fichier local que vous pouvez télécharger à partir du dépôt GitHub de cet atelier de programmation.
Ajouter un fichier de modèle à votre projet
Créez un dossier nommé Models
dans votre projet Xcode.
Téléchargez le modèle à partir du dépôt d'exemples d'applications GitHub. Ajoutez-le à votre projet en le faisant glisser vers le nouveau dossier dans la vue du projet Xcode.
Assurez-vous de définir la cible comme cible principale de votre application.
Vérifiez les paramètres Build Phases > Copy Bundle Resources (Phases de compilation > Copier les ressources du bundle) de votre projet. Le fichier de modèle doit figurer dans la liste des ressources copiées dans le bundle. Si ce n'est pas le cas, cliquez sur + pour l'ajouter.
Ajoutez le modèle à votre application.
Créez un fichier SwiftUI appelé ModelDemo.swift
.
Ajoutez des instructions import
pour SwiftUI
et GoogleMaps3D
comme aux étapes précédentes.
Déclarez un Map
dans un VStack
dans votre body
.
import SwiftUI
import GoogleMaps3D
struct ModelDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
}
}
}
}
Obtenez le chemin d'accès au modèle à partir de votre bundle. Ajoutez le code à l'extérieur de struct
.
private let fileUrl = Bundle.main.url(forResource: "balloon", withExtension: "glb")
Déclarez une variable pour votre modèle dans la structure.
Indiquez une valeur par défaut si fileUrl
n'est pas fourni.
@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. Utilisez le modèle avec votre carte.
Comme pour ajouter un Marker
, il vous suffit de fournir la référence à votre Model
dans la déclaration Map
.
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
balloonModel
}
}
}
Prévisualiser et exécuter votre application
Ajoutez un NavigationLink
à GoogleMaps3DDemoApp.swift
, avec une destination ModelDemo()
et le Text
"Démo du modèle".
...
NavigationLink(destination: ModelDemo()) {
Text("Model Demo")
}
...
Actualisez l'aperçu ou exécutez votre application pour afficher le modèle.
8. Tracez une ligne et un polygone sur votre carte.
Au cours de cette étape, vous allez apprendre à ajouter des lignes et des polygones à votre carte 3D.
Par souci de simplicité, vous allez définir les formes en tant que tableaux d'objets LatLngAltitude
. Dans une application réelle, les données peuvent être chargées à partir d'un fichier, d'un appel d'API ou d'une base de données.
Créez des objets de forme pour gérer les données de forme.
Ajoutez une définition Camera
à MapHelpers.swift
qui examine le centre-ville de San Francisco.
public static var downtownSanFrancisco: Camera = .init(latitude: 37.7905, longitude: -122.3989, heading: 25, tilt: 71, range: 2500)
Ajoutez un fichier nommé ShapesDemo.swift
à votre projet. Ajoutez une struct
appelée ShapesDemo
qui implémente le protocole View
, puis ajoutez-y un body
.
struct ShapesDemo: View {
@State var camera: Camera = .downtownSanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
}
}
}
}
Les classes que vous utiliserez pour gérer les données de forme sont Polyline
et Polygon
. Ouvrez ShapesDemo.swift
et ajoutez-les au struct
comme suit.
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) )
Notez les paramètres d'initialisation utilisés.
altitudeMode: .relativeToGround
permet d'extruder les polygones à une hauteur spécifique au-dessus du sol.altitudeMode: .clampToGround
permet de faire en sorte que la polyligne suive la forme de la surface de la Terre.- Les styles sont définis sur les objets
Polygon
en associant un appel de méthode àstyleOptions()
après l'appel de.init()
.
Ajouter les formes à la carte
Comme dans les étapes précédentes, les formes peuvent être ajoutées directement à la fermeture Map
. Créez votre Map
dans un VStack
.
...
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
polyline
originPolygon
destinationPolygon
}
}
}
...
Prévisualiser et exécuter votre application
Ajoutez du code Preview et inspectez votre application dans le volet Preview (Aperçu) de Xcode.
#Preview {
ShapesDemo()
}
Pour exécuter votre application, ajoutez un NavigationLink
à GoogleMaps3DDemoApp.swift
qui ouvre la nouvelle vue de démonstration.
...
NavigationLink(destination: ShapesDemo()) {
Text("Shapes Demo")
}
...
Exécutez votre application et explorez les formes que vous avez ajoutées.
9. Gérer les événements d'appui sur les repères de lieu
Au cours de cette étape, vous allez apprendre à répondre aux pressions de l'utilisateur sur "Placer des repères".
Remarque: Pour afficher les repères de lieu sur la carte, vous devez définir MapMode
sur .hybrid
.
Pour gérer le tapotement, vous devez implémenter la méthode Map.onPlaceTap
.
L'événement onPlaceTap
fournit un objet PlaceTapInfo
à partir duquel vous pouvez obtenir l'ID de lieu du repère de lieu sélectionné.
Vous pouvez utiliser l'identifiant de lieu pour rechercher d'autres informations à l'aide du SDK Places ou de l'API Places.
Ajouter une vue Swift
Ajoutez le code suivant à un nouveau fichier Swift nommé 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()
}
Prévisualiser et exécuter votre application
Ouvrez le volet d'aperçu pour prévisualiser l'application.
Pour exécuter l'application, ajoutez un NavigationLink
à GoogleMaps3DDemoApp.swift
.
...
NavigationLink(destination: PlaceTapDemo()) {
Text("Place Tap Demo")
}
...
10. (Facultatif) Pour aller plus loin
Animations avancées de la caméra
Certains cas d'utilisation nécessitent une animation fluide sur une séquence ou une liste d'emplacements ou d'états de la caméra, par exemple dans un simulateur de vol ou lors de la relecture d'une randonnée ou d'une course.
Dans cette étape, vous allez apprendre à charger une liste d'emplacements à partir d'un fichier et à animer chaque emplacement dans l'ordre.
Chargez un fichier contenant une séquence d'établissements.
Téléchargez flightpath.json
à partir du dépôt GitHub d'applications exemples.
Créez un dossier nommé JSON
dans votre projet Xcode.
Faites glisser flightpath.json
vers votre dossier JSON
dans Xcode.
Définissez la cible comme étant la cible principale de votre application. Vérifiez que les paramètres de votre projet "Copier les ressources du bundle" incluent ce fichier.
Créez deux fichiers Swift dans votre application, nommés FlightPathData.swift
et FlightDataLoader.swift
.
Copiez le code suivant dans votre application. Ce code crée des structures et des classes qui lisent un fichier local appelé "flighpath.json" et le décodent en tant que fichier JSON.
Les structures FlightPathData
et FlightPathLocation
représentent la structure de données du fichier JSON en tant qu'objets Swift.
La classe FlightDataLoader
lit les données du fichier et les décode. Il adopte le protocole ObservableObject
pour permettre à votre application d'observer les modifications apportées à ses données.
Les données analysées sont exposées via une propriété publiée.
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.")
}
}
}
}
}
Animer la caméra à chaque emplacement
Pour animer la caméra entre une séquence d'étapes, vous devez utiliser un KeyframeAnimator
.
Chaque Keyframe
sera créé en tant que CubicKeyframe
, de sorte que les changements d'état de la caméra soient animés de manière fluide.
L'utilisation de flyCameraTo()
entraînerait un "rebondissement" de la vue entre chaque emplacement.
Commencez par déclarer une caméra appelée "innsbruck" dans 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)
Configurez maintenant une nouvelle vue dans un fichier nommé FlyAlongRoute.swift
.
Importez SwiftUI
et GoogleMaps3D
. Ajoutez un Map
et un Button
dans un VStack
. Configurez Button
pour activer/désactiver l'état de la variable booléenne animation
.
Déclarez un objet State
pour FlightDataLoader
, qui chargera le fichier JSON lors de son initialisation.
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()
}
}
}
}
Créer les images clés
Le processus de base consiste à créer une fonction qui renvoie un nouveau frame dans la séquence d'animation. Chaque nouveau frame définit l'état de la caméra suivant que l'animateur doit animer. Une fois cette fonction créée, appelez-la avec chaque emplacement du fichier dans l'ordre.
Ajoutez deux fonctions à votre struct FlyAlongRoute
. La fonction makeKeyFrame
renvoie un CubicKeyframe
avec un état de la caméra. La fonction makeCamera
prend une étape de la séquence de données de vol et renvoie un objet Camera
représentant l'étape.
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
)
}
Assembler l'animation
Appelez keyframeAnimator
après l'initialisation de Map
et définissez les valeurs initiales.
Vous aurez besoin d'un état initial de la caméra en fonction du premier emplacement du parcours de vol.
L'animation doit se déclencher en fonction d'un changement d'état d'une variable.
Le contenu keyframeAnimator
doit être une carte.
La liste réelle des clés d'animation est générée en parcourant chaque emplacement du parcours de vol.
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])
}
})
}
)
}
Prévisualisez et exécutez votre application.
Ouvrez le volet d'aperçu pour prévisualiser votre vue.
Ajoutez un NavigationLink
avec une destination FlightPathDemo()
à GoogleMaps3DDemoApp.swift
, puis exécutez l'application pour la tester.
11. Félicitations
Vous avez créé une application qui :
- Ajoute une carte 3D de base à votre application.
- Ajoute des repères, des lignes, des polygones et des modèles à votre carte.
- Implémente du code pour contrôler la caméra afin de survoler la carte et des emplacements spécifiques.
Ce que vous avez appris
- Ajouter le package
GoogleMaps3D
à une application SwiftUI Xcode - Initialiser une carte 3D avec une clé API et une vue par défaut
- Ajouter des repères, des modèles 3D, des lignes et des polygones à votre carte
- Contrôler la caméra pour animer un mouvement vers un autre emplacement
- Gérer les événements de clic sur les repères de lieu
Étape suivante
- Consultez le guide du développeur pour en savoir plus sur ce que vous pouvez faire avec le SDK Maps 3D pour iOS.
- Aidez-nous à créer le contenu qui vous semble le plus utile en répondant à l'enquête suivante: