Ajouter une carte à votre application iOS avec SwiftUI (Swift)

1. Avant de commencer

Cet atelier de programmation vous explique comment utiliser le SDK Maps pour iOS avec SwiftUI.

screenshot-iphone-12-black@2x.png

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

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.

  1. Dans Cloud Console, cliquez sur le menu déroulant des projets, puis sélectionnez celui que vous souhaitez utiliser pour cet atelier de programmation.

  1. 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.
  2. 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.

  1. 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.

  1. Une fois le code obtenu, ouvrez un terminal et utilisez la commande cd pour accéder au répertoire starter/GoogleMapsSwiftUI.
  2. Exécutez carthage update --platform iOS pour télécharger le SDK Maps pour iOS.
  3. 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ément UIWindowSceneDelegate de l'application à partir duquel ContentView 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 rend MapViewController 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.

add-a-map-screenshot@2x.png

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 :

  1. 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ément UIViewController sous-jacent. C'est là que vous instanciez votre UIViewController 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ément UIViewController sous-jacent pour réagir à ce changement d'état.
  1. 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.

  1. 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.

  1. 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()
      } // ...
    }
  }
}
  1. 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.

map-with-markers@2x.png

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 :

  1. déclarez une nouvelle propriété markers dans MapViewControllerBridge, annotée avec @Binding.

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. Dans MapViewControllerBridge, mettez à jour la méthode updateUIViewController(_, 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 }
  }
}
  1. Transmettez la propriété markers de ContentView à 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.

  1. 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.

animate-city@2x.png

Animer la carte au niveau de la ville sélectionnée

Pour animer la carte au niveau de la ville sélectionnée :

  1. 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?
}
  1. Mettez à jour MapViewControllerBridge pour animer la carte chaque fois que selectedMarker 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.

  1. Transmettez selectedMarker de ContentView à 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 :

  1. 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()
            })
          })
        }
      }
    }
  }
}
  1. Implémentez onAnimationEnded dans MapViewControllerBridge.

Implémentez la route fermée onAnimationEndedMapViewControllerBridge 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))
      }
    }
  }
}
  1. 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 :

  1. Créez un coordinateur appelé MapViewCoordinator dans MapViewControllerBridge.

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
    }
  }
}
  1. Implémentez makeCoordinator() dans MapViewControllerBridge.

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)
  }
}
  1. 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
  }
  1. 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)
    }
  }
}
  1. 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
        })
        // ...
      }
    }
  }
}
  1. 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

É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 ?

Visualisation des données sur les cartes En savoir plus sur la personnalisation du style de mes cartes Concevoir des interactions 3D dans Google Maps

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.