1. قبل از شروع
این کد لبه به شما می آموزد که چگونه از Maps SDK برای iOS با SwiftUI استفاده کنید.
پیش نیازها
- دانش اولیه سوئیفت
- آشنایی اولیه با SwiftUI
کاری که خواهی کرد
- Maps SDK برای iOS را فعال کنید و از آن استفاده کنید تا Google Maps را با استفاده از SwiftUI به برنامه iOS اضافه کنید.
- نشانگرها را به نقشه اضافه کنید.
- وضعیت را از نمای SwiftUI به یک شی
GMSMapView
و بالعکس.
آنچه شما نیاز دارید
- Xcode 11.0 یا بالاتر
- یک حساب Google با فعال بودن صورتحساب
- Maps SDK برای iOS
- کارتاژ
2. راه اندازی شوید
برای مرحله فعال سازی زیر، Maps SDK برای iOS را فعال کنید.
پلتفرم نقشه های گوگل را راه اندازی کنید
اگر قبلاً حساب Google Cloud Platform و پروژهای با صورتحساب فعال ندارید، لطفاً راهنمای شروع به کار با Google Maps Platform را برای ایجاد یک حساب صورتحساب و یک پروژه ببینید.
- در Cloud Console ، روی منوی کشویی پروژه کلیک کنید و پروژه ای را که می خواهید برای این کد لبه استفاده کنید انتخاب کنید.
- APIها و SDKهای پلتفرم Google Maps مورد نیاز برای این لبه کد را در Google Cloud Marketplace فعال کنید. برای انجام این کار، مراحل این ویدئو یا این مستند را دنبال کنید.
- یک کلید API در صفحه Credentials در Cloud Console ایجاد کنید. می توانید مراحل این ویدئو یا این مستند را دنبال کنید. همه درخواستها به پلتفرم نقشههای Google به یک کلید API نیاز دارند.
3. کد شروع را دانلود کنید
برای شروع هر چه سریعتر، در اینجا چند کد شروع وجود دارد که به شما کمک میکند تا این نرمافزار را دنبال کنید. از شما استقبال می شود که به سراغ راه حل بروید، اما اگر می خواهید تمام مراحل ساخت آن را خودتان دنبال کنید، به خواندن ادامه دهید.
- اگر
git
را نصب کرده اید، مخزن را کلون کنید.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git
همچنین میتوانید روی دکمه زیر کلیک کنید تا کد منبع را دانلود کنید.
- پس از دریافت کد، در یک
cd
ترمینال وارد فهرست راهنماstarter/GoogleMapsSwiftUI
شوید. - برای دانلود Maps SDK برای iOS، به
carthage update --platform iOS
را اجرا کنید - در نهایت فایل
GoogleMapsSwiftUI.xcodeproj
را در Xcode باز کنید
4. مروری بر کد
در پروژه استارتری که دانلود کردید، کلاس های زیر برای شما تهیه و پیاده سازی شده است:
-
AppDelegate
-UIApplicationDelegate
برنامه. اینجاست که Maps SDK برای iOS راه اندازی می شود. -
City
- ساختاری که نشان دهنده یک شهر است (شامل نام و مختصات شهر). -
MapViewController
- یک UIKitUIViewController
ساده حاوی نقشه گوگل ( GMSMapView ) -
SceneDelegate
- UIWindowSceneDelegate برنامه کهUIWindowSceneDelegate
از آن نمونه سازی میContentView
.
علاوه بر این، کلاس های زیر پیاده سازی جزئی دارند و تا پایان این Codelab توسط شما تکمیل خواهند شد:
-
ContentView
- نمای سطح بالای SwiftUI حاوی برنامه شما. -
MapViewControllerBridge
- کلاسی که نمای UIKit را به نمای SwiftUI پیوند می دهد. به طور خاص، این کلاسی است که MapViewController را درMapViewController
قابل دسترسی می کند.
5. استفاده از SwiftUI در مقابل UIKit
SwiftUI در iOS 13 به عنوان یک فریم ورک جایگزین رابط کاربری نسبت به UIKit برای توسعه برنامه های iOS معرفی شد. در مقایسه با UIKit قبلی خود، SwiftUI چندین مزیت را ارائه می دهد. چندتا را نام بردن:
- هنگام تغییر وضعیت، نمایش ها به طور خودکار به روز می شوند. با استفاده از اشیایی به نام State ، هر تغییری در مقدار اساسی موجود در آن باعث بهروزرسانی خودکار رابط کاربری میشود.
- پیش نمایش زنده توسعه سریعتر را امکان پذیر می کند. پیشنمایشهای زنده نیاز به ساخت و استقرار کد در شبیهساز را برای مشاهده تغییرات بصری به حداقل میرسانند، زیرا پیشنمایش نمای SwiftUI به راحتی در Xcode قابل مشاهده است.
- منبع حقیقت در سوئیفت است. همه نماها در SwiftUI در سوئیفت اعلان می شوند، بنابراین استفاده از Interface Builder دیگر ضروری نیست.
- با UIKit تعامل دارد. قابلیت همکاری با UIKit تضمین می کند که برنامه های موجود می توانند به صورت تدریجی از SwiftUI با نماهای موجود خود استفاده کنند. علاوه بر این، کتابخانههایی که هنوز از SwiftUI پشتیبانی نمیکنند، مانند Maps SDK برای iOS، همچنان میتوانند در SwiftUI استفاده شوند.
برخی از اشکالات نیز وجود دارد:
- SwiftUI فقط در iOS 13 یا بالاتر در دسترس است.
- سلسله مراتب نمایش را نمی توان در پیش نمایش های Xcode بررسی کرد.
وضعیت SwiftUI و جریان داده
SwiftUI یک روش جدید برای ایجاد رابط کاربری با استفاده از یک رویکرد اعلانی ارائه میدهد—شما به SwiftUI میگویید که میخواهید نمای شما همراه با تمام حالتهای مختلف برای آن چگونه به نظر برسد، و سیستم بقیه کارها را انجام خواهد داد. SwiftUI هر زمان که وضعیت اساسی به دلیل یک رویداد یا اقدام کاربر تغییر کند، نمای را به روز می کند. این طرح معمولاً به جریان داده های یک طرفه گفته می شود. در حالی که ویژگیهای این طراحی در این نرمافزار کد خارج از محدوده است، توصیه میکنیم نحوه عملکرد آن را در اسناد وضعیت و جریان داده اپل مطالعه کنید.
پل زدن UIKit و SwiftUI با استفاده از UIViewRepresentable یا UIViewControllerRepresentable
از آنجایی که Maps SDK برای iOS بر روی UIKit ساخته شده است و هنوز نمای سازگار با SwiftUI ارائه نمی دهد، استفاده از آن در SwiftUI مستلزم انطباق با UIViewRepresentable
یا UIViewControllerRepresentable
است. این پروتکلها SwiftUI را قادر میسازد تا به UIView
و UIViewController
ساختهشده توسط UIKit را شامل شود. در حالی که میتوانید از هر یک از پروتکلها برای افزودن نقشه Google به نمای SwiftUI استفاده کنید، در مرحله بعد، نگاهی به استفاده از UIViewControllerRepresentable
برای گنجاندن یک UIViewController
حاوی نقشه خواهیم داشت.
6. یک نقشه اضافه کنید
در این بخش، نقشه های گوگل را به نمای SwiftUI اضافه می کنید.
کلید API خود را اضافه کنید
کلید API که در مرحله قبل ایجاد کردید باید به Maps SDK برای iOS ارائه شود تا حساب شما را با نقشه ای که در برنامه نمایش داده می شود مرتبط کند.
برای ارائه کلید API خود، فایل AppDelegate.swift
را باز کنید و به روش application(_, didFinishLaunchingWithOptions)
. در حال حاضر، SDK از طریق GMSServices.provideAPIKey()
با رشته "YOUR_API_KEY" مقداردهی اولیه می شود. آن رشته را با کلید API خود جایگزین کنید. با تکمیل این مرحله، Maps SDK برای iOS هنگام راهاندازی برنامه، مقداردهی اولیه میشود.
با استفاده از MapViewControllerBridge یک نقشه گوگل اضافه کنید
اکنون که کلید API شما در حال ارائه به SDK است، مرحله بعدی نمایش نقشه در برنامه است.
کنترلر View که در کد شروع ارائه شده است، MapViewController
در حال حاضر حاوی یک GMSMapView
در نمای خود است. با این حال، از آنجایی که این view controller در 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
شما اکنون باید به شکل زیر باشد:
MapViewControllerBridge
import GoogleMaps
import SwiftUI
struct MapViewControllerBridge: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MapViewController {
return MapViewController()
}
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
}
}
از MapViewControllerBridge در ContentView استفاده کنید
اکنون که MapViewControllerBridge
در حال ایجاد یک نمونه از MapViewController
است، قدم بعدی استفاده از این ساختار در ContentView
برای نمایش نقشه است.
- فایل
ContentView
را در Xcode باز کنید.
ContentView
در SceneDelegate
نمونه سازی شده است و شامل نمای برنامه سطح بالا است. نقشه از داخل این فایل اضافه خواهد شد.
- یک
MapViewControllerBridge
در ویژگیbody
کنید.
در داخل ویژگی body
این فایل، یک ZStack
قبلا برای شما تهیه و پیاده سازی شده است. ZStack
در حال حاضر شامل یک لیست قابل تعامل و قابل کشیدن از شهرها است که در مرحله بعد از آنها استفاده خواهید کرد. در حال حاضر، در ZStack
یک MapViewControllerBridge
به عنوان اولین نمای فرزند ZStack
ایجاد کنید تا یک نقشه در برنامه پشت لیست نمای شهرها نمایش داده شود. پس از انجام این کار، محتویات ویژگی body
در ContentView
باید به شکل زیر باشد:
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
است. توجه داشته باشید که این ویژگی با وضعیت بسته بندی ویژگی SwiftUI حاشیه نویسی شده است تا نشان دهد که باید توسط SwiftUI مدیریت شود. بنابراین، اگر تغییراتی مانند افزودن یا حذف نشانگر با این ویژگی شناسایی شود، نماهایی که از این حالت استفاده می کنند به روز می شوند.
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
}
توجه داشته باشید که 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)
}
}
}
}
از طریق Binding، وضعیت را به MapViewControllerBridge منتقل کنید
علاوه بر لیست شهرهایی که داده ها را از ویژگی markers
نمایش می دهند، این ویژگی را به ساختار MapViewControllerBridge
کنید تا بتوان از آن برای نمایش آن نشانگرها روی نقشه استفاده کرد. برای انجام آن:
- یک ویژگی
markers
جدید را درMapViewControllerBridge
که با@Binding
حاشیه نویسی شده است، اعلام کنید
MapViewControllerBridge
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
استفاده شده است زیرا انتظار یک ویژگی محدود را دارد. $
یک پیشوند رزرو شده برای استفاده با بستهبندیهای ویژگی Swift است. وقتی برای یک ایالت اعمال می شود، یک Binding را برمی گرداند.
- ادامه دهید و برنامه را اجرا کنید تا نشانگرهای نمایش داده شده روی نقشه را ببینید.
8. به یک شهر انتخاب شده متحرک شوید
در مرحله قبل، با انتقال State از یک نمای SwiftUI به نمای دیگر، نشانگرها را به نقشه اضافه کردید. در این مرحله، پس از اینکه یک شهر/نشانگر در لیست تعاملی قرار گرفت، متحرک سازی خواهید کرد. برای اجرای انیمیشن، با تغییر موقعیت دوربین نقشه هنگام تغییر، به تغییرات یک وضعیت واکنش نشان خواهید داد. برای کسب اطلاعات بیشتر در مورد مفهوم دوربین نقشه، به دوربین و مشاهده مراجعه کنید.
متحرک کردن نقشه به شهر انتخاب شده
برای متحرک سازی نقشه به یک شهر انتخاب شده:
- یک Binding جدید در
MapViewControllerBridge
تعریف کنید
ContentView
دارای یک ویژگی State selectedMarker
نام SelectMarker است که مقدار اولیه آن صفر می شود و هر زمان که شهری در لیست انتخاب شود به روز می شود. این کار توسط CitiesList
view buttonAction
در ContentView
انجام می شود.
ContentView
CitiesList(markers: $markers) { (marker) in
guard self.selectedMarker != marker else { return }
self.selectedMarker = marker
// ...
}
هر زمان selectedMarker
SelectMarker تغییر کند، MapViewControllerBridge
باید از این تغییر حالت آگاه باشد تا بتواند نقشه را به نشانگر انتخاب شده متحرک کند. بنابراین، یک Binding جدید در MapViewControllerBridge
از نوع GMSMarker
و نام ویژگی را selectedMarker
بگذارید.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
@Binding var selectedMarker: GMSMarker?
}
-
MapViewControllerBridge
را بهروزرسانی کنید تا هر زمان که علامتگذاریselectedMarker
تغییر کند، نقشه را متحرک کنید
هنگامی که یک Binding جدید اعلام شد، باید MapViewControllerBridge
's updateUIViewController_, context)
را بهروزرسانی کنید تا نقشه به نشانگر انتخاب شده متحرک شود. ادامه دهید و این کار را با کپی کردن کد زیر انجام دهید:
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
Binding جدید را اعلام کرد، ادامه دهید و ContentView
را به روز کنید تا در MapViewControllerBridge
selectedMarker
آن نصب شده است عبور کنید.
ContentView
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)
فراخوانی کنید.
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
درMapViewControllerBridge
بسته شدن onAnimationEnded
را در جایی که MapViewControllerBridge
در ContentView
نمونهسازی میکند، اجرا کنید. کد زیر را کپی و جایگذاری کنید که حالت جدیدی به نام zoomInCenter
اضافه می کند و همچنین با استفاده از clipShape
نمای را تغییر می دهد و قطر شکل بریده شده را بسته به مقدار 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))
}
}
}
}
- ادامه دهید و برنامه را اجرا کنید تا انیمیشن ها را ببینید!
9. یک رویداد به SwiftUI ارسال کنید
در این مرحله، شما به رویدادهای منتشر شده از GMSMapView
گوش می دهید و آن رویداد را به SwiftUI ارسال می کنید. به طور خاص، شما یک نماینده را برای نمای نقشه تنظیم میکنید و به رویدادهای حرکت دوربین گوش میدهید، به طوری که وقتی یک شهر متمرکز است و دوربین نقشه از یک حرکت حرکت میکند، نمای نقشه از حالت فوکوس خارج میشود تا بتوانید نقشه بیشتری را ببینید.
با استفاده از هماهنگ کننده های SwiftUI
GMSMapView
رویدادهایی مانند تغییر موقعیت دوربین یا زمانی که یک نشانگر ضربه میخورد را منتشر میکند. مکانیسم گوش دادن به این رویدادها از طریق پروتکل GMSMapViewDelegate است. SwiftUI مفهوم یک Coordinator را معرفی می کند که به طور خاص برای عمل به عنوان نماینده برای کنترل کننده های view UIKit استفاده می شود. بنابراین، در دنیای SwiftUI، یک Coordinator باید مسئول انطباق با پروتکل GMSMapViewDelegate
باشد. برای این کار مراحل زیر را انجام دهید:
- یک Coordinator به نام
MapViewCoordinator
درMapViewControllerBridge
یک کلاس تودرتو در داخل کلاس MapViewControllerBridge
و آن را MapViewCoordinator
. این کلاس باید با GMSMapViewDelegate
مطابقت داشته باشد و MapViewControllerBridge
را به عنوان یک ویژگی اعلام کند.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
var mapViewControllerBridge: MapViewControllerBridge
init(_ mapViewControllerBridge: MapViewControllerBridge) {
self.mapViewControllerBridge = mapViewControllerBridge
}
}
}
-
makeCoordinator()
makeCoordinator را درMapViewControllerBridge
پیاده سازی کنید
سپس، makeCoordinator()
را در MapViewControllerBridge
پیاده سازی کنید و نمونه ای از MapViewCoodinator
را که در مرحله قبل ایجاد کردید، برگردانید.
MapViewControllerBridge
struct MapViewControllerBridge: UIViewControllerRepresentable {
// ...
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator(self)
}
}
-
MapViewCoordinator
را به عنوان نماینده نمای نقشه تنظیم کنید
با ایجاد هماهنگ کننده سفارشی، گام بعدی این است که هماهنگ کننده را به عنوان نماینده برای نمای نقشه view controller تنظیم کنید. برای انجام این کار، مقداردهی اولیه view controller را در makeUIViewController(context)
به روز کنید. هماهنگ کننده ایجاد شده از مرحله قبل از شی Context قابل دسترسی خواهد بود.
MapViewControllerBridge
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 بتواند فقط به رویدادهای حرکت دوربین مرتبط با اشاره واکنش نشان دهد.
MapViewControllerBridge
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
تغییر دهید. این به طور موثر نقشه را دوباره در نمای کامل نشان می دهد زمانی که نقشه توسط یک حرکت حرکت می کند.
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
})
// ...
}
}
}
}
- ادامه دهید و برنامه را اجرا کنید تا تغییرات جدید را ببینید!
10. تبریک می گویم
تبریک می گویم برای رسیدن به اینجا! شما زمینه های زیادی را پوشش دادید و امیدواریم درسی که آموخته اید به شما این امکان را می دهد که اکنون برنامه SwiftUI خود را با استفاده از Maps SDK برای iOS بسازید.
چیزی که یاد گرفتی
- تفاوت بین SwiftUI و UIKit
- نحوه پل زدن بین SwiftUI و UIKit با استفاده از UIViewControllerRepresentable
- نحوه ایجاد تغییرات در نمای نقشه با State و Binding
- نحوه ارسال یک رویداد از نمای نقشه به SwiftUI با استفاده از یک Coordinator
بعدش چی؟
- Maps SDK برای iOS - اسناد رسمی برای Maps SDK برای iOS
- مکانها SDK برای iOS - کسبوکارهای محلی و نقاط مورد علاقه را در اطراف خود پیدا کنید
- maps-sdk-for-ios-samples - کد نمونه در GitHub که تمام ویژگیهای موجود در Maps SDK برای iOS را نشان میدهد.
- SwiftUI - اسناد رسمی اپل در مورد SwiftUI
- با پاسخ به سوال زیر به ما کمک کنید محتوایی را ایجاد کنیم که برای شما مفیدتر باشد:
دوست دارید چه کدهای دیگری را ببینید؟
آیا کد لبه مورد نظر شما در بالا فهرست نشده است؟ آن را با یک شماره جدید در اینجا درخواست کنید .