Karte mit SwiftUI in Ihre iOS-App einfügen (Swift)

1. Vorbereitung

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

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

Vorbereitung

  • Grundlegende Swift-Kenntnisse
  • Grundkenntnisse in SwiftUI

Aufgaben

  • Aktivieren und verwenden Sie das Maps SDK for iOS, um Google Maps mithilfe von SwiftUI in eine iOS-App einzubinden.
  • Fügen Sie der Karte Markierungen hinzu.
  • Status zwischen einem SwiftUI- und einem GMSMapView-Objekt übergeben.

Voraussetzungen

2. Einrichten

Aktivieren Sie im nächsten Schritt Maps SDK for iOS.

Google Maps Platform einrichten

Wenn Sie noch kein Google Cloud-Konto und kein Projekt mit aktivierter Abrechnung haben, lesen Sie bitte den Leitfaden Erste Schritte mit 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 das Projekt und wählen Sie das Projekt aus, das Sie für dieses Codelab verwenden möchten.

  1. Aktivieren Sie die für dieses Codelab erforderlichen APIs und SDKs der Google Maps Platform im Google Cloud Marketplace. Folgen Sie dazu der Anleitung in diesem Video oder dieser Dokumentation.
  2. Generieren Sie einen API-Schlüssel in der Cloud Console auf der Seite Anmeldedaten. Folgen Sie dazu dieser Anleitung 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, finden Sie hier einige Startcodes, die Ihnen helfen, diesem Codelab zu folgen. Sie können direkt zur Lösung springen, aber wenn Sie alle Schritte nachvollziehen möchten, um sie selbst zu erstellen, lesen Sie weiter.

  1. Klonen Sie das Repository, wenn Sie git installiert haben.
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. Nachdem Sie den Code erhalten haben, geben Sie in einem Terminal cd in das Verzeichnis starter/GoogleMapsSwiftUI ein.
  2. Führen Sie carthage update --platform iOS aus, um das Maps SDK for iOS herunterzuladen.
  3. Öffnen Sie die Datei GoogleMapsSwiftUI.xcodeproj in Xcode.

4. Codeübersicht

Im heruntergeladenen Starterprojekt sind die folgenden Klassen für Sie bereitgestellt und implementiert:

  • AppDelegate: die UIApplicationDelegate der Anwendung. Hier wird das Maps SDK for iOS initialisiert.
  • City: Ein Struct, das eine Stadt repräsentiert (enthält einen Namen und die Koordinaten der Stadt).
  • MapViewController – ein eingeschränktes UIKit UIViewController mit einer Google-Karte (GMSMapView)
    • SceneDelegate: die UIWindowSceneDelegate der Anwendung, aus der ContentView instanziiert wird.

Außerdem haben die folgenden Klassen teilweise Implementierungen, die Sie am Ende dieses Codelabs abschließen:

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

5. SwiftUI im Vergleich zu UIKit

SwiftUI wurde in iOS 13 als alternatives UI-Framework zu UIKit für die Entwicklung von iOS-Apps eingeführt. Im Vergleich zum Vorgänger UIKit bietet SwiftUI eine Reihe von Vorteilen. Hier einige Beispiele:

  • Ansichten werden automatisch aktualisiert, wenn sich der Status ändert. Wenn Sie Objekte namens State verwenden, wird die Benutzeroberfläche automatisch aktualisiert, sobald sich der zugrunde liegende Wert ändert.
  • Live-Vorschauen ermöglichen eine schnellere Entwicklung. Live-Vorschauen minimieren die Notwendigkeit, Code zu erstellen und in einem Emulator bereitzustellen, um visuelle Änderungen zu sehen, da eine Vorschau der SwiftUI-Ansicht direkt in Xcode angezeigt werden kann.
  • Die Source of Truth ist in Swift. Alle Ansichten in SwiftUI werden in Swift deklariert. Die Verwendung von Interface Builder ist daher nicht mehr erforderlich.
  • Funktioniert mit UIKit. Die Interoperabilität mit UIKit sorgt dafür, dass bestehende Apps SwiftUI inkrementell mit ihren vorhandenen Ansichten verwenden können. Außerdem können Bibliotheken, die SwiftUI noch nicht unterstützen, wie das Maps SDK for iOS, weiterhin in SwiftUI verwendet werden.

Es gibt aber auch einige Nachteile:

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

SwiftUI-Status und Datenfluss

SwiftUI bietet eine neue Möglichkeit, Benutzeroberflächen mit einem deklarativen Ansatz zu erstellen. Sie geben SwiftUI an, wie Ihre Ansicht aussehen soll, und das System erledigt den Rest. SwiftUI aktualisiert die Ansicht, wenn sich der zugrunde liegende Status aufgrund eines Ereignisses oder einer Nutzeraktion ändert. Dieses Design wird häufig als unidirektionaler Datenfluss bezeichnet. Die genauen Details dieses Designs werden in diesem Codelab nicht behandelt. Wir empfehlen jedoch, in der Apple-Dokumentation zu State and Data Flow nachzulesen, wie das funktioniert.

UIKit und SwiftUI mit UIViewRepresentable oder UIViewControllerRepresentable überbrücken

Da das Maps SDK for iOS auf UIKit basiert und keine SwiftUI-kompatible Ansicht bietet, muss es in SwiftUI entweder UIViewRepresentable oder UIViewControllerRepresentable entsprechen. Diese Protokolle ermöglichen es SwiftUI, UIViews und UIViewControllers einzuschließen, die mit UIKit erstellt wurden. Sie können beide Protokolle verwenden, um einer SwiftUI-Ansicht eine Google-Karte hinzuzufügen. Im nächsten Schritt sehen wir uns an, wie Sie ein UIViewControllerRepresentable verwenden, um ein UIViewController mit einer Karte einzufügen.

6. Karte hinzufügen

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

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

Eigenen API-Schlüssel hinzufügen

Der API-Schlüssel, den Sie in einem früheren Schritt erstellt haben, muss dem Maps SDK for iOS zur Verfügung gestellt werden, damit Ihr Konto mit der Karte verknüpft wird, die in der App angezeigt wird.

Um Ihren API-Schlüssel anzugeben, öffnen Sie die Datei AppDelegate.swift und rufen Sie die Methode application(_, didFinishLaunchingWithOptions) auf. Das SDK wird mit GMSServices.provideAPIKey() und dem String „YOUR_API_KEY“ initialisiert. Ersetzen Sie diesen String durch Ihren API-Schlüssel. Wenn Sie diesen Schritt ausführen, wird das Maps SDK for iOS beim Start der Anwendung initialisiert.

Google Maps-Karte mit MapViewControllerBridge einfügen

Nachdem Sie den API-Schlüssel für das SDK bereitgestellt haben, müssen Sie die Karte in der App anzeigen.

Der im Startcode bereitgestellte Ansichtscontroller MapViewController enthält in seiner Ansicht ein GMSMapView. Da dieser Ansichtscontroller jedoch in UIKit erstellt wurde, müssen Sie diese Klasse in SwiftUI überbrücken, damit sie in ContentView verwendet werden kann. Anleitung:

  1. Öffnen Sie die Datei MapViewControllerBridge in Xcode.

Diese Klasse entspricht UIViewControllerRepresentable, dem Protokoll, das zum Umschließen eines UIKit-UIViewController erforderlich ist, damit es als SwiftUI-Ansicht verwendet werden kann. Mit anderen Worten: Die Einhaltung dieses Protokolls erleichtert die Überbrückung einer UIKit-Ansicht zu einer SwiftUI-Ansicht. Für die Einhaltung dieses Protokolls müssen zwei Methoden implementiert werden:

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

Instanziieren Sie in der Funktion makeUIViewController(context) ein neues MapViewController-Objekt und geben Sie es als Ergebnis zurück. Danach sollte Ihr 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, besteht der nächste Schritt darin, diese Struktur in ContentView zu verwenden, um eine Karte anzuzeigen.

  1. Öffnen Sie die Datei ContentView in Xcode.

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

  1. Erstellen Sie ein MapViewControllerBridge in der Property body.

In der body-Eigenschaft dieser Datei wurde bereits ein ZStack für Sie bereitgestellt und implementiert. ZStack enthält eine interaktive und ziehbare Liste von Städten, die Sie in einem späteren Schritt verwenden. Erstellen Sie vorerst innerhalb von ZStack ein MapViewControllerBridge als erstes untergeordnetes Element von ZStack, damit in der App hinter der Ansicht mit der Liste der Städte eine Karte angezeigt wird. Danach sollte der Inhalt der Property body in ContentView so aussehen:

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. Führen Sie die App nun aus. Die Karte sollte auf dem Display Ihres Geräts geladen werden. Außerdem sollte unten auf dem Display eine verschiebbare Liste mit Städten angezeigt werden.

7. Markierungen zur Karte hinzufügen

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

map-with-markers@2x.png

Markierungen als Status

Mit ContentView wird ein Attribut namens markers deklariert, das eine Liste von GMSMarker ist, die jede in der statischen Eigenschaft cities deklarierte Stadt darstellt. Beachten Sie, dass diese Property mit dem SwiftUI-Property-Wrapper State annotiert ist, um anzugeben, dass sie von SwiftUI verwaltet werden soll. Wenn also Änderungen an dieser Eigenschaft erkannt werden, z. B. das Hinzufügen oder Entfernen einer Markierung, werden Ansichten, die diesen Status verwenden, aktualisiert.

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
  }

Beachten Sie, dass ContentView das Attribut markers verwendet, um die Liste der Städte zu rendern. Dazu wird es an die Klasse CitiesList übergeben.

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

Status mithilfe von @Binding an MapViewControllerBridge übergeben

Übergeben Sie diese Property zusätzlich zur Liste der Städte, in denen Daten aus der markers-Property angezeigt werden, an das MapViewControllerBridge-Struct, damit sie zum Anzeigen dieser Markierungen auf der Karte verwendet werden kann. Gehen Sie hierzu folgendermaßen vor:

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

MapViewControllerBridge

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

Wie im vorherigen Schritt erwähnt, wird updateUIViewController(_, context) von SwiftUI aufgerufen, wenn sich der Status ändert. In dieser Methode soll die Karte aktualisiert werden, damit die Markierungen in markers angezeigt werden. Dazu müssen Sie das Attribut map jedes Markers aktualisieren. Nach Abschluss dieses Schritts sollte Ihr 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. markers-Property von ContentView an MapViewControllerBridge übergeben

Da Sie in MapViewControllerBridge ein neues Attribut hinzugefügt haben, muss der Wert für dieses Attribut jetzt im Initialisierer für MapViewControllerBridge übergeben werden. Wenn Sie also versuchen, die App zu erstellen, sollte sie nicht kompiliert werden. Um das Problem zu beheben, müssen Sie ContentView aktualisieren, wo MapViewControllerBridge erstellt wird, und die markers-Eigenschaft so übergeben:

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

Beachten Sie, dass das Präfix $ verwendet wurde, um markers an MapViewControllerBridge zu übergeben, da dort eine gebundene Property erwartet wird. $ ist ein reserviertes Präfix für die Verwendung mit Swift-Property-Wrappern. Wenn sie auf einen Status angewendet wird, wird ein Binding zurückgegeben.

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

8. Zu einer ausgewählten Stadt animieren

Im vorherigen Schritt haben Sie einer Karte Markierungen hinzugefügt, indem Sie den Status von einer SwiftUI-Ansicht an eine andere übergeben haben. In diesem Schritt wird eine Stadt oder Markierung animiert, nachdem in der interaktiven Liste darauf getippt wurde. Für die Animation reagieren Sie auf Änderungen an einem Status, indem Sie die Kameraposition der Karte ändern, wenn die Änderung eintritt. Weitere Informationen zum Konzept der Kartenkamera finden Sie unter Kamera und Ansicht.

animate-city@2x.png

Karte auf ausgewählte Stadt animieren

So animieren Sie die Karte für eine ausgewählte Stadt:

  1. Neue Bindung in MapViewControllerBridge definieren

ContentView hat ein State-Attribut namens selectedMarker, das mit „nil“ initialisiert wird und immer dann aktualisiert wird, wenn in der Liste eine Stadt ausgewählt wird. Dies wird über die Ansicht CitiesList buttonAction in ContentView abgewickelt.

ContentView

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

Immer wenn sich selectedMarker ändert, sollte MapViewControllerBridge über diese Statusänderung informiert werden, damit die Karte zum ausgewählten Marker animiert werden kann. Definieren Sie also ein neues Binding innerhalb von MapViewControllerBridge vom Typ GMSMarker und nennen Sie die Property selectedMarker.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?
}
  1. MapViewControllerBridge aktualisieren, um die Karte zu animieren, wenn sich selectedMarker ändert

Nachdem eine neue Bindung deklariert wurde, müssen Sie die updateUIViewController_, context)-Funktion von MapViewControllerBridge aktualisieren, damit die Karte zum ausgewählten Marker animiert wird. Kopieren Sie dazu den folgenden Code:

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

Mit der Funktion animateToSelectedMarker(viewController) wird eine Reihe von Kartenanimationen mit der Funktion animate(with) von GMSMapView ausgeführt.

  1. selectedMarker von ContentView an MapViewControllerBridge weitergeben

Sobald MapViewControllerBridge das neue Binding deklariert hat, können Sie ContentView aktualisieren, um selectedMarker zu übergeben, wo MapViewControllerBridge instanziiert wird.

ContentView

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

Wenn Sie diesen Schritt abgeschlossen haben, wird die Karte animiert, sobald eine neue Stadt in der Liste ausgewählt wird.

SwiftUI-Ansicht animieren, um die Stadt hervorzuheben

SwiftUI vereinfacht das Animieren von Ansichten, da es Animationen für Statusübergänge ausführt. Um das zu demonstrieren, fügen Sie weitere Animationen hinzu, indem Sie die Ansicht nach Abschluss der Kartenanimation auf die ausgewählte Stadt fokussieren. Gehen Sie dazu folgendermaßen vor:

  1. onAnimationEnded-Schluss zu MapViewControllerBridge hinzufügen

Da die SwiftUI-Animation nach der zuvor hinzugefügten Kartenanimationssequenz ausgeführt wird, deklarieren Sie innerhalb von MapViewControllerBridge einen neuen Closure namens onAnimationEnded und rufen Sie diesen Closure nach einer Verzögerung von 0,5 Sekunden nach der letzten Kartenanimation in der Methode animateToSelectedMarker(viewController) auf.

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

Implementieren Sie den onAnimationEnded-Abschluss, wobei MapViewControllerBridge in ContentView instanziiert wird. Kopieren Sie den folgenden Code und fügen Sie ihn ein. Dadurch wird ein neuer Status namens zoomInCenter hinzugefügt. Außerdem wird die Ansicht mit clipShape geändert und der Durchmesser der zugeschnittenen Form variiert je nach Wert von 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. Führen Sie die App aus, um die Animationen zu sehen.

9. Ereignis an SwiftUI senden

In diesem Schritt hören Sie auf Ereignisse, die von GMSMapView ausgegeben werden, und senden das Ereignis an SwiftUI. Sie legen einen Delegaten für die Kartenansicht fest und erfassen Ereignisse für Kamerabewegungen. Wenn also eine Stadt im Fokus ist und die Kartenkamera durch eine Geste bewegt wird, wird der Fokus der Kartenansicht aufgehoben, damit Sie mehr von der Karte sehen können.

SwiftUI-Koordinatoren verwenden

GMSMapView gibt Ereignisse aus, z. B. Änderungen der Kameraposition oder wenn auf eine Markierung getippt wird. Das Protokoll GMSMapViewDelegate bietet einen Mechanismus zum Abhören dieser Ereignisse. SwiftUI führt das Konzept eines Koordinators ein, der speziell als Delegat für UIKit-Ansichtscontroller dient. In der SwiftUI-Welt sollte ein Coordinator also für die Einhaltung des GMSMapViewDelegate-Protokolls verantwortlich sein. Dazu müssen Sie die folgenden Schritte ausführen:

  1. Erstelle in MapViewControllerBridge einen Koordinator mit dem Namen MapViewCoordinator.

Erstellen Sie eine verschachtelte Klasse in der Klasse MapViewControllerBridge und nennen Sie sie MapViewCoordinator. Diese Klasse sollte GMSMapViewDelegate entsprechen und MapViewControllerBridge als Attribut deklarieren.

MapViewControllerBridge

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

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

Implementieren Sie als Nächstes die Methode makeCoordinator() in MapViewControllerBridge und geben Sie eine Instanz von MapViewCoodinator zurück, die Sie im vorherigen Schritt erstellt haben.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeCoordinator() -> MapViewCoordinator {
    return MapViewCoordinator(self)
  }
}
  1. MapViewCoordinator als Delegaten der Kartenansicht festlegen

Nachdem der benutzerdefinierte Koordinator erstellt wurde, muss er als Delegat für die Kartenansicht des Ansichtscontrollers festgelegt werden. Aktualisieren Sie dazu die Initialisierung des Ansichts-Controllers in makeUIViewController(context). Der im vorherigen Schritt erstellte Koordinator 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. Fügen Sie MapViewControllerBridge einen Abschluss hinzu, damit das Kameraereignis weitergegeben werden kann.

Da die Ansicht mit den Kamerabewegungen aktualisiert werden soll, deklarieren Sie eine neue Closure-Eigenschaft, die einen booleschen Wert in MapViewControllerBridge akzeptiert, mit dem Namen mapViewWillMove, und rufen Sie diese Closure in der Delegatenmethode mapView(_, willMove) in MapViewCoordinator auf. Übergeben Sie den Wert von gesture an den Closure, damit die SwiftUI-Ansicht nur auf gestenbezogene Kamerabewegungsereignisse 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. ContentView aktualisieren, um einen Wert für mapWillMove zu übergeben

Da die Schließung am MapViewControllerBridge erklärt wurde, müssen Sie ContentView aktualisieren, um einen Wert für diese neue Schließung zu übergeben. Schalten Sie innerhalb dieses Schließvorgangs den Status zoomInCenter auf false um, wenn sich das Ereignis auf eine Geste bezieht. Dadurch wird die Karte wieder in der Vollansicht angezeigt, wenn sie durch eine Geste verschoben wird.

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. Führen Sie die App aus, um sich die neuen Änderungen anzusehen.

10. Glückwunsch

Herzlichen Glückwunsch, dass Sie es bis hierher geschafft haben! Sie haben viel gelernt und hoffentlich können Sie jetzt mit dem Maps SDK for iOS Ihre eigene SwiftUI-App erstellen.

Das haben Sie gelernt

Nächste Schritte

  • Maps SDK for iOS
    • Offizielle Dokumentation zum Maps SDK for iOS
  • Places SDK for iOS: Lokale Unternehmen und Sehenswürdigkeiten in der Nähe finden
  • maps-sdk-for-ios-samples
    • Beispielcode auf GitHub, der alle Funktionen des Maps SDK for iOS demonstriert.
  • SwiftUI – Offizielle Dokumentation von Apple zu SwiftUI
  • Helfen Sie uns, die Inhalte zu erstellen, die für Sie am nützlichsten sind, indem Sie die folgende Umfrage beantworten:

Welche anderen Codelabs würden Sie sich wünschen?

Datenvisualisierung auf Karten Weitere Informationen zum Anpassen des Stils von Karten 3D-Interaktionen in Karten entwickeln

Sie können das Codelab, das Sie am meisten interessiert, nicht finden? Hier können Sie sie mit einem neuen Problem anfordern.