1. Zanim zaczniesz
Dzięki nim dowiesz się, jak używać pakietu SDK Maps na iOS w połączeniu ze SwiftUI.
Wymagania wstępne
- Podstawowe informacje o Swift
- Podstawowe informacje o SwiftUI
Jakie zadania wykonasz:
- Włącz pakiet SDK Maps na iOS i używaj go, aby dodawać Mapy Google do aplikacji za pomocą SwiftUI.
- Dodaj znaczniki na mapie.
- Przekazanie stanu z widoku SwiftUI do obiektu
GMSMapView
i odwrotnie.
Czego potrzebujesz
- Xcode 11.0 lub nowsza wersja;
- konto Google z włączonymi płatnościami.
- Pakiet SDK Map Google na iOS
- Kartagina
2. Konfiguracja
W następnym kroku włącz Pakiet SDK Map Google na iOS.
Konfigurowanie Google Maps Platform
Jeśli nie masz jeszcze konta Google Cloud Platform ani projektu z włączonymi płatnościami, przeczytaj przewodnik Pierwsze kroki z Google Maps Platform, by utworzyć konto rozliczeniowe i projekt.
- W Cloud Console kliknij menu projektu i wybierz projekt, którego chcesz użyć w tym ćwiczeniu z programowania.
- Włącz interfejsy API i pakiety SDK Google Maps Platform wymagane w ramach tego ćwiczenia z ćwiczeń w Google Cloud Marketplace. W tym celu wykonaj czynności opisane w tym filmie lub w tej dokumentacji.
- Wygeneruj klucz interfejsu API na stronie Dane logowania w Cloud Console. Odpowiednie instrukcje znajdziesz w tym filmie lub w tej dokumentacji. Wszystkie żądania wysyłane do Google Maps Platform wymagają klucza interfejsu API.
3. Pobierz kod startowy
Aby ułatwić Ci rozpoczęcie tego ćwiczenia, skorzystaj z tego kodu, który ułatwia rozpoczęcie ćwiczeń z programowania. Zachęcamy do przejścia do rozwiązania, ale jeśli chcesz samodzielnie wykonać wszystkie kroki niezbędne do jego zbudowania, czytaj dalej.
- Skopiuj repozytorium, jeśli masz zainstalowane narzędzie
git
.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git
Możesz też kliknąć poniższy przycisk, aby pobrać kod źródłowy.
- Po otrzymaniu kodu przejdź do terminala
cd
do terminalastarter/GoogleMapsSwiftUI
. - Uruchom aplikację
carthage update --platform iOS
, by pobrać pakiet SDK Maps na iOS - Na koniec otwórz plik
GoogleMapsSwiftUI.xcodeproj
w Xcode.
4. Przegląd kodu
W pobranym przez Ciebie projekcie startowym dodaliśmy i wdrożyliśmy te klasy:
AppDelegate
– aplikacjaUIApplicationDelegate
. W tym miejscu zostanie zainicjowany pakiet SDK Maps na iOS.City
– budowla reprezentująca miasto (zawiera nazwę i współrzędne miasta).MapViewController
– prosty UIKitUIViewController
zawierający mapę Google (GMSMapView).SceneDelegate
- aplikacjaUIWindowSceneDelegate
, z której utworzonoContentView
.
Te zajęcia mają częściowe implementacje i ukończysz je do końca tego ćwiczenia z programowania:
ContentView
– widok aplikacji SwiftUI najwyższego poziomu zawierający Twoją aplikację.MapViewControllerBridge
– klasa łącząca widok UIKit z widokiem SwiftUI. Chodzi w nich o udostępnienieMapViewController
w narzędziu SwiftUI.
5. Używanie SwiftUI a UIKit
SwiftUI został wprowadzony w iOS 13 jako alternatywna platforma interfejsu UIKit do programowania aplikacji na iOS. W porównaniu z poprzednim interfejsem UIKit SwiftUI ma wiele zalet. Oto kilka przykładów:
- Widoki są aktualizowane automatycznie po zmianie stanu. Używanie obiektu o nazwie State w celu wprowadzenia zmian w znajdującej się w nim wartości spowoduje automatyczne zaktualizowanie interfejsu.
- Podgląd na żywo umożliwia szybszy rozwój. Podgląd na żywo minimalizuje kompilację i wdrażanie kodu w emulatorze, aby można było zobaczyć zmiany wizualne, ponieważ podgląd widoku SwiftUI jest łatwo widoczny w Xcode.
- Podstawowym źródłem danych jest Swift. Wszystkie widoki w SwiftUI są deklarowane w Swift, więc używanie interfejsu Builder API nie jest już potrzebne.
- Współdziała z UIKit. Dzięki współdziałaniu z UIKit istniejące aplikacje mogą stopniowo używać SwiftUI z istniejącymi widokami. Oprócz tego biblioteki, które nie obsługują jeszcze SwiftUI, takie jak Maps SDK na iOS, mogą nadal być używane w SwiftUI.
Są też pewne wady:
- SwiftUI jest dostępna tylko na urządzeniach z systemem iOS 13 lub nowszym.
- Hierarchii widoku nie można analizować w podglądach Xcode.
Stan SwiftUI i przepływ danych
SwiftUI oferuje nowatorską metodę tworzenia UI za pomocą deklaratywnego podejścia. Powiedz SwiftUI, jak ma wyglądać Twój widok wraz z różnymi stanami. System zajmie się resztą. SwiftUI obsługuje aktualizowanie widoku w razie zmiany stanu z powodu zdarzenia lub działania użytkownika. Ten projekt jest często nazywany jednokierunkowym przepływem danych. Chociaż szczegóły dotyczące tego projektu nie należą do zakresu tych ćwiczeń z programowania, zalecamy zapoznanie się z dokumentacją State and Data Flow firmy Apple.
Łączenie UIKit i SwiftUI za pomocą UIViewRepresentable lub UIViewControllerRepresentable
Maps SDK na iOS został oparty na UIKit i nie zapewnia jeszcze widoku zgodnego ze SwiftUI. Dlatego używanie go w SwiftUI wymaga spełnienia wymagań UIViewRepresentable
lub UIViewControllerRepresentable
. Te protokoły powodują, że SwiftUI zawiera odpowiednio elementy UIView
i UIViewController
utworzone przez UIKit. Za pomocą dowolnego protokołu możesz dodać mapę Google do widoku SwiftUI, ale w następnym kroku skorzystamy z obiektu UIViewControllerRepresentable
, by dodać UIViewController
do mapy.
6. Dodawanie mapy
W tej sekcji dodasz Mapy Google do widoku SwiftUI.
Dodaj klucz interfejsu API
Klucz interfejsu API utworzony we wcześniejszym kroku należy przekazać do pakietu Maps SDK na iOS, aby można było powiązać konto z mapą, która będzie wyświetlana w aplikacji.
Aby podać klucz interfejsu API, otwórz plik AppDelegate.swift
i przejdź do metody application(_, didFinishLaunchingWithOptions)
. Obecnie pakiet SDK jest inicjowany przez GMSServices.provideAPIKey()
z ciągiem "YOUR_API_KEY". Zastąp ten ciąg swoim kluczem interfejsu API. Ten krok spowoduje zainicjowanie pakietu Maps SDK na iOS po uruchomieniu aplikacji.
Dodawanie mapy za pomocą obiektu MapViewControllerBridge
Po udostępnieniu klucza interfejsu API możesz przesłać mapę w aplikacji.
Kontroler widoku dostępny w kodzie początkowym (MapViewController
) zawiera obecnie GMSMapView
w widoku. Ponieważ ten kontroler widoku został utworzony w UIKit, musisz połączyć tę klasę z SwiftUI, aby można było jej używać w: ContentView
. Aby to zrobić:
- Otwórz plik
MapViewControllerBridge
w Xcode.
Ta klasa jest zgodna z protokołem UIViewControllerRepresentable, który jest wymagany do opakowania UIKit UIViewController
, aby można było go użyć jako widoku SwiftUI. Inaczej mówiąc, zgodność z tym protokołem umożliwia połączenie widoku UIKit z widokiem SwiftUI. Dostosowanie się do tego protokołu wymaga wdrożenia dwóch metod:
makeUIViewController(context)
– ta metoda jest wywoływana przez SwiftUI, by utworzyć podstawowy elementUIViewController
. W tym miejscu utworzysz instancjęUIViewController
i przejdziesz do stanu początkowego.updateUIViewController(_, context)
– ta metoda jest wywoływana przez SwiftUI za każdym razem, gdy zmieni się stan. W tym miejscu możesz wprowadzić zmiany w grupieUIViewController
, aby zareagować na zmiany stanu.
- Utwórz
MapViewController
Utwórz instancję nowego elementu MapViewController
w funkcji makeUIViewController(context)
i zwróć go w wyniku. Gdy to zrobisz, MapViewControllerBridge
powinien wyglądać tak:
Mostek kontrolera widoku mapy
import GoogleMaps
import SwiftUI
struct MapViewControllerBridge: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MapViewController {
return MapViewController()
}
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
}
}
Używanie elementu MapViewControllerBridge w ContentView
Gdy MapViewControllerBridge
tworzy wystąpienie MapViewController
, następnym krokiem jest użycie tej struktury z usługi ContentView
do wyświetlenia mapy.
- Otwórz plik
ContentView
w Xcode.
Wystąpienie ContentView
zostało utworzone w SceneDelegate
i zawiera widok aplikacji najwyższego poziomu. Mapa zostanie dodana z tego pliku.
- Utwórz
MapViewControllerBridge
w obrębie właściwościbody
.
Właściwość ZStack
została już zawarta we właściwości body
tego pliku. ZStack
zawiera obecnie interaktywną i przeciąganą listę miast, których użyjesz w kolejnym kroku. Na razie w usłudze ZStack
utwórz MapViewControllerBridge
jako pierwszy widok podrzędny obiektu ZStack
, aby w aplikacji wyświetlić mapę z listy miast. Zawartość usługi body
w ContentView
powinna wyglądać tak:
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()
} // ...
}
}
}
- Teraz uruchom aplikację. Na ekranie urządzenia powinno pojawić się wczytanie mapy oraz u dołu ekranu możesz przeciągać listę miast.
7. Dodawanie znaczników do mapy
W poprzednim kroku dodano mapę wraz z interaktywną listą zawierającą listę miast. W tej sekcji możesz dodać znaczniki do poszczególnych miast na liście.
Znaczniki jako stan
ContentView
deklaruje obecnie usługę o nazwie markers
, która zawiera listę GMSMarker
domen i deklaruje każde miasto zadeklarowane w usłudze cities
statycznej. Pamiętaj, że ta właściwość jest opatrzona adnotacją opakowującej właściwości SwiftUI State, wskazując, że powinna ona być zarządzana przez SwiftUI. Jeśli więc zostaną wykryte jakiekolwiek zmiany w tej właściwości, np. dodanie lub usunięcie znacznika, zostaną zaktualizowane widoki korzystające z tego stanu.
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
}
Zwróć uwagę, że ContentView
używa właściwości markers
do renderowania listy miast, przekazując ją do klasy CitiesList
.
Lista miast
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)
}
}
}
}
Przekazanie stanu do elementu MapViewControllerBridge za pomocą powiązania
Oprócz listy miast wyświetlających dane z właściwości markers
przekaż tę właściwość do struktury MapViewControllerBridge
, aby można było jej używać do wyświetlania tych znaczników na mapie. Aby go ustawić:
- Zadeklaruj nową właściwość
markers
w:MapViewControllerBridge
z adnotacją@Binding
Mostek kontrolera widoku mapy
struct MapViewControllerBridge: : UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
// ...
}
- Aby skorzystać z właściwości
markers
, w usłudzeMapViewControllerBridge
zaktualizuj metodęupdateUIViewController(_, context)
.
Jak wspomnieliśmy w poprzednim kroku, funkcja SwiftUI będzie wywoływać funkcję updateUIViewController(_, context)
po każdej zmianie stanu. Chcemy zaktualizować mapę w ten sposób, więc będziemy wyświetlać znaczniki w tej lokalizacji: markers
. Aby to zrobić, musisz zaktualizować właściwość map
każdego znacznika. Po wykonaniu tej czynności MapViewControllerBridge
powinien wyglądać tak:
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 }
}
}
- Przekaż właściwość
markers
zContentView
doMapViewControllerBridge
Ponieważ dodano nową usługę w MapViewControllerBridge
, wymaga ona teraz przekazania jej właściwości inicjatora MapViewControllerBridge
. Jeśli więc spróbujesz utworzyć aplikację, zauważysz, że nie skompiluje się. Aby rozwiązać ten problem, zaktualizuj atrybut ContentView
, w którym jest tworzony element MapViewControllerBridge
, i przekaż go w usłudze markers
:
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers)
// ...
}
}
}
}
Zwróć uwagę, że przedrostek $
został użyty w przekierowaniu markers
do MapViewControllerBridge
, ponieważ oczekuje on powiązanej usługi. $
to zarezerwowany prefiks do użycia z kodami przypisanymi do usługi Swift. Zastosowanie do stanu powoduje zwrócenie wiązania.
- Możesz uruchomić aplikację, aby zobaczyć znaczniki na mapie.
8. Animowanie do wybranego miasta
W poprzednim kroku dodano znaczniki do mapy, przekazując stan z jednego widoku SwiftUI do innego. W tym kroku możesz animować miasto/znacznik po kliknięciu go na liście możliwych do interakcji. Aby wprowadzić animację, należy reagować na zmiany w stanie, modyfikując położenie kamery na mapie. Aby dowiedzieć się więcej o pojęciach związanych z aparatem i mapą, zobacz Aparat i widok.
Animacja mapy do wybranego miasta
Aby animować mapę wybranego miasta:
- Zdefiniuj nowe powiązanie w elemencie
MapViewControllerBridge
ContentView
ma właściwość stanową selectedMarker
zainicjowaną do Nini i jest aktualizowana po każdym wybraniu miasta na liście. Jest on obsługiwany przez widok CitiesList
buttonAction
w ContentView
.
ContentView
CitiesList(markers: $markers) { (marker) in
guard self.selectedMarker != marker else { return }
self.selectedMarker = marker
// ...
}
Za każdym razem, gdy selectedMarker
się zmieni, MapViewControllerBridge
musi wiedzieć o tej zmianie, by animować mapę względem wybranego znacznika. Zdefiniuj nowe powiązanie w ramach typu MapViewControllerBridge
typu GMSMarker
i nazwij właściwość selectedMarker
.
Mostek kontrolera widoku mapy
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var selectedMarker: GMSMarker?
}
- Zaktualizuj aplikację
MapViewControllerBridge
, aby animować mapę po każdej zmianie parametruselectedMarker
Po zadeklarowaniu nowego powiązania musisz zaktualizować funkcję updateUIViewController_, context)
MapViewControllerBridge
i to, by mapa animowała się przy użyciu wybranego znacznika. Możesz to zrobić, kopiując poniższy kod:
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)
})
}
}
}
}
}
Funkcja animateToSelectedMarker(viewController)
wykona sekwencję animacji mapy za pomocą funkcji animate(with)
GMSMapView
.
- Przekazanie
selectedMarker
–ContentView
do:MapViewControllerBridge
Po zadeklarowaniu nowego powiązania w MapViewControllerBridge
przejdź dalej i zaktualizuj ContentView
, aby przechodziło przez selectedMarker
, gdzie utworzono instancję MapViewControllerBridge
.
ContentView
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
// ...
}
}
}
}
Osiągnięcie tego kroku spowoduje teraz animowanie mapy po wybraniu nowego miasta na liście.
Animacja widoku SwiftUI podkreślająca miasto
SwiftUI sprawia, że animowanie widoków jest bardzo proste, ponieważ obsługuje on animacje wykonywane podczas przejść stanu. Aby to pokazać, musisz dodać więcej animacji, skupiając się na widoku dla wybranego miasta. Aby to zrobić:
- Dodaj zamknięcie
onAnimationEnded
doMapViewControllerBridge
Animacja SwiftUI będzie wykonywana po wcześniej dodanej sekwencji animacji mapy, więc zadeklaruj nowe zamknięcie o nazwie onAnimationEnded
w obrębie MapViewControllerBridge
i wywołaj to zamknięcie po 0,5 sekundy od ostatniej animacji mapy w metodzie animateToSelectedMarker(viewController)
.
Mostek kontrolera widoku mapy
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()
})
})
}
}
}
}
}
- Wdróż
onAnimationEnded
wMapViewControllerBridge
Wdróż zamknięcie onAnimationEnded
, w którym utworzono instancję MapViewControllerBridge
w ciągu ContentView
. Skopiuj następujący kod i wklej go, aby dodać nowy stan o nazwie zoomInCenter
. Zmienia też widok, używając clipShape
i zmienia średnicę przyciętego kształtu w zależności od wartości 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))
}
}
}
}
- Uruchom aplikację, aby zobaczyć animacje.
9. Wysyłanie wydarzenia do SwiftUI
W tym kroku odsłuchasz zdarzenia generowane przez GMSMapView
i wyślesz je do SwiftUI. W szczególności wyznaczasz osoby wyznaczone w widoku mapy i wykrywasz zdarzenia przemieszczania się zdjęć. Gdy miasto jest zaznaczone, a kamera kamery przesuwa się z gestu, widok mapy jest nieostry, dzięki czemu możesz zobaczyć więcej mapy.
Korzystanie z koordynatorów SwiftUI
GMSMapView
emituje zdarzenia, takie jak zmiana położenia kamery lub kliknięcie znacznika. Mechanizmem nasłuchiwania tych zdarzeń jest protokół GMSMapViewCredential. SwiftUI przedstawia koordynatora, który jest używany jako przedstawiciel kontrolerów widoku UIKit. W świecie SwiftUI koordynator odpowiada za przestrzeganie protokołu GMSMapViewDelegate
. Aby to zrobić:
- Utwórz koordynatora o nazwie
MapViewCoordinator
w domenieMapViewControllerBridge
Utwórz zagnieżdżoną klasę w klasie MapViewControllerBridge
i nazwij ją MapViewCoordinator
. Ta klasa powinna być zgodna z GMSMapViewDelegate
i zadeklarować MapViewControllerBridge
jako właściwość.
Mostek kontrolera widoku mapy
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
var mapViewControllerBridge: MapViewControllerBridge
init(_ mapViewControllerBridge: MapViewControllerBridge) {
self.mapViewControllerBridge = mapViewControllerBridge
}
}
}
- Wdróż
makeCoordinator()
wMapViewControllerBridge
Następnie zaimplementuj metodę makeCoordinator()
w MapViewControllerBridge
i zwróć wystąpienie MapViewCoodinator
, które zostało utworzone w poprzednim kroku.
Mostek kontrolera widoku mapy
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator(self)
}
}
- Ustaw
MapViewCoordinator
jako przedstawiciela na mapie
Po utworzeniu niestandardowego koordynatora należy ustawić go jako osobę, której przekazano dostęp do widoku mapy kontrolera widoku. Aby to zrobić, zaktualizuj inicjację kontrolera widoku w: makeUIViewController(context)
. Utworzony koordynator z poprzedniego kroku będzie dostępny z obiektu Context.
Mostek kontrolera widoku mapy
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeUIViewController(context: Context) -> MapViewController {
let uiViewController = MapViewController()
uiViewController.map.delegate = context.coordinator
return uiViewController
}
- Dodaj zamknięcie w polu
MapViewControllerBridge
, aby kamera mogła przenieść wydarzenie w górę
Ponieważ celem jest zaktualizowanie widoku o ruchu kamery, zadeklaruj nową właściwość zamknięcia, która akceptuje wartość logiczną MapViewControllerBridge
o nazwie mapViewWillMove
, i wywoła to zamknięcie w metodzie przekazywania mapView(_, willMove)
w MapViewCoordinator
. Przekaż wartość gesture
do zamknięcia, aby widok SwiftUI mógł reagować tylko na zdarzenia ruchu kamery związane z gestami.
Mostek kontrolera widoku mapy
struct MapViewControllerBridge: UIViewControllerRepresentable {
var mapViewWillMove: (Bool) -> ()
//...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
// ...
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
self.mapViewControllerBridge.mapViewWillMove(gesture)
}
}
}
- Zaktualizuj element ContentView, by przekazywać wartość
mapWillMove
Po zadeklarowaniu nowej daty zamknięcia MapViewControllerBridge
zaktualizuj ContentView
, by podać wartość tego nowego zamknięcia. W ramach tego zamknięcia ustaw stan zoomInCenter
na false
, jeśli zdarzenie ruchu jest związane z gestem. Mapa zostanie ponownie wyświetlona w pełnym widoku, gdy użytkownik przesunie ją za pomocą gestu.
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
})
// ...
}
}
}
}
- Możesz uruchomić aplikację, aby zapoznać się ze zmianami.
10. Gratulacje
Gratulujemy! Tak daleko! Świetnie Ci idzie i mam nadzieję, że dzięki zdobytym lekcjom udało Ci się stworzyć własną aplikację SwiftUI za pomocą pakietu SDK Maps na iOS.
Czego się nauczysz
- Różnice między SwiftUI a UIKit
- Jak połączyć interfejs SwiftUI z UIKit za pomocą metody UIViewControllerRepresentable
- Jak wprowadzić zmiany w widoku mapy za pomocą atrybutów Stan i Powiązanie
- Jak wysłać wydarzenie z widoku mapy do SwiftUI za pomocą koordynatora
Co dalej?
- Pakiet SDK Map Google na iOS – oficjalna dokumentacja pakietu SDK Map na iOS
- Pakiet SDK Miejsc na iOS – znajduj lokalne firmy i ciekawe miejsca w pobliżu
- maps-sdk-for-ios-samples – przykładowy kod z GitHuba, który pokazuje wszystkie funkcje pakietu Maps SDK na iOS.
- SwiftUI – oficjalna dokumentacja firmy S&ft firmy Apple
- Pomóż nam utworzyć treści, które będą dla Ciebie najbardziej przydatne, odpowiadając na poniższe pytanie:
Jakie inne ćwiczenia z programowania chcesz obejrzeć?
Czy ćwiczeń z programowania nie ma na liście powyżej? Tutaj możesz poprosić o nowy problem.