1. לפני שתתחיל
ב-Codelab הזה אתם יכולים ללמוד איך להשתמש ב-SDK של מפות Google ל-iOS עם SwiftUI.
דרישות מוקדמות
- בסיסי של Swift
- היכרות בסיסית עם SwiftUI
הפעולות שתבצעו:
- יש להפעיל את ה-SDK של מפות Google ל-iOS ולהשתמש בו כדי להוסיף את מפות Google לאפליקציה ל-iOS באמצעות SwiftUI.
- הוספת סמנים למפה.
- אפשר להעביר מצב מתצוגת SwiftUI לאובייקט
GMSMapView
ולהפך.
מה תצטרך להכין
- Xcode 11.0 ואילך
- חשבון Google עם חיוב מופעל
- SDK של מפות ל-iOS
- עגלה
2. להגדרה
בשלב הבא של ההפעלה, מפעילים את SDK של מפות Google ל-iOS.
הגדרת מפות Google
אם עדיין אין לכם חשבון Google Cloud Platform ופרויקט שבו מופעל חיוב, כדאי לעיין במדריך תחילת העבודה עם הפלטפורמה של מפות Google ליצירת חשבון לחיוב ופרויקט.
- ב-Cloud Console, לוחצים על התפריט הנפתח של הפרויקט ובוחרים את הפרויקט שבו רוצים להשתמש ב-Codelab הזה.
- מפעילים את ממשקי ה-API ואת ערכות ה-SDK של מפות Google הנדרשים למעבדת קוד זו ב-Google Cloud Marketplace. כדי לעשות זאת, יש לבצע את השלבים המפורטים בסרטון הזה או בתיעוד הזה.
- יוצרים מפתח API בדף פרטי הכניסה ב-Cloud Console. ניתן לבצע את השלבים המפורטים בסרטון הזה או בתיעוד הזה. לכל הבקשות שנשלחות לפלטפורמה של מפות Google נדרש מפתח API.
3. להורדת הקוד למתחילים
כדי לעזור לך להתחיל במהירות האפשרית, לפניך קוד התחלה שיעזור לך לעקוב אחר שיעור Lab זה. אתם מוזמנים לקפוץ לפתרון, אבל אם אתם רוצים להמשיך בכל השלבים בעצמכם, המשיכו לקרוא.
- משכפלים את המאגר אם
git
מותקן.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git
לחלופין, אפשר ללחוץ על הלחצן הבא כדי להוריד את קוד המקור.
- עם קבלת הקוד, במסוף
cd
אל המחוזstarter/GoogleMapsSwiftUI
. - כדי להוריד את ה-SDK של מפות Google ל-iOS, יש להפעיל
carthage update --platform iOS
- לבסוף, פותחים את הקובץ
GoogleMapsSwiftUI.xcodeproj
ב-Xcode
4. סקירה כללית של הקוד
בפרויקט למתחילים שהורדת, השיעורים הבאים סופקו לך ויושמו עבורך:
AppDelegate
- האפליקציה שלUIApplicationDelegate
. כאן יופעל ה-SDK של מפות Google ל-iOS.City
- מבנה שמייצג עיר (מכיל שם וקואורדינטה של העיר).MapViewController
– ממשק משתמש פשוט ב-UIKitUIViewController
שמכיל מפת Google (GMSmapView)SceneDelegate
- האפליקציה שלUIWindowSceneDelegate
שממנה נוצר אובייקטContentView
.
בנוסף, לכיתות הבאות יש הטמעות חלקיות והן יבוצעו על ידך עד סוף ה-Codelab הזה:
ContentView
– תצוגת ה-SwitUI ברמה העליונה שמכילה את האפליקציה שלך.MapViewControllerBridge
– כיתה שמגשרת עם תצוגה של UIKit לתצוגה של SwiftUI. באופן ספציפי, זוהי הכיתה שתהפוך אתMapViewController
לנגיש ב-SwiifUI.
5. באמצעות SwiftUI לעומת UIKit
SwiftUI הושק ב-iOS 13 כמסגרת ממשק משתמש חלופית עבור UIKit, לפיתוח אפליקציות ל-iOS. בהשוואה ל-UIKit הקודם שלו, ל-SififUI יש כמה יתרונות. הנה כמה שמות:
- התצוגות מתעדכנות באופן אוטומטי כאשר המצב משתנה. שימוש באובייקטים שנקרא State, כל שינוי בערך הבסיס שהוא מכיל יגרום לעדכון ממשק המשתמש באופן אוטומטי.
- התצוגה המקדימה בזמן אמת מאפשרת פיתוח מהיר יותר. תצוגות מקדימות בשידור חי מצמצמות את הצורך בבנייה ובפריסה של קוד לאמולטור כדי לראות שינויים חזותיים בתצוגה מקדימה של התצוגה המפורטת של SwiftUI ב-Xcode.
- מקור העובדות הוא בסוויפט. כל הצפיות ב-SififUI מוצהרות ב-Swift, כך שאין יותר צורך להשתמש ב-API Builder.
- אינטראקציה עם UIKit. יכולת הפעולה ההדדית עם UIKit מבטיחה שאפליקציות קיימות יוכלו להשתמש ב-SwiftUI יחד עם התצוגות הקיימות שלהן. כמו כן, ניתן להשתמש בספריות ב-SwiifUI שעדיין לא תומכות בספריות SwiftUI, כמו ה-SDK של מפות Google ל-iOS.
יש גם כמה חסרונות:
- SwiftUI זמין רק ב-iOS 13 ומעלה.
- לא ניתן לבדוק את היררכיית התצוגה המקדימה בתצוגות מקדימות של Xcode.
מצב SwiftUI וזרימת הנתונים
SwiftUI מציע דרך חדשנית ליצירת ממשק משתמש בגישה הצהרתית - עליך לומר ל-SwittUI כיצד ברצונך שהתצוגה המפורטת שלך תבחן את כל המצבים השונים, והמערכת לעשות את כל השאר. SwiftUI מטפל בעדכון התצוגה בכל פעם שמצב הבסיס משתנה עקב אירוע או פעולת משתמש. העיצוב הזה נקרא בדרך כלל תהליך נתונים חד-כיווני. למרות שהעיצוב הספציפי הזה אינו בטווח של מעבדת הקוד הזו, מומלץ לקרוא איך זה עובד בתיעוד של Apple's בנושא מצב וזרימת נתונים.
מגשר בין UIKit ו-SwitUI באמצעות UIViewRepresentable או UIViewControllerRepresentable
מכיוון שה-SDK של מפות Google ל-iOS מבוסס על UIKit, ועדיין לא מספק תצוגה תואמת ל-SwiifUI, צריך להשתמש בו ב-SwiifUI כדי להתאים ל-UIViewRepresentable
או ל-UIViewControllerRepresentable
. הפרוטוקולים האלה מאפשרים ל-SwiiftUI לכלול UIView
ו-UIViewController
שנוצרו על ידי UIKit, בהתאמה. ניתן להשתמש בכל אחד מהפרוטוקולים כדי להוסיף מפת Google לתצוגה SwiftUI, אבל בשלב הבא נבחן את הפונקציה UIViewControllerRepresentable
כדי לכלול קובץ UIViewController
שמכיל מפה.
6. הוספת מפה
בקטע הזה, מוסיפים את מפות Google לתצוגה של SwiftUI.
הוספת מפתח API
צריך לספק את מפתח ה-API שיצרתם בשלב קודם ל-SDK של מפות Google ל-iOS כדי לשייך את החשבון למפה שתוצג באפליקציה.
כדי לספק את מפתח ה-API, יש לפתוח את הקובץ AppDelegate.swift
ולעבור אל השיטה application(_, didFinishLaunchingWithOptions)
. נכון לעכשיו, ה-SDK מופעל דרך GMSServices.provideAPIKey()
עם המחרוזת "YOUR_API_KEY". צריך להחליף את המחרוזת הזו במפתח ה-API. אחרי ביצוע השלב הזה, להפעיל את SDK של מפות Google ל-iOS עם הפעלת האפליקציה.
הוספת מפה של Google באמצעות MapViewControllerBiger
לאחר שמפתח ה-API שלכם מועבר ל-SDK, השלב הבא הוא להציג את המפה באפליקציה.
בקר התצוגה המפורטת שמספק את הקוד למתחילים, MapViewController
מכיל כרגע GMSMapView
בתצוגה המפורטת שלו. עם זאת, מאחר שבקר התצוגה הזה נוצר ב-UIKit, יהיה עליך לגשר את הכיתה הזו אל SwiftUI כדי שניתן יהיה להשתמש בה בתוך ContentView
. כך נכנסים לדף:
- פותחים את הקובץ
MapViewControllerBridge
ב-Xcode.
סיווג זה תואם ל-UIViewControllerRepresentable, שהוא הפרוטוקול הנדרש לאחזור ממשק משתמש של UIKit UIViewController
כדי שניתן יהיה להשתמש בו כתצוגת SwiftUI. כלומר, תאימות לפרוטוקול זה מאפשרת לגשר על תצוגה של UIKit לתצוגה של SwiftUI. כדי להשתמש בפרוטוקול הזה, צריך להטמיע שתי שיטות:
makeUIViewController(context)
– השיטה הזו נקראת SwiftUI כדי ליצור אתUIViewController
הבסיסי. כאן אפשר ליצור את הUIViewController
ולעבור אותו במצב הראשוני.updateUIViewController(_, context)
– השיטה הזו נקראת SwiftUI בכל פעם שהמצב משתנה. כאן מבצעים את השינויים הרצויים ב-UIViewController
כדי להגיב לשינוי במצב.
- צור
MapViewController
בתוך הפונקציה makeUIViewController(context)
, יוצרים אובייקט MapViewController
חדש ומחזירים אותו כתוצאה. לאחר מכן, ה-MapViewControllerBridge
אמור להיראות כך:
MapViewControllerBרידג'
import GoogleMaps
import SwiftUI
struct MapViewControllerBridge: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MapViewController {
return MapViewController()
}
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
}
}
שימוש ב-MapViewControllerBiger ב-ContentView
כעת, אם MapViewControllerBridge
יוצר מופע של MapViewController
, השלב הבא הוא להשתמש במבנה זה ב-ContentView
כדי להציג מפה.
- פותחים את הקובץ
ContentView
ב-Xcode.
נוצר אובייקט ContentView
ב-SceneDelegate
ומכיל את תצוגת האפליקציה ברמה העליונה. המפה תתווסף מתוך הקובץ הזה.
- יצירת
MapViewControllerBridge
בתוך הנכסbody
.
בנכס body
של הקובץ הזה כבר סופק ערך ZStack
והוא הוטמע עבורך. ה-ZStack
מכיל כרגע רשימה של ערים שניתנות לאינטראקציה ולגרירה, שישמשו בשלב מאוחר יותר. בשלב זה, בZStack
יש ליצור MapViewControllerBridge
בתור תצוגת הצאצא הראשונה של ZStack
כך שמפה תוצג באפליקציה שמאחורי רשימת הערים. לאחר מכן, התוכן של הנכס body
בתוך 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()
} // ...
}
}
}
- עכשיו הגיע הזמן להריץ את האפליקציה. כעת אתה אמור לראות את טעינת המפה במסך של המכשיר יחד עם רשימה של ערים שניתן לגרור אותן אל תחתית המסך.
7. הוספת סמנים למפה
בשלב הקודם, הוספתם מפה לצד רשימה אינטראקטיבית שבה מוצגת רשימה של ערים. בקטע הזה, תוסיפו סמנים לכל עיר ברשימה.
סמנים כמצב
ContentView
מצהיר כרגע על נכס בשם markers
, שהוא רשימה של GMSMarker
המייצגת כל עיר המוצהרת בנכס cities
הסטטי. שימו לב לנכס הזה יש הערות עם מאפיין WiftUI של הנכס WraptUI State כדי לציין שהוא ינוהל על ידי SwiftUI. לכן, אם יזוהו שינויים בנכס הזה, כגון הוספה או הסרה של סמן, צפיות שמשתמשים במצב הזה יעודכנו.
צפייה בתוכן
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
}
לידיעתך, ContentView
משתמש בנכס markers
כדי לעבד את רשימת הערים על ידי העברתו למחלקה 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)
}
}
}
}
מעביר את המדינה אל MapViewControllerBbridge באמצעות כריכה
בנוסף לרשימת הערים שבהן מוצגים נתונים מהנכס markers
, יש להעביר את הנכס הזה למבנה MapViewControllerBridge
כדי שניתן יהיה להציג את הסמנים האלה במפה. לשם כך:
- יש להצהיר על נכס
markers
חדש ב-MapViewControllerBridge
עם הערות לגבי@Binding
MapViewControllerBרידג'
struct MapViewControllerBridge: : UIViewControllerRepresentable {
@Binding var markers: [GMSMarker]
// ...
}
- ב-
MapViewControllerBridge
, יש לעדכן את השיטהupdateUIViewController(_, context)
כדי להשתמש בנכסmarkers
כפי שצוין בשלב הקודם, updateUIViewController(_, context)
יתקשר אל SwiftUI בכל פעם שהמצב ישתנה. בשיטה הזו אנחנו רוצים לעדכן את המפה, ולכן עליך להציג את הסמנים בmarkers
. לשם כך, עליך לעדכן את המאפיין map
בכל סמן. לאחר ביצוע השלב הזה, ה-MapViewControllerBridge
אמור להיראות כך:
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
מ-ContentView
אלMapViewControllerBridge
מאחר שהוספת נכס חדש ב-MapViewControllerBridge
, עכשיו צריך להעביר את הערך של הנכס הזה באתחול של MapViewControllerBridge
. לכן, אם תנסו ליצור את האפליקציה, שימו לב שהיא לא תספור. כדי לפתור את הבעיה, צריך לעדכן את כתובת ה-ContentView
שבה נוצר ה-MapViewControllerBridge
ולהעביר אותו בנכס של markers
כך:
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers)
// ...
}
}
}
}
חשוב לשים לב שהקידומת $
שימשה להעברת נתונים ב-markers
אל MapViewControllerBridge
, כי היא צפויה לכלול נכס משויך. $
היא קידומת שמורה לשימוש בwrapper של נכס Swift. אחרי שמחילים אותו על מדינה, היא תחזיר איגוד.
- יש להריץ את האפליקציה כדי לראות את הסמנים המוצגים במפה.
8. אנימציה לעיר שנבחרה
בשלב הקודם, הוספת סמנים למפה על ידי העברת מצב מתצוגת SwiftUI אחת לאחרת. בשלב זה, המערכת תשיק אנימציה של עיר/סמן לאחר ההקשה ברשימת הפריטים האינטראקטיביים. כדי לבצע את האנימציה, עליך להגיב לשינויים במצב על ידי שינוי מיקום המצלמה של המפה כשהשינוי מתבצע. למידע נוסף על הקונספט של המצלמה במפה, ניתן לעיין במאמר מצלמה ותצוגה.
יצירת אנימציה של המפה בעיר שנבחרה
כדי להנפיש את העיר בעיר שנבחרה:
- הגדרת חיוב חדש ב-
MapViewControllerBridge
ב-ContentView
יש מאפיין מדינה בשם selectedMarker
, שאתחול שלו מצוין במספר n ועודכן בכל פעם שהעיר נבחרת ברשימה. פעולה זו מטופלת על ידי התצוגה המפורטת CitiesList
buttonAction
בתוך ContentView
.
צפייה בתוכן
CitiesList(markers: $markers) { (marker) in
guard self.selectedMarker != marker else { return }
self.selectedMarker = marker
// ...
}
בכל פעם ש-selectedMarker
משתנה, MapViewControllerBridge
צריך להיות מודע לשינוי במצב הזה כדי שניתן יהיה להנפיש את המפה לסמן שנבחר. לכן, צריך להגדיר קישור חדש ב-MapViewControllerBridge
מסוג GMSMarker
ולתת שם לנכס selectedMarker
.
MapViewControllerBרידג'
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var selectedMarker: GMSMarker?
}
- יש לעדכן את
MapViewControllerBridge
כדי ליצור אנימציה במפה בכל פעם שselectedMarker
משתנה
אחרי הכרזה על קישור חדש, צריך לעדכן את הפונקציה updateUIViewController_, context)
של MapViewControllerBridge
כך שהמפה תסומן לסמן שנבחר. כדי לעשות זאת צריך להעתיק את הקוד שבהמשך:
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)
})
}
}
}
}
}
הפונקציה animateToSelectedMarker(viewController)
תבצע רצף של אנימציות במפה באמצעות הפונקציה animate(with)
של GMSMapView
'.
- להעביר את
selectedMarker
שלContentView
אלMapViewControllerBridge
אחרי ההצהרה על הקישור החדש של MapViewControllerBridge
, יש לעדכן את ContentView
. לאחר מכן, יש להעביר את הקובץ אל selectedMarker
במקום שבו MapViewControllerBridge
נוצר.
צפייה בתוכן
struct ContentView: View {
// ...
var body: some View {
// ...
GeometryReader { geometry in
ZStack(alignment: .top) {
// Map
MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
// ...
}
}
}
}
השלמת שלב זה תגרום להנפשה במפה בכל פעם שעיר חדשה נבחרת ברשימה.
תצוגת אנימציה של SwiftUI כדי להדגיש את העיר
SwiftUI מאפשר ליצור אנימציות בקלות רבה, משום שהוא יטפל באנימציות של מעברים בין מדינות. כדי להמחיש זאת, מוסיפים אנימציות נוספות על ידי התמקדות בתצוגה לעיר שנבחרה לאחר השלמת האנימציה במפה. כדי לעשות זאת, יש לבצע את השלבים הבאים:
- הוספת סגירה של
onAnimationEnded
אלMapViewControllerBridge
האנימציה של SwiftUI תבוצע לאחר רצף האנימציות במפה שהוספת בעבר, ולכן עליך להצהיר על סגירה חדשה בשם onAnimationEnded
תוך MapViewControllerBridge
. היא תופעל לאחר הסגירה של 0.5 שניות אחרי האנימציה האחרונה במפה בתוך השיטה animateToSelectedMarker(viewController)
.
MapViewControllerBרידג'
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
ב-MapViewControllerBridge
מטמיעים את הסגירה onAnimationEnded
שבה MapViewControllerBridge
מופיעה בתוך ContentView
. יש להעתיק ולהדביק את הקוד הבא, שמוסיף מצב חדש בשם zoomInCenter
. בנוסף, הוא משנה את התצוגה באמצעות clipShape
ומשתנה בקוטר של הצורה שנחתכה, בהתאם לערך של zoomInCenter
צפייה בתוכן
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))
}
}
}
}
- קדימה, אפשר להריץ את האפליקציה כדי לראות את האנימציות!
9. שליחת אירוע אל SwiftUI
בשלב זה, יש להאזין לאירועים שנוצרו על ידי GMSMapView
ולשלוח את האירוע ל-SififUI. באופן ספציפי, יש להגדיר גישה אל תצוגת המפה ולהאזין לאירועי תנועה במצלמה. כך, כשהעיר תתמקד והמצלמה במפה זזה מתנועה, תצוגת המפה תבטל את המיקוד שלה, כך שאפשר יהיה לראות יותר מקומות במפה.
שימוש במתאמים של SwiftUI
GMSMapView
פולט אירועים כמו שינויים במיקום המצלמה או הקשה על סמן. המנגנון להאזנה לאירועים האלה הוא דרך הפרוטוקול GMSmapViewDelegate. SwiftUI מציג את הקונספט של מתאם שמשמש במיוחד כדי להעניק גישה לנאמני מידע של ViewKit. לכן, בעולם ה-SififUI, על המתאם להיות אחראי לתאימות לפרוטוקול GMSMapViewDelegate
. כדי לעשות זאת, יש לבצע את השלבים הבאים:
- יצירת מתאם בשם
MapViewCoordinator
בתוךMapViewControllerBridge
יש ליצור כיתה מקוננת בתוך הכיתה MapViewControllerBridge
ולקרוא לה MapViewCoordinator
. הכיתה צריכה לעמוד ב-GMSMapViewDelegate
ועליה להצהיר על MapViewControllerBridge
כנכס.
MapViewControllerBרידג'
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
var mapViewControllerBridge: MapViewControllerBridge
init(_ mapViewControllerBridge: MapViewControllerBridge) {
self.mapViewControllerBridge = mapViewControllerBridge
}
}
}
- הטמעת
makeCoordinator()
ב-MapViewControllerBridge
לאחר מכן יש ליישם את השיטה makeCoordinator()
בתוך MapViewControllerBridge
ולהחזיר מופע של MapViewCoodinator
שיצרת בשלב הקודם.
MapViewControllerBרידג'
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator(self)
}
}
- הגדרת
MapViewCoordinator
בתור תצוגת המפה
לאחר יצירת המתאם המותאם אישית, השלב הבא הוא להגדיר את המתאם כנציג מורשה של תצוגת המפה של. לשם כך יש לעדכן את אתחול בקר התצוגה ב-makeUIViewController(context)
. ניתן יהיה לגשת למתאם שנוצר מהשלב הקודם מאובייקט ההקשר.
MapViewControllerBרידג'
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeUIViewController(context: Context) -> MapViewController {
let uiViewController = MapViewController()
uiViewController.map.delegate = context.coordinator
return uiViewController
}
- צריך להוסיף סגירה ל-
MapViewControllerBridge
כדי שהמצלמה תפיץ אירוע למעלה
המטרה היא לעדכן את התצוגה עם תנועות המצלמה, ולכן יש להצהיר על מאפיין סגירה חדש שמקבל את הערך הבוליאני ב-MapViewControllerBridge
שנקרא mapViewWillMove
ולהפעיל את הסגירה הזו בשיטה 'הענקת גישה' mapView(_, willMove)
בתוך MapViewCoordinator
. יש להעביר את הערך של gesture
לסגירה כדי שהתצוגה של SwiftUI תוכל להגיב רק לאירועי תנועה במצלמה שקשורים לתנועות.
MapViewControllerBרידג'
struct MapViewControllerBridge: UIViewControllerRepresentable {
var mapViewWillMove: (Bool) -> ()
//...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
// ...
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
self.mapViewControllerBridge.mapViewWillMove(gesture)
}
}
}
- יש לעדכן את ContentView כדי להעביר ערך עבור
mapWillMove
עם הסגירה החדשה ב-MapViewControllerBridge
, יש לעדכן את ContentView
כך שיעביר ערך עבור הסגירה החדשה. בתוך סגירה, מעבירים את מצב zoomInCenter
למצב false
אם האירוע בהעברה קשור לתנועה. פעולה זו תציג שוב את המפה בתצוגה מלאה כאשר המפה זזה.
צפייה בתוכן
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
})
// ...
}
}
}
}
- כדאי לך להריץ את האפליקציה כדי לראות את השינויים החדשים!
10. מזל טוב
כל הכבוד! הגעת ליעד! הצלחתם ללמוד הרבה, ואנחנו מקווים שבזכות השיעורים האלה למדתם איך לבנות את אפליקציית SwiftUI שלכם באמצעות ה-SDK של מפות Google ל-iOS.
מה למדת
- ההבדלים בין SwiftUI ל-UIKit
- איך לגשר בין SwiftUI ל-UIKit באמצעות UIViewControllerRepresentable
- איך לשנות את תצוגת המפה בעזרת מדינה וקישור
- איך שולחים אירוע מתצוגת המפה אל SwiftUI באמצעות מתאם
מה עכשיו?
- SDK של מפות Google ל-iOS - תיעוד רשמי של ה-SDK של מפות Google ל-iOS
- Place SDK ל-iOS – חיפוש עסקים מקומיים ונקודות עניין בסביבה
- maps-sdk-for-ios-samples – קוד לדוגמה ב-GitHub שמדגים את כל התכונות שב-SDK של מפות Google ל-iOS.
- SwiftUI – התיעוד הרשמי של Apple' ב-SwiftUI
- ענו על השאלה הבאה כדי לעזור לנו ליצור את התוכן השימושי ביותר:
אילו מעבדי קוד אחרים היית רוצה לראות?
האם קוד הקוד שאתם לא רוצים מופיע למעלה? אפשר לבקש אותו באמצעות בעיה חדשה כאן.