Karte mit SwiftUI (Swift) in die iOS-App einbinden

1. Vorbereitung

In diesem Codelab lernen Sie, wie Sie das Maps SDK for iOS mit SwiftUI verwenden.

Screenshot-Iphone-12-Schwarz@2x.png

Vorbereitung

  • Grundlegendes Swift-Wissen
  • Grundkenntnisse in SwiftUI

Aufgaben

  • Mithilfe von SwiftUI das Maps SDK for iOS aktivieren und verwenden, um Google Maps einer iOS-App hinzuzufügen
  • Der Karte Markierungen hinzufügen
  • Übergeben Sie den Status von einer SwiftUI-Ansicht an ein GMSMapView-Objekt und umgekehrt.

Voraussetzungen

2. Einrichten

Aktivieren Sie für den folgenden Aktivierungsschritt das Maps SDK for iOS.

Google Maps Platform einrichten

Wenn Sie noch kein Google Cloud Platform-Konto und kein Projekt mit aktivierter Abrechnung haben, lesen Sie den Leitfaden Erste Schritte mit der Google Maps Platform, um ein Rechnungskonto und ein Projekt zu erstellen.

  1. Klicken Sie in der Cloud Console auf das Drop-down-Menü für Projekte und wählen Sie das Projekt aus, das Sie für dieses Codelab verwenden möchten.

  1. Aktivieren Sie im Google Cloud Marketplace die für dieses Codelab erforderlichen Google Maps Platform APIs und SDKs. Folgen Sie dazu der Anleitung in diesem Video oder dieser Dokumentation.
  2. Generieren Sie in der Cloud Console auf der Seite Anmeldedaten einen API-Schlüssel. Folgen Sie der Anleitung in diesem Video oder dieser Dokumentation. Für alle Anfragen an die Google Maps Platform ist ein API-Schlüssel erforderlich.

3. Startcode herunterladen

Damit Sie so schnell wie möglich loslegen können, erhalten Sie hier einen Startcode, den Sie bei diesem Codelab nutzen können. Sie können gerne direkt zur Lösung wechseln. Wenn Sie den Schritten aber selbst folgen möchten, lesen Sie einfach weiter.

  1. Wenn Sie git installiert haben, klonen Sie das Repository.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git

Alternativ können Sie auf die folgende Schaltfläche klicken, um den Quellcode herunterzuladen.

  1. Beim Abrufen des Codes befindet sich das Terminal im Terminal cd in das Verzeichnis starter/GoogleMapsSwiftUI.
  2. Führe das carthage update --platform iOS-Tool aus, um das Maps SDK for iOS herunterzuladen
  3. Öffnen Sie schließlich die Datei GoogleMapsSwiftUI.xcodeproj in Xcode

4. Codeübersicht

Für das heruntergeladene Starter-Projekt wurden die folgenden Kurse bereitgestellt und implementiert:

  • AppDelegate: Die UIApplicationDelegate von der Anwendung Hier wird das Maps SDK for iOS initialisiert.
  • City: Eine Struktur, die eine Stadt darstellt. Sie enthält den Namen und die Koordinaten der Stadt.
  • MapViewController – ein einfaches UIKit-UIViewController-Objekt mit einer Google Maps-Karte (GMSMapView)
  • SceneDelegate ist die UIWindowSceneDelegate-Anwendung, von der ContentView instanziiert wird.

Außerdem werden in den folgenden Klassen nur teilweise Implementierungen ausgeführt und Sie werden bis zum Ende des Codelabs von Ihnen abgeschlossen:

  • ContentView – Die SwiftUI-Ansicht der obersten Ebene, die Ihre App enthält.
  • MapViewControllerBridge: Eine Klasse, die eine UIKit-Ansicht in eine SwiftUI-Ansicht überbrückt. Insbesondere ist dies die Klasse, die MapViewController in SwiftUI zugänglich macht.

5. SwiftUI und UIKit im Vergleich

SwiftUI wurde in iOS 13 als alternatives UI-Framework über UIKit für die Entwicklung von iOS-Apps eingeführt. Verglichen mit der Vorgängerversion von UIKit bietet SwiftUI zahlreiche Vorteile. Hier einige Beispiele:

  • Ansichten werden automatisch aktualisiert, wenn sich der Status ändert. Bei Objekten namens Status wird die Benutzeroberfläche automatisch aktualisiert, wenn der zugrunde liegende Wert geändert wird.
  • Mit der Live-Vorschau lässt sich die Entwicklung beschleunigen. Durch Live-Vorschauen muss kein Code erstellt und bereitgestellt werden, da visuelle Änderungen nötig sind, um die SwiftUI-Vorschau in Xcode darzustellen.
  • Die Informationsquelle lautet „Swift“. Alle Ansichten in SwiftUI werden in Swift deklariert, daher ist die Verwendung von Interface Builder nicht mehr erforderlich.
  • Interoperabilität mit UIKit möglich. Dank der Interoperabilität mit UIKit können bestehende Apps SwiftUI weiterhin mit den bestehenden Ansichten nutzen. Außerdem können Bibliotheken, die SwiftUI noch nicht unterstützen, z. B. das Maps SDK for iOS, weiterhin in SwiftUI verwendet werden.

Einige Nachteile:

  • SwiftUI ist nur auf iOS 13 und höher verfügbar.
  • Die Ansichtshierarchie kann in Xcode-Vorschauen nicht untersucht werden.

SwiftUI-Status und Datenfluss

SwiftUI bietet eine neue Möglichkeit, eine deklarative Herangehensweise zu erstellen. Sie teilen SwiftUI mit, wie Ihre Ansicht zusammen mit den verschiedenen Status dargestellt werden soll. Das System erledigt den Rest. SwiftUI aktualisiert die Ansicht immer dann, wenn sich der zugrunde liegende Status aufgrund eines Ereignisses oder einer Nutzeraktion ändert. Diese Methode wird allgemein als unidirektionaler Datenfluss bezeichnet. Die Details dieses Designs werden in diesem Codelab nicht behandelt. Wir empfehlen Ihnen jedoch, den Abschnitt State and Data Flow in der Dokumentation von Apple durchzulesen.

UIKit und SwiftUI über UIViewRepresentable oder UIViewControllerRepresentable verbinden

Da das Maps SDK for iOS auf einer Benutzeroberfläche (UIKit) basiert, bietet es noch keine mit SwiftUI kompatible Ansicht, sodass sie in SwiftUI verwendet werden kann (entspricht UIViewRepresentable oder UIViewControllerRepresentable). Diese Protokolle ermöglichen es SwiftUI, in UIKit erstellte UIViews bzw. UIViewControllers einzubeziehen. Sie können Google-Karten über beide Protokolle einer SwiftUI-Ansicht hinzufügen. Im nächsten Schritt sehen wir uns jedoch an, wie ein UIViewControllerRepresentable eine UIViewController-Karte mit einer Karte enthält.

6. Karte hinzufügen

In diesem Abschnitt fügen Sie Google Maps einer SwiftUI-Ansicht hinzu.

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

Eigenen API-Schlüssel hinzufügen

Der API-Schlüssel, den Sie in einem vorherigen Schritt erstellt haben, muss an das Maps SDK for iOS gesendet werden, um Ihr Konto mit der Karte zu verknüpfen, die in der App angezeigt wird.

Öffnen Sie die Datei AppDelegate.swift und rufen Sie die Methode application(_, didFinishLaunchingWithOptions) auf, um Ihren API-Schlüssel anzugeben. Derzeit wird das SDK über GMSServices.provideAPIKey() mit dem String {YOUR_API_KEY" initialisiert. Ersetzen Sie diesen String durch Ihren API-Schlüssel. Wenn Sie diesen Schritt abschließen, wird das Maps SDK for iOS beim Start der App initialisiert.

Google Maps-Karte mit MapViewControllerBridge hinzufügen

Nachdem dein API-Schlüssel an das SDK übermittelt wurde, kannst du die Karte in der App aufrufen.

Der Ansichts-Controller, der im Starter-Code enthalten ist, enthält MapViewControllerderzeit eine GMSMapViewAnsicht. Weil dieser Ansichts-Controller jedoch in UIKit erstellt wurde, müssen Sie diesen Kurs mit SwiftUI überbrücken, damit er in ContentView verwendet werden kann. Gehe dazu folgendermaßen vor:

  1. Öffne die Datei MapViewControllerBridge in Xcode.

Diese Klasse entspricht UIViewControllerRepresentable, dem Protokoll, das zum Wrapping von UIKit UIViewController erforderlich ist, damit es als SwiftUI-Ansicht verwendet werden kann. Mit anderen Worten: Wenn Sie dieses Protokoll einhalten, können Sie eine UIKit-Ansicht mit einer SwiftUI-Datenansicht verbinden. Die Einhaltung dieses Protokolls erfordert die Implementierung von zwei Methoden:

  • makeUIViewController(context): Diese Methode wird von SwiftUI aufgerufen, um die zugrunde liegenden UIViewController zu erstellen. Hier würden Sie Ihre UIViewController instanziieren und ihren Anfangszustand übergeben.
  • updateUIViewController(_, context): Diese Methode wird von SwiftUI aufgerufen, wenn sich der Status ändert. Hier würden Sie Änderungen am zugrunde liegenden UIViewController vornehmen, um auf die Statusänderung zu reagieren.
  1. MapViewController erstellen

Instanziiere in der Funktion makeUIViewController(context) eine neue MapViewController und gib sie als Ergebnis zurück. Anschließend sollte der MapViewControllerBridge so aussehen:

MapViewControllerBridge

import GoogleMaps
import SwiftUI

struct MapViewControllerBridge: UIViewControllerRepresentable {

  func makeUIViewController(context: Context) -> MapViewController {
    return MapViewController()
  }

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
  }
}

MapViewControllerBridge in ContentView verwenden

Nachdem MapViewControllerBridge eine Instanz von MapViewController erstellt hat, verwenden Sie als Nächstes diese Struktur in ContentView, um eine Karte anzuzeigen.

  1. Öffne die Datei ContentView in Xcode.

ContentView wird in SceneDelegate instanziiert und enthält die Anwendungsansicht der obersten Ebene. Die Karte wird aus dieser Datei hinzugefügt.

  1. Erstelle eine MapViewControllerBridge in der body-Property.

In der body-Property dieser Datei wurde bereits ein ZStack-Element für Sie bereitgestellt und implementiert. Die ZStack enthält derzeit eine Liste von Städten, die interaktiv sind und dragbar sind, die Sie in einem späteren Schritt verwenden. Erstelle derzeit innerhalb der ZStack ein MapViewControllerBridge als erste untergeordnete Ansicht des ZStack, sodass eine Karte in der App hinter der Liste der Städte angezeigt wird. Danach sollte der Inhalt der body-Property in ContentView so aussehen:

Contentansicht

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. Jetzt kannst du die App ausführen. Du solltest jetzt den Kartenaufruf auf deinem Bildschirm sowie eine dragbare Liste von Städten am unteren Bildschirmrand sehen.

7. Der Karte Markierungen hinzufügen

Im vorigen Schritt haben Sie neben einer interaktiven Liste eine Karte mit einer Liste von Städten hinzugefügt. In diesem Abschnitt fügen Sie für jede Stadt in der Liste Markierungen hinzu.

map-with-markers@2x.png

Markierungen als Bundesland

ContentView deklariert derzeit eine Property namens markers. Das ist eine Liste von GMSMarker für jede Stadt, die in der statischen Property cities angegeben wurde. Diese Property ist mit dem Status der SwiftUI-Property-Anmerkung versehen, um anzugeben, dass sie von SwiftUI verwaltet werden soll. Werden Änderungen mit dieser Eigenschaft erkannt, z. B. das Hinzufügen oder Entfernen einer Markierung, werden Datenansichten mit diesem Status aktualisiert.

Contentansicht

  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
  }

Beachten Sie, dass ContentView die Property markers verwendet, um die Liste der Städte zu rendern und sie an die Klasse CitiesList zu übergeben.

Städteliste

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)
      }
    }
  }
}

Status mithilfe von Bindung an MapViewControllerBridge übergeben

Zusätzlich zur Liste der Städte, für die Daten aus der markers-Property angezeigt werden, muss diese Property an die Struktur MapViewControllerBridge übergeben werden, damit sie auf der Karte angezeigt werden kann. Gehen Sie hierzu folgendermaßen vor:

  1. Deklariere eine neue markers-Property in MapViewControllerBridge, die mit @Binding annotiert ist

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. Aktualisiere in MapViewControllerBridge die Methode updateUIViewController(_, context), um die Property markers zu verwenden

Wie im vorherigen Schritt erwähnt, wird updateUIViewController(_, context) von SwiftUI aufgerufen, wenn sich der Status ändert. Mit dieser Methode, die die Karte aktualisiert werden soll, werden die Markierungen in markers angezeigt. Dazu musst du für jede Markierung die map-Property aktualisieren. Nach Abschluss dieses Schritts sollte MapViewControllerBridge so aussehen:

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. Property markers von ContentView an MapViewControllerBridge übergeben

Da Sie in MapViewControllerBridge eine neue Property hinzugefügt haben, muss der Wert für diese Property jetzt im Initialisierungsmodus für MapViewControllerBridge übergeben werden. Wenn Sie versuchen, eine App zu erstellen, werden Sie feststellen, dass sie nicht kompiliert wird. Führen Sie eine Aktualisierung von ContentView durch, wo MapViewControllerBridge erstellt wird, und übergeben Sie die Property markers folgendermaßen, um das Problem zu beheben:

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers)
        // ...
      }
    }
  }
}

Das Präfix $ wurde zur Übergabe von markers an MapViewControllerBridge verwendet, da eine gebundene Property erwartet wird. $ ist ein reserviertes Präfix für die Verwendung mit Swift-Property-Wrappern. Wenn sie auf einen Bundesstaat angewendet wird, wird eine Bindung zurückgegeben.

  1. Führe die App aus, um die Markierungen auf der Karte zu sehen.

8. Animiert zur ausgewählten Stadt

Im vorherigen Schritt haben Sie einer Karte Markierungen hinzugefügt, indem Sie den Status von einer SwiftUI-Ansicht in eine andere übergeben. In diesem Schritt werden Sie zu einer Stadt/Markierung animiert, nachdem Sie auf die Liste geklickt haben. Um die Animation auszuführen, reagieren Sie auf Änderungen eines Status, indem Sie die Kameraposition beim Ändern der Karte ändern. Weitere Informationen zum Konzept der Kamera finden Sie unter Kamera und Ansicht.

animieren-city@2x.png

Karte zur ausgewählten Stadt animieren

So animieren Sie die Karte zu einer ausgewählten Stadt:

  1. Neue Bindung in MapViewControllerBridge definieren

ContentView hat die Status-Property selectedMarker, die auf null zugeschnitten ist und aktualisiert wird, sobald eine Stadt in der Liste ausgewählt wird. Dies wird von der CitiesList-Datenansicht buttonAction in ContentView verarbeitet.

Contentansicht

CitiesList(markers: $markers) { (marker) in
  guard self.selectedMarker != marker else { return }
  self.selectedMarker = marker
  // ...
}

Jedes Mal, wenn sich selectedMarker ändert, sollte MapViewControllerBridge mit dieser Statusänderung vertraut sein, damit die Karte zur ausgewählten Markierung animiert werden kann. Definieren Sie also eine neue Bindung in MapViewControllerBridge vom Typ GMSMarker und nennen Sie die Property selectedMarker.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?
}
  1. MapViewControllerBridge aktualisieren, um die Karte bei jeder Änderung von selectedMarker zu animieren

Sobald eine neue Bindung deklariert wurde, müssen Sie die Funktion updateUIViewController_, context) von MapViewControllerBridge aktualisieren, damit die Karte mit der ausgewählten Markierung animiert wird. Kopieren Sie dazu einfach den Code unten:

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)
          })
        }
      }
    }
  }
}

Die Funktion animateToSelectedMarker(viewController) führt eine Reihe von Kartenanimationen mithilfe der Funktion animate(with) von GMSMapView aus.

  1. selectedMarker von ContentView an MapViewControllerBridge weitergeben

Sobald MapViewControllerBridge die neue Bindung deklariert hat, aktualisieren Sie ContentView, um die selectedMarker zu übergeben, in der MapViewControllerBridge instanziiert wird.

Contentansicht

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
        // ...
      }
    }
  }
}

Wenn Sie diesen Schritt abschließen, wird die Karte jetzt animiert, wenn eine neue Stadt in der Liste ausgewählt wird.

SwiftUI-Ansicht zur Hervorhebung der Stadt animieren

Die Animation von Ansichten mit SwiftUI ist sehr einfach, da sie Animationen für Statusübergänge verarbeitet. Um dies zu zeigen, fügen Sie weitere Animationen hinzu, indem Sie die Ansicht auf die ausgewählte Stadt ausrichten, nachdem die Kartenanimation abgeschlossen ist. Das funktioniert so:

  1. MapViewControllerBridge eine onAnimationEnded-Sperrung hinzufügen

Da die SwiftUI-Animation nach der zuvor hinzugefügten Kartenanimationssequenz ausgeführt wird, muss eine neue Schließung mit dem Namen onAnimationEnded innerhalb von MapViewControllerBridge deklariert und anschließend mit einer Verzögerung von 0,5 Sekunden nach der letzten Kartenanimation in der animateToSelectedMarker(viewController)-Methode aufgerufen werden.

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. onAnimationEnded in MapViewControllerBridge implementieren

Implementiere die onAnimationEnded-Sperrung, bei der MapViewControllerBridge innerhalb von ContentView instanziiert wird. Kopiere den folgenden Code und füge ihn ein. Dabei wird ein neuer Status namens zoomInCenter hinzugefügt. Außerdem wird die Ansicht mithilfe von clipShape geändert. Der Durchmesser der abgeschnittenen Form hängt vom Wert von zoomInCenter ab.

Contentansicht

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. Starten Sie die App und sehen Sie sich die Animationen an!

9. Ereignis an SwiftUI senden

In diesem Schritt werden die von GMSMapView ausgegebenen Ereignisse überwacht und an SwiftUI gesendet. Insbesondere legen Sie einen Bevollmächtigten für die Kartenansicht fest und erfassen Kamera-Ereignisbewegungen, sodass, wenn eine Stadt fokussiert und die Kamera von einer Geste entfernt wird, die Kartenansicht von der Karte entfernt wird, sodass Sie einen größeren Teil der Karte sehen können.

Verwendung von SwiftUI-Koordinatoren

GMSMapView löst Ereignisse aus, z. B. wenn sich die Kameraposition ändert oder wenn auf eine Markierung getippt wird. Der Mechanismus zur Überwachung dieser Ereignisse erfolgt über das GMSMapViewDelegate-Protokoll. Mit SwiftUI wird das Konzept eines Koordinators vorgestellt, das speziell als Bevollmächtigter für UIKit-Ansicht-Controller verwendet wird. Im SwiftUI-Bereich sollte ein Koordinator also für die Einhaltung des GMSMapViewDelegate-Protokolls verantwortlich sein. Dazu müssen Sie die folgenden Schritte ausführen:

  1. Erstellen Sie einen Koordinator namens MapViewCoordinator in MapViewControllerBridge

Erstelle eine verschachtelte Klasse innerhalb der Klasse MapViewControllerBridge und rufe sie MapViewCoordinator auf. Diese Klasse sollte GMSMapViewDelegate entsprechen und MapViewControllerBridge als Eigenschaft deklarieren.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    var mapViewControllerBridge: MapViewControllerBridge

    init(_ mapViewControllerBridge: MapViewControllerBridge) {
      self.mapViewControllerBridge = mapViewControllerBridge
    }
  }
}
  1. makeCoordinator() in MapViewControllerBridge implementieren

Implementiere als Nächstes die Methode makeCoordinator() in MapViewControllerBridge und gib eine Instanz von MapViewCoodinator zurück, die du im vorherigen Schritt erstellt hast.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeCoordinator() -> MapViewCoordinator {
    return MapViewCoordinator(self)
  }
}
  1. MapViewCoordinator als Bevollmächtigten für die Kartenansicht festlegen

Im nächsten Schritt wird der benutzerdefinierte Koordinator als Bevollmächtigter für die Kartenansicht des Ansichts-Controllers festgelegt. Aktualisieren Sie dazu die Initialisierung des Ansichts-Controllers in makeUIViewController(context). Der erstellte Koordinator des vorherigen Schritts ist über das Kontextobjekt zugänglich.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeUIViewController(context: Context) -> MapViewController {
    let uiViewController = MapViewController()
    uiViewController.map.delegate = context.coordinator
    return uiViewController
  }
  1. Du kannst MapViewControllerBridge einen Ausschluss hinzufügen, damit das Ereignis zum Bewegen der Kamera übertragen werden kann

Da die Ansicht mit den Kamerabewegungen aktualisiert werden soll, muss eine neue Schließen-Eigenschaft deklariert werden, die einen booleschen Wert innerhalb von MapViewControllerBridge mit dem Namen mapViewWillMove akzeptiert und diese Öffnung in der delegierten Methode mapView(_, willMove) in MapViewCoordinator aufruft. Übergeben Sie den Wert von gesture an die Öffnung, damit die SwiftUI-Ansicht nur auf bewegungsbezogene Kamera-Bewegungsereignisse reagieren kann.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  var mapViewWillMove: (Bool) -> ()
  //...

  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    // ...
    func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
      self.mapViewControllerBridge.mapViewWillMove(gesture)
    }
  }
}
  1. Aktualisieren Sie ContentView, um einen Wert für mapWillMove zu übergeben

Wenn die neue Sperrung am MapViewControllerBridge deklariert ist, aktualisieren Sie ContentView, damit ein Wert für diese neue Schließung übergeben wird. Ändere in diesem Fall den Status zoomInCenter in false, wenn sich das Ereignis „Verschieben“ auf eine Geste bezieht. So wird die Karte wieder vollständig angezeigt, wenn die Karte durch eine Geste verschoben wird.

Contentansicht

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. Führe die App aus, um die neuen Änderungen zu sehen.

10. Glückwunsch

Glückwunsch! Sie haben viel gelernt und hoffentlich können Sie mit den gewonnenen Erkenntnissen jetzt Ihre eigene SwiftUI-App mit dem Maps SDK for iOS erstellen.

Das haben Sie gelernt

  • Die Unterschiede zwischen SwiftUI und UIKit
  • Die Überbrückung von SwiftUI und UIKit mit UIViewControllerRepresentable
  • Mit der Funktion State und mit der Bindung Änderungen an der Kartenansicht vornehmen
  • Ereignis über einen Koordinator aus der Kartenansicht an SwiftUI senden

Nächste Schritte

  • Maps SDK for iOS – offizielle Dokumentation zum Maps SDK for iOS
  • Places SDK for iOS: Unternehmen und Sehenswürdigkeiten in der Nähe finden
  • maps-sdk-for-ios-samples – Beispielcode auf GitHub, in dem alle Funktionen im Maps SDK for iOS demonstriert werden.
  • SwiftUI – offizielle Dokumentation zu SwiftUI von Apple
  • Hilf uns, die Inhalte zu erstellen, die für dich am nützlichsten wären. Beantworten Sie dazu die folgende Frage:

Welche weiteren Codelabs möchten Sie sehen?

Datenvisualisierung auf Google Maps Weitere Informationen zum Anpassen des Kartenstils Erstellen von 3D-Interaktionen in Karten

Ist das Codelab, das oben nicht aufgeführt werden soll? Hier können Sie ein neues Problem beantragen.