1. Vorbereitung
In diesem Codelab erfahren Sie, wie Sie das Maps SDK for iOS mit SwiftUI verwenden.
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
- Xcode 11.0 oder höher
- Ein Google-Konto mit aktivierter Abrechnung
- Maps SDK for iOS
- Karthago
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.
- 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.
- 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.
- 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.
- 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.
- Nachdem Sie den Code erhalten haben, geben Sie in einem Terminal
cd
in das Verzeichnisstarter/GoogleMapsSwiftUI
ein. - Führen Sie
carthage update --platform iOS
aus, um das Maps SDK for iOS herunterzuladen. - Ö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
: dieUIApplicationDelegate
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 UIKitUIViewController
mit einer Google-Karte (GMSMapView)SceneDelegate
: dieUIWindowSceneDelegate
der Anwendung, aus derContentView
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, dieMapViewController
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, UIView
s und UIViewController
s 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.
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:
- Ö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 liegendeUIViewController
zu erstellen. Hier instanziieren SieUIViewController
und übergeben den Anfangszustand.updateUIViewController(_, context)
: Diese Methode wird von SwiftUI aufgerufen, wenn sich der Status ändert. Hier nehmen Sie alle Änderungen am zugrunde liegendenUIViewController
vor, um auf die Statusänderung zu reagieren.
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.
- Ö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.
- Erstellen Sie ein
MapViewControllerBridge
in der Propertybody
.
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()
} // ...
}
}
}
- 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.
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:
- Deklarieren Sie eine neue
markers
-Property inMapViewControllerBridge
, die mit@Binding
annotiert ist.
MapViewControllerBridge
struct MapViewControllerBridge: : UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
// ...
}
- Aktualisieren Sie in
MapViewControllerBridge
die MethodeupdateUIViewController(_, context)
, um die Eigenschaftmarkers
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 }
}
}
markers
-Property vonContentView
anMapViewControllerBridge
ü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.
- 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.
Karte auf ausgewählte Stadt animieren
So animieren Sie die Karte für eine ausgewählte Stadt:
- 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?
}
MapViewControllerBridge
aktualisieren, um die Karte zu animieren, wenn sichselectedMarker
ä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.
selectedMarker
vonContentView
anMapViewControllerBridge
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:
onAnimationEnded
-Schluss zuMapViewControllerBridge
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()
})
})
}
}
}
}
}
onAnimationEnded
inMapViewControllerBridge
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))
}
}
}
}
- 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:
- Erstelle in
MapViewControllerBridge
einen Koordinator mit dem NamenMapViewCoordinator
.
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
}
}
}
makeCoordinator()
inMapViewControllerBridge
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)
}
}
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
}
}
- 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)
}
}
}
- 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
})
// ...
}
}
}
}
- 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
- Unterschiede zwischen SwiftUI und UIKit
- Mit UIViewControllerRepresentable zwischen SwiftUI und UIKit wechseln
- Kartenansicht mit State und Binding ändern
- Ereignis aus der Kartenansicht mit einem Coordinator an SwiftUI senden
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?
Sie können das Codelab, das Sie am meisten interessiert, nicht finden? Hier können Sie sie mit einem neuen Problem anfordern.