1. Avant de commencer
Cet atelier de programmation vous explique comment utiliser le SDK Maps pour iOS avec SwiftUI.
Conditions préalables
- Connaissances de base en Swift
- Connaissances de base en SwiftUI
Objectifs de l'atelier
- Activer et utiliser le SDK Maps pour iOS afin d'ajouter Google Maps à une application iOS avec SwiftUI
- Ajouter des repères à la carte
- Transmettre l'état d'une vue SwiftUI à un objet
GMSMapView
et inversement
Prérequis
- Xcode 11.0 ou version ultérieure
- Un compte Google pour lequel la facturation est activée
- SDK Maps pour iOS
- Carthage
2. Configuration
Pour l'étape suivante, activez le SDK Maps pour iOS.
Configurer Google Maps Platform
Si vous ne disposez pas encore d'un compte Google Cloud Platform ni 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.
3. Télécharger le code de démarrage
Voici un code de démarrage qui vous permettra de commencer rapidement cet atelier de programmation. Vous pouvez tout à fait passer directement au résultat, mais si vous souhaitez voir toutes les étapes et les réaliser de votre côté, poursuivez votre lecture.
- Clonez le dépôt si vous avez installé
git
.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git
Vous pouvez également cliquer sur le bouton suivant pour télécharger le code source.
- Une fois le code obtenu, ouvrez un terminal et utilisez la commande
cd
pour accéder au répertoirestarter/GoogleMapsSwiftUI
. - Exécutez
carthage update --platform iOS
pour télécharger le SDK Maps pour iOS. - Enfin, ouvrez le fichier
GoogleMapsSwiftUI.xcodeproj
dans Xcode.
4. Présentation du code
Dans le projet initial que vous avez téléchargé, les classes suivantes ont été fournies et implémentées pour vous :
AppDelegate
:UIApplicationDelegate
de l'application. C'est ici que le SDK Maps pour iOS sera initialisé.City
: structure qui représente une ville (contient son nom et ses coordonnées).MapViewController
:UIViewController
UIKit simple contenant une carte Google Maps (GMSMapView).SceneDelegate
: élémentUIWindowSceneDelegate
de l'application à partir duquelContentView
est instancié.
En outre, les classes suivantes seront partiellement implémentées, et vous devrez les terminer d'ici la fin de cet atelier de programmation :
ContentView
: vue racine SwiftUI contenant votre application.MapViewControllerBridge
: classe qui relie une vue UIKit à une vue SwiftUI. Plus précisément, il s'agit de la classe qui rendMapViewController
accessible dans SwiftUI.
5. SwiftUI par rapport à UIKit
SwiftUI a été lancé sous iOS 13 afin de développer des applications iOS, en tant que framework d'interface utilisateur remplaçant UIKit. Par rapport à son prédécesseur UIKit, SwiftUI présente plusieurs avantages, dont les suivants :
- Les vues sont automatiquement mises à jour lorsque l'état change. Avec des objets État, toute modification de la valeur sous-jacente contenue par l'état entraîne la mise à jour automatique de l'interface utilisateur.
- Grâce aux aperçus en direct, le développement est plus rapide. Ils évitent d'avoir à créer et à déployer du code au niveau d'un émulateur pour visualiser les modifications, car un aperçu de la vue SwiftUI est facilement visible sur Xcode.
- Swift contient une source d'informations fiable. Toutes les vues dans SwiftUI sont déclarées dans Swift. Il n'est donc plus nécessaire d'utiliser Interface Builder.
- SwiftUI et UIKit sont synchronisés. Cette interopérabilité permet aux applications existantes d'utiliser SwiftUI de manière incrémentale avec leurs vues existantes. De plus, les bibliothèques qui ne sont pas encore compatibles avec SwiftUI, comme le SDK Maps pour iOS, peuvent toujours être utilisées dans SwiftUI.
Cependant, SwiftUI présente aussi quelques inconvénients :
- Il est uniquement disponible sous iOS 13 ou version ultérieure.
- La hiérarchie des vues ne peut pas être examinée dans les aperçus Xcode.
État et flux de données SwiftUI
SwiftUI propose une méthode innovante pour créer une interface utilisateur à l'aide d'une approche déclarative : vous indiquez à SwiftUI l'apparence souhaitée pour votre vue ainsi que ses différents états, et le système se charge du reste. SwiftUI gère la mise à jour de la vue chaque fois que l'état sous-jacent change en raison d'un événement ou d'une action de l'utilisateur. Cette conception est couramment appelée flux de données unidirectionnel. Bien que les détails de cette conception ne soient pas traités dans cet atelier de programmation, nous vous recommandons de vous familiariser avec son fonctionnement grâce au document d'Apple sur l'état et le flux de données.
Relier UIKit et SwiftUI à l'aide de UIViewRepresentable ou UIViewControllerRepresentable
Étant donné que le SDK Maps pour iOS repose sur l'UIKit et qu'il ne fournit pas encore de vue compatible avec SwiftUI, vous devez vous conformer à UIViewRepresentable
ou UIViewControllerRepresentable
pour l'utiliser dans SwiftUI. Ces protocoles permettent à SwiftUI d'inclure respectivement des éléments UIView
et UIViewController
créés par UIKit. Bien que vous puissiez utiliser l'un ou l'autre de ces protocoles pour ajouter une carte Google Maps à une vue SwiftUI, nous allons voir à l'étape suivante comment utiliser un UIViewControllerRepresentable
pour inclure un UIViewController
contenant une carte.
6. Ajouter une carte
Dans cette section, vous allez ajouter une carte Google Maps à une vue SwiftUI.
Ajouter votre clé API
Vous devez fournir au SDK Maps pour iOS la clé API que vous avez créée précédemment, afin de pouvoir associer votre compte à la carte qui s'afficherait dans l'application.
Pour fournir votre clé API, ouvrez le fichier AppDelegate.swift
et accédez à la méthode application(_, didFinishLaunchingWithOptions)
. Actuellement, le SDK est initialisé via GMSServices.provideAPIKey()
avec la chaîne "YOUR_API_KEY". Remplacez cette chaîne par votre clé API. Cette étape initialise le SDK Maps pour iOS lorsque l'application est lancée.
Ajouter une carte Google Maps à l'aide de MapViewControllerBridge
Maintenant que votre clé API est transmise au SDK, vous devez afficher la carte dans l'application.
Le contrôleur de vue fourni dans le code de démarrage MapViewController
contient actuellement GMSMapView
dans sa vue. Cependant, comme il a été créé dans UIKit, vous devrez relier cette classe à SwiftUI afin de pouvoir l'utiliser dans ContentView
. Pour ce faire :
- Ouvrez le fichier
MapViewControllerBridge
dans Xcode.
Cette classe est conforme à UIViewControllerRepresentable, le protocole nécessaire pour encapsuler un UIViewController
UIKit afin de pouvoir l'utiliser en tant que vue SwiftUI. En d'autres termes, le respect de ce protocole vous permet de relier une vue UIKit à une vue SwiftUI. Pour respecter le protocole, vous devez mettre en œuvre deux méthodes :
makeUIViewController(context)
: cette méthode est appelée par SwiftUI pour créer l'élémentUIViewController
sous-jacent. C'est là que vous instanciez votreUIViewController
et lui transmettez son état initial.updateUIViewController(_, context)
: cette méthode est appelée par SwiftUI lorsque l'état change. C'est là que vous apportez des modifications à l'élémentUIViewController
sous-jacent pour réagir à ce changement d'état.
- Créez un
MapViewController
.
Dans la fonction makeUIViewController(context)
, instanciez un nouveau MapViewController
et renvoyez-le en tant que résultat. Votre MapViewControllerBridge
devrait alors se présenter comme suit :
MapViewControllerBridge
import GoogleMaps
import SwiftUI
struct MapViewControllerBridge: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MapViewController {
return MapViewController()
}
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
}
}
Utiliser MapViewControllerBridge dans ContentView
Maintenant que MapViewControllerBridge
crée une instance de MapViewController
, l'étape suivante consiste à utiliser cette structure dans ContentView
pour afficher une carte.
- Ouvrez le fichier
ContentView
dans Xcode.
ContentView
est instancié dans SceneDelegate
et contient la vue d'ensemble de l'application. La carte sera ajoutée à partir de ce fichier.
- Créez un
MapViewControllerBridge
dans la propriétébody
.
Dans la propriété body
de ce fichier, un ZStack
a déjà été fourni et implémenté pour vous. Le ZStack
contient actuellement une liste de villes (interactive et déplaçable) que vous utiliserez plus tard. Pour l'instant, dans ZStack
, créez un MapViewControllerBridge
en tant que première vue enfant de ZStack
: une carte s'affiche alors dans l'application derrière la vue de liste des villes. Ce faisant, le contenu de la propriété body
dans ContentView
devrait ressembler à ceci :
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()
} // ...
}
}
}
- Exécutez à présent l'application. La carte devrait se charger sur l'écran de votre appareil, avec une liste déplaçable de villes (vers le bas de l'écran).
7. Ajouter des repères à la carte
À l'étape précédente, vous avez ajouté une carte ainsi qu'une liste interactive contenant plusieurs villes. Dans cette section, vous allez ajouter des repères pour chaque ville de cette liste.
Repères en tant qu'état
ContentView
déclare actuellement une propriété appelée markers
, à savoir une liste de GMSMarker
représentant chaque ville déclarée dans la propriété statique cities
. Notez que cette propriété est annotée avec le wrapper de propriété État de SwiftUI pour indiquer qu'elle doit être gérée par SwiftUI. Par conséquent, si des modifications sont détectées dans cette propriété (par exemple, si vous ajoutez ou supprimez un repère), les vues utilisant cet état seront mises à jour.
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
}
Notez que ContentView
utilise la propriété markers
pour afficher la liste des villes en la transmettant à la 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)
}
}
}
}
Transmettre l'état à MapViewControllerBridge via une liaison
En plus de la liste des villes qui affiche les données de la propriété markers
, transmettez cette propriété à la structure MapViewControllerBridge
afin de pouvoir l'utiliser pour afficher ces repères sur la carte. Pour ce faire :
- déclarez une nouvelle propriété
markers
dansMapViewControllerBridge
, annotée avec@Binding
.
MapViewControllerBridge
struct MapViewControllerBridge: : UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
// ...
}
- Dans
MapViewControllerBridge
, mettez à jour la méthodeupdateUIViewController(_, context)
pour pouvoir utiliser la propriétémarkers
.
Comme indiqué à l'étape précédente, updateUIViewController(_, context)
sera appelé par SwiftUI à chaque modification de l'état. C'est dans cette méthode que nous souhaitons mettre à jour la carte pour afficher les repères dans markers
. Pour ce faire, vous devez mettre à jour la propriété map
de chaque repère. Une fois cette étape terminée, votre MapViewControllerBridge
devrait se présenter comme suit :
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 }
}
}
- Transmettez la propriété
markers
deContentView
àMapViewControllerBridge
.
Étant donné que vous avez ajouté une propriété dans MapViewControllerBridge
, la valeur de cette propriété doit désormais être transmise dans l'initialiseur pour MapViewControllerBridge
. Si vous essayez de créer l'application, vous remarquerez sans doute l'absence de compilation. Pour résoudre ce problème, effectuez une mise à jour de ContentView
où le MapViewControllerBridge
est créé et transmettez la propriété markers
comme suit :
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers)
// ...
}
}
}
}
Vous remarquerez que le préfixe $
a été utilisé pour transmettre markers
à MapViewControllerBridge
, car il attend une propriété liée. $
est un préfixe réservé à utiliser avec les wrappers de propriété Swift. Lorsqu'il est appliqué à un état, il renvoie une liaison.
- Exécutez à présent l'application pour voir les repères affichés sur la carte.
8. Animer la carte au niveau de la ville sélectionnée
À l'étape précédente, vous avez ajouté des repères à une carte en transmettant l'état d'une vue SwiftUI à une autre. À cette étape, vous allez animer la carte au niveau d'une ville/d'un repère après avoir appuyé dessus dans la liste interactive. Pour exécuter l'animation, vous réagissez aux changements d'état en modifiant la position de la caméra de la carte lorsque la modification se produit. Pour en savoir plus sur le concept de caméra de la carte, consultez Caméra et vue.
Animer la carte au niveau de la ville sélectionnée
Pour animer la carte au niveau de la ville sélectionnée :
- définissez une nouvelle liaison dans
MapViewControllerBridge
.
ContentView
comporte une propriété d'état appelée selectedMarker
, initialisée sur "zéro". Elle est mise à jour chaque fois qu'une ville est sélectionnée dans la liste. Cela est géré par l'élément buttonAction
permettant d'afficher la vue CitiesList
dans ContentView
.
ContentView
CitiesList(markers: $markers) { (marker) in
guard self.selectedMarker != marker else { return }
self.selectedMarker = marker
// ...
}
Chaque fois que selectedMarker
change, MapViewControllerBridge
doit être informé de ce changement d'état pour pouvoir animer la carte au niveau du repère sélectionné. Ainsi, définissez une nouvelle liaison dans MapViewControllerBridge
de type GMSMarker
et nommez la propriété selectedMarker
.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var selectedMarker: GMSMarker?
}
- Mettez à jour
MapViewControllerBridge
pour animer la carte chaque fois queselectedMarker
change.
Une fois qu'une nouvelle liaison a été déclarée, vous devez mettre à jour la fonction updateUIViewController_, context)
de MapViewControllerBridge
afin que la carte s'anime au niveau du repère sélectionné. Pour ce faire, copiez le code ci-dessous :
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 fonction animateToSelectedMarker(viewController)
effectue une séquence d'animations de carte à l'aide de la fonction animate(with)
de GMSMapView
.
- Transmettez
selectedMarker
deContentView
àMapViewControllerBridge
.
Une fois que MapViewControllerBridge
a déclaré la nouvelle liaison, mettez alors à jour ContentView
pour transmettre l'élément selectedMarker
lorsque que MapViewControllerBridge
est instancié.
ContentView
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
// ...
}
}
}
}
Une fois cette étape terminée, la carte s'anime chaque fois qu'une nouvelle ville est sélectionnée dans la liste.
Animer une vue SwiftUI pour mettre en avant une ville
SwiftUI facilite l'animation des vues, car il gère l'exécution des animations pour les transitions d'état. Pour illustrer cela, vous allez ajouter d'autres animations en axant la vue sur la ville sélectionnée une fois l'animation de la carte terminée. Pour ce faire, procédez comme suit :
- Ajoutez une route fermée
onAnimationEnded
àMapViewControllerBridge
.
L'animation SwiftUI étant exécutée après la séquence d'animation de la carte que vous avez ajoutée précédemment, déclarez une nouvelle route fermée appelée onAnimationEnded
dans MapViewControllerBridge
. Appelez cette fermeture 0,5 seconde après la dernière animation de carte dans la méthode 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()
})
})
}
}
}
}
}
- Implémentez
onAnimationEnded
dansMapViewControllerBridge
.
Implémentez la route fermée onAnimationEnded
où MapViewControllerBridge
est instancié dans ContentView
. Copiez et collez le code suivant, qui ajoute un état appelé zoomInCenter
. Il modifie également la vue en utilisant clipShape
et fait varier le diamètre de la forme tronquée en fonction de la valeur de 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))
}
}
}
}
- Vous pouvez maintenant exécuter l'application pour voir les animations.
9. Envoyer un événement à SwiftUI
Au cours de cette étape, vous allez écouter les événements émis à partir de GMSMapView
et les envoyer à SwiftUI. Plus précisément, vous allez définir un délégué pour la vue plan et écouter les événements de mouvement de la caméra. Ainsi, lorsqu'une ville fait l'objet d'un zoom avant et que la caméra bouge sous l'effet d'un geste, un zoom arrière se produit dans la vue plan. Vous disposez alors d'une plus grande superficie visible sur la carte.
Utiliser les coordinateurs SwiftUI
GMSMapView
émet des événements tels que des changements de position de la caméra ou lorsqu'un utilisateur appuie sur un repère. Le mécanisme d'écoute de ces événements passe par le protocole GMSMapViewDelegate. SwiftUI lance le concept de coordinateur, qui joue spécifiquement le rôle de délégué au niveau des contrôleurs de vue UIKit. Dans l'environnement SwiftUI, un coordinateur doit traiter des questions de conformité avec le protocole GMSMapViewDelegate
. Pour ce faire, procédez comme suit :
- Créez un coordinateur appelé
MapViewCoordinator
dansMapViewControllerBridge
.
Créez une classe imbriquée dans la classe MapViewControllerBridge
, puis appelez-la MapViewCoordinator
. Cette classe doit se conformer à GMSMapViewDelegate
et déclarer MapViewControllerBridge
comme propriété.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
var mapViewControllerBridge: MapViewControllerBridge
init(_ mapViewControllerBridge: MapViewControllerBridge) {
self.mapViewControllerBridge = mapViewControllerBridge
}
}
}
- Implémentez
makeCoordinator()
dansMapViewControllerBridge
.
Implémentez ensuite la méthode makeCoordinator()
dans MapViewControllerBridge
et renvoyez une instance du MapViewCoodinator
que vous avez créé à l'étape précédente.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator(self)
}
}
- Définissez
MapViewCoordinator
comme délégué de la vue plan.
Une fois le coordinateur personnalisé créé, définissez-le à l'étape suivante en tant que délégué pour la vue plan du contrôleur de vue. Pour ce faire, mettez à jour l'initialisation du contrôleur de vue dans makeUIViewController(context)
. Le coordinateur créé à l'étape précédente est accessible depuis l'objet "Context".
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeUIViewController(context: Context) -> MapViewController {
let uiViewController = MapViewController()
uiViewController.map.delegate = context.coordinator
return uiViewController
}
- Ajoutez une route fermée à
MapViewControllerBridge
pour permettre à l'événement de mouvement de la caméra d'être appliqué.
L'objectif étant de mettre à jour la vue avec les mouvements de la caméra, déclarez une nouvelle propriété de route fermée qui accepte une valeur booléenne dans MapViewControllerBridge
, appelée mapViewWillMove
. Appelez alors cette fermeture dans la méthode de délégué mapView(_, willMove)
dans MapViewCoordinator
. Transmettez la valeur de gesture
à la route fermée afin que la vue SwiftUI ne puisse réagir qu'aux événements de mouvement de la caméra liés aux gestes.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
var mapViewWillMove: (Bool) -> ()
//...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
// ...
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
self.mapViewControllerBridge.mapViewWillMove(gesture)
}
}
}
- Mettez à jour ContentView pour transmettre une valeur pour
mapWillMove
.
La nouvelle route fermée étant déclarée dansMapViewControllerBridge
, modifiez ContentView
pour transmettre une valeur à cette nouvelle fermeture. Au niveau de cette route fermée, définissez l'état zoomInCenter
sur false
si l'événement de mouvement est lié à un geste. Cela permet d'afficher à nouveau la carte en mode complet lorsque vous la faites bouger d'un geste.
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
})
// ...
}
}
}
}
- Vous pouvez maintenant exécuter l'application pour voir les nouvelles modifications.
10. Félicitations
Vous êtes arrivé à la fin, félicitations ! Vous avez terminé un programme bien rempli. Nous espérons que les connaissances acquises vous permettront de créer votre propre application SwiftUI à l'aide du SDK Maps pour iOS.
Ce que vous avez appris
- Les différences entre SwiftUI et UIKit
- Relier SwiftUI et UIKit à l'aide de UIViewControllerRepresentable
- Modifier la vue plan avec État et Liaison
- Envoyer un événement à SwiftUI depuis la vue plan à l'aide d'un Coordinateur
Étapes suivantes
- SDK Maps pour iOS : documentation officielle sur le SDK Maps pour iOS
- SDK Places pour iOS : trouver des points d'intérêt et des établissements locaux
- maps-sdk-for-ios-samples : exemple de code sur GitHub illustrant toutes les fonctionnalités du SDK Maps pour iOS
- SwiftUI : documentation officielle d'Apple sur SwiftUI
- Aidez-nous à créer le contenu qui vous semble le plus utile en répondant à la question ci-dessous :
Quels autres ateliers de programmation souhaiteriez-vous voir ?
L'atelier de programmation que vous souhaitez suivre ne figure pas dans la liste ci-dessus ? Demandez-le en décrivant un nouveau problème ici.