
Gunakan penyesuaian tata letak untuk mengontrol hierarki tampilan dan penempatan layar untuk tampilan yang disediakan Google dan tampilan bisnis kustom Anda sendiri.
Daripada menambahkan tampilan kustom ke slot tata letak yang telah ditentukan, terapkan delegasi tata letak untuk mengelola tata letak seluruh layar. Selama transisi status navigasi, delegasi tata letak Anda akan menerima komponen yang disediakan Google, seperti kartu belokan, kartu PWT, dan tombol. Posisikan elemen ini bersama konten kustom Anda sendiri menggunakan batasan Tata Letak Otomatis iOS standar.
Gunakan framework ini untuk memosisikan informasi bisnis kustom—seperti status pesanan atau petunjuk pengambilan—dengan tepat di layar sekaligus mencegah tampilan Anda tumpang-tindih.
Cara kerja penyesuaian tata letak
Penyesuaian tata letak menggunakan pola desain delegasi. Alih-alih otomatis menggambar atau memosisikan komponen UI di layar, SDK meneruskannya langsung ke class kustom yang Anda tulis: delegasi tata letak.
Untuk menyesuaikan tata letak, buat class yang sesuai dengan protokolNavigationLayoutDelegate dan teruskan instance ke metode setLayoutDelegate(_:) dari GMSMapView Anda. Setiap kali status navigasi
berubah—seperti berpindah dari peta dasar ke panduan belokan demi belokan
aktif—SDK akan menjalankan metode callback pada delegasi Anda dan menyediakan
komponen UI yang tersedia untuk status tertentu tersebut.
Untuk memberikan pengalaman pengguna yang lancar dan terintegrasi, framework ini menetapkan pemisahan tanggung jawab yang jelas antara aplikasi Anda dan SDK. Gunakan delegasi tata letak untuk menyesuaikan hal berikut:
- Membangun hierarki tampilan: Pilih dengan tepat komponen Google dan tampilan bisnis kustom yang akan ditambahkan ke layar untuk setiap status UI.
- Posisikan setiap elemen: Tetapkan anchor layar, margin, dan penempatan tata letak yang tepat. Hindari menerapkan batasan lebar atau tinggi kustom ke komponen Google karena komponen Google menghitung dimensi internalnya sendiri.
- Membingkai peta dasar: Tentukan batas yang terlihat dari kamera peta menggunakan koordinat komponen area pandang.
- Lapisi layar: Tentukan apakah tampilan kustom akan mengambang di atas, di bawah, atau di samping kontrol bawaan Google.
Sementara itu, Anda tidak dapat menyesuaikan komponen Google berikut dengan delegasi tata letak:
- Dimensi komponen: Ukuran dan dimensi internal komponen yang disediakan Google, yang dihitung secara otomatis oleh SDK.
- Kondisi pemicu: Saat pemberitahuan atau perintah dinamis muncul berdasarkan data rute real-time.
Prinsip penerapan
Saat menulis delegasi tata letak, perhatikan aturan berikut untuk mencegah bug tata letak atau error runtime:
- Defaultnya adalah layar kosong: Komponen yang disediakan Google hanya muncul jika delegasi Anda secara eksplisit menambahkannya ke hierarki tampilan dan memosisikannya.
- API lama tidak didukung: Properti dan metode yang mengontrol model tata letak berbasis slot lama tidak akan didukung dan mungkin tidak berperilaku seperti yang diharapkan saat delegasi kustom aktif.
- Jangan ubah struktur tampilan internal: Jangan melintasi atau mengubah hierarki tampilan komponen yang disediakan Google (seperti kartu belokan atau kartu PWT). Karena hierarki tampilan internal ini adalah detail implementasi yang mendasarinya, hierarki tersebut dapat berubah di seluruh rilis SDK. Mengubahnya dapat menyebabkan tata letak Anda rusak selama update SDK mendatang.
Kompatibilitas API lama
Untuk perilaku tata letak yang andal saat menggunakan delegasi tata letak kustom, hindari penggunaan API berbasis slot lama berikut, yang direncanakan untuk dihentikan penggunaannya. Untuk memigrasikan aplikasi yang ada, ganti penggunaan API ini dengan kode di delegasi tata letak kustom Anda:
Menampilkan API berbasis slot lama
| API Lama | Penggantian Layout Delegate |
|---|---|
isNavigationHeaderEnabled |
Baca tampilan turnCard di
startGuidance(navMap:newState:oldState:). |
isNavigationFooterEnabled |
Baca tampilan etaCard di
startGuidance(navMap:newState:oldState:). |
isNavigationTripProgressBarEnabled |
Baca tampilan tripProgressBar di
startGuidance(navMap:newState:oldState:). |
isNavigationReportIncidentButtonEnabled |
Temukan tombol .reporting dalam
array buttons. |
setHeaderAccessoryView(_:) dan
invalidateLayout(forAccessoryView:) |
Tambahkan tampilan Anda sendiri ke tata letak dan tautkan ke
turnCard. |
padding dan paddingAdjustmentBehavior |
Posisikan tampilan viewport untuk membingkai kamera. |
navigationHeaderLayoutGuide |
Tautkan tampilan kustom Anda langsung ke turnCard. |
navigationFooterLayoutGuide |
Tautkan tampilan kustom Anda langsung ke etaCard. |
bottomTrailingButtonsLayoutGuide |
Tautkan tombol Anda langsung ke panduan etaCard atau penampung. |
bottomTrailingButtonsAlternateLayoutGuide |
Tautkan tombol Anda langsung ke tombol .reporting atau batasan wideMode. |
navigatorWillPresentPrompt(_:) dan
navigatorDidDismissPrompt(_:) |
Mengandalkan callback perintah NavigationLayoutDelegate,
seperti showPrompt(navMap:newPrompt:). |
Saat delegasi tata letak kustom ditetapkan, panduan tata letak lama (seperti
navigationHeaderLayoutGuide atau
bottomTrailingButtonsLayoutGuide) dan metode tampilan aksesori header
tidak akan berpengaruh. Sebagai gantinya, kaitkan tampilan Anda ke tampilan yang disediakan Google.
Properti compassButton dari GMSUISettings masih
mengontrol kompas saat UI navigasi dinonaktifkan. Saat navigasi diaktifkan, delegasi Anda akan memutuskan apakah akan menampilkan kompas dari array buttons atau tidak.
Checklist Essentials
Ikuti langkah-langkah dan persyaratan penting berikut untuk berhasil menerapkan delegasi tata letak:
-
Tetapkan delegasi sebelum mengaktifkan navigasi: Panggil
setLayoutDelegate(_:)diGMSMapViewsebelum Anda mengaktifkan navigasi denganisNavigationEnabledatauenableNavigation(with:). Metode ini akan menampilkan error jika navigasi sudah diaktifkan atau jika Anda membuat tampilan peta untuk layar CarPlay. Tampilan peta menyimpan referensi yang kuat ke delegasi Anda. Untuk memulihkan tata letak bawaan, teruskannilsaat navigasi dinonaktifkan.// Set the layout delegate before you enable navigation. do { try mapView.setLayoutDelegate(MyLayoutDelegate()) } catch { print("Couldn't set the layout delegate: \(error)") } mapView.isNavigationEnabled = true
-
Lampirkan tampilan wajib: Anda harus menambahkan logo Google (
googleLogo) dan Area pandang (viewport) ke penampung tata letak di semua status navigasi. -
Mematuhi dimensi tetap: SDK menentukan dimensi untuk beberapa komponen yang disediakan Google. Jangan terapkan batasan lebar atau tinggi kustom ke elemen berikut:
- Kartu petunjuk navigasi
- kartu PWT
- Perintah masuk
- Logo Google
- Widget kecepatan
-
Tambahkan elemen sebagai sub-tampilan: Tambahkan tampilan yang disediakan Google langsung sebagai sub-tampilan ke tampilan penampung kustom atau ke
GMSMapViewitu sendiri. -
Sejajarkan menggunakan panduan tata letak: Tampilan yang disediakan Google menyertakan margin visual bawaan. Untuk menyelaraskan elemen kustom Anda secara sempurna dengan komponen yang disediakan Google, batasi tampilan Anda ke properti
layoutMarginsGuidetampilan Google. -
Pembersihan saat keluar dari status: Di
stopGuidance(navMap:newState:oldState:), hapus tampilan panduan aktif dan nonaktifkan batasannya sebelum Anda memulihkan tata letak siap navigasi. DidisableNavigationUI(navMap:oldState:), hapus semua tampilan dan panduan tata letak yang Anda tambahkan, termasuk perintah apa pun di layar. Tindakan ini mencegah tampilan dari satu status tumpang-tindih dengan status berikutnya. -
Miliki aksesibilitas dan dukungan kanan ke kiri: Tampilan yang disediakan Google memenuhi standar aksesibilitas, tetapi delegasi Anda bertanggung jawab atas aksesibilitas tata letak secara keseluruhan. Untuk mendukung bahasa yang ditulis dari kanan ke kiri, gunakan anchor awal dan akhir, bukan anchor kiri dan kanan.
-
Hindari API tata letak lama: Jangan gunakan properti pengubah tata letak lama di
GMSUISettingsatau panduan tata letak lama diGMSMapViewsaat delegasi kustom aktif. SDK mungkin mengabaikan panggilan lama ini saat delegasi kustom dilampirkan.
Status UI dan komponen Google
Saat transisi status navigasi terjadi, SDK akan meneruskan objek NavigationUIState hanya baca ke callback delegasi Anda. Objek ini menggabungkan flag konfigurasi tata letak saat ini dengan komponen Google (misalnya, instance UIView) yang Anda perlukan untuk merender layar.
Delegasi tata letak mengelola hierarki tampilan di empat status operasional. Diagram status berikut mengilustrasikan cara SDK bertransisi di antara status navigasi dan metode callback yang dijalankannya pada delegasi Anda:
Komponen Google tertentu yang disediakan untuk delegasi Anda bergantung pada fase siklus proses navigasi saat ini.
Komponen yang diperlukan (semua status navigasi)
Terlepas dari fase navigasi saat ini, Anda harus menyertakan, memosisikan, dan menjaga komponen Google berikut tetap terlihat dalam hierarki tampilan Anda:
Logo Google (
googleLogo): Komponen ini menampilkan logo Google Maps wajib. Jika tombol Pusatkan ulang diaktifkan, logo akan otomatis berubah menjadi tombol ini saat pengemudi men-scroll peta menjauh dari kendaraannya. Akibatnya, penempatan logo Anda menentukan tempat tombol Pusatkan ulang muncul. Sebaiknya tempatkan logo di sudut kiri bawah tata letak agar sesuai dengan ekspektasi UI peta standar.Area pandang (
viewport):UIViewtidak terlihat yang menentukan batas penyesuaian frame kamera. Penempatan area pandang menentukan dengan tepat tempat SDK memusatkan chevron kendaraan dan menggambar garis rute aktif. Posisikan area pandang agar menutupi area layar yang terbuka dan tidak terhalang, sehingga aman dari overlay buram seperti panel bawah kustom.
Komponen siap navigasi
Selama status siap navigasi, UI tetap minimal untuk mempertahankan fokus pada
peta dasar. Objek NavigationReadyUIState Anda memberikan akses ke hal berikut:
- buttons: Array tampilan tindakan mengambang yang dikonfigurasi untuk peta dasar (biasanya hanya tombol Kompas). Karena Google mungkin menambahkan atau menyusun ulang
tombol dalam rilis SDK mendatang, hindari mengandalkan indeks
array tetap. Sebagai gantinya, lakukan iterasi melalui
array, baca jenis setiap tombol dengan membandingkan
properti
type-nya denganNavigationButtonKnownType.compass, dan ekstrak tampilan fisik dengan memanggil propertiview-nya. Perhatikan bahwa tombol yang tepat dalam array ini berbeda dengan tombol yang tersedia selama panduan aktif.
Komponen panduan aktif
Saat panduan belokan demi belokan dimulai, SDK akan membuka rangkaian lengkap kontrol
navigasi. Objek ActiveGuidanceUIState Anda memberikan akses ke komponen Google berikut:
turnCard: Banner header utama yang menampilkan petunjuk manuver mendatang, pengukuran jarak, dan panduan jalur. Tempatkan di bagian atas tata letak untuk membuat hierarki navigasi yang sudah dikenal dan menambatkan tampilan kustom di sekitarnya.etaCard: Banner footer yang menampilkan perkiraan waktu tiba, sisa waktu perjalanan, dan sisa jarak ke tujuan. Tempatkan di sepanjang tepi bawah layar, atau integrasikan koordinatnya dengan sheet pengelolaan tugas kustom Anda.tripProgressBar: Status progres vertikal yang menunjukkan kepada pengemudi seberapa jauh mereka telah melakukan perjalanan di sepanjang rute saat ini. Tidak seperti tata letak lama yang menetapkan ini secara ketat ke tepi peta, Anda memiliki kebebasan penuh untuk menambatkannya di mana saja—misalnya, di sepanjang tepi samping penampung kustom.speedWidget: Kontrol mengambang untuk speedometer dan batas kecepatan yang diposting. Bergantung pada setelan API Anda (propertishouldDisplaySpeedometerdanshouldDisplaySpeedLimitdariGMSMapView) dan ketersediaan data, tampilan ini akan diubah ukurannya secara dinamis di antara empat status visual saat runtime (tidak menampilkan apa pun, hanya kecepatan saat ini, hanya batas kecepatan, atau kedua pembacaan). Karena widget dapat beralih di antara ukuran ini tanpa pemberitahuan, selalu jangkar tampilan di sekitarnya menggunakan batasan sehingga tata letak Anda otomatis beradaptasi untuk mencegah tumpang-tindih spasial.
buttons: Array tampilan tindakan mengambang yang diperluas untuk status panduan aktif (biasanya mencakup tombol Kompas dan Pelaporan Insiden). Sama seperti dalam status siap navigasi, Anda dapat menemukan dan mengekstrak tampilan tombol satu per satu dengan memfilter array menuruttype(.compassatau.reporting) dan mengekstrak tampilan fisik menggunakan propertiview-nya. Anda kemudian dapat memosisikannya secara terpisah, atau menambahkannya keGMSNavigationHidingStackView. Tampilan stack ini mengatur tombol secara vertikal dan, saat ruang habis, menyembunyikannya mulai dari akhir arrayarrangedSubviews. Jangan tetapkanisHiddenpada tampilan yang dikelolanya.
NavigationStyleValues.headerNominalHeight, yang cukup tinggi untuk
konten kartu belokan apa pun. Agar framing kamera tetap stabil, batasi bagian atas
viewport langsung ke tepi bawah turnCard, seperti yang ditunjukkan
dalam contoh implementasi.
Komponen perintah dinamis
Perintah, seperti pemberitahuan insiden atau peringatan kamera pemantau, dipicu secara independen selama panduan aktif.
Saat perintah siap ditampilkan, SDK akan memanggil callback showPrompt(navMap:newPrompt:) delegasi Anda dan meneruskan tampilan newPrompt secara langsung. Delegasi Anda bertanggung jawab untuk memosisikan
perintah ini dengan lancar di atas tata letak Anda (biasanya ditambatkan ke tepi bawah
penampung peta).
Karena perintah yang masuk mencakup bagian bawah layar, Anda harus memperbarui tata letak untuk mencegah perintah tumpang-tindih dengan area pandang, logo Google, atau tombol apa pun yang sejajar di bagian bawah.
Delegasi Anda juga mengontrol cara perintah ditampilkan dan ditutup di layar. Untuk mengetahui detailnya, lihat Menyesuaikan perintah.
Menangani ukuran layar dan mode lebar
Untuk menangani perubahan dimensi peta dan orientasi layar, delegasi tata letak menggunakan fitur berikut:
Pengubahan ukuran tampilan: Menyesuaikan tata letak setiap kali ukuran fisik peta berubah.
Mode lebar: Beralih ke varian tata letak format lebar jika peta cukup lebar.
Merespons pengubahan ukuran tampilan
Tata letak layar terpisah, penggeser penampung, dan rotasi perangkat biasanya memicu callbacksizeChanged(navMap:newState:). Gunakan callback ini untuk melakukan penyesuaian responsif umum pada UI kustom Anda. Terapkan
sizeChanged(navMap:newState:) untuk memosisikan ulang elemen kustom untuk rasio aspek layar
baru, terapkan titik henti sementara lebar atau tinggi kustom Anda sendiri, dan deteksi saat
peristiwa pengubahan ukuran mengalihkan mode lebar untuk menukar varian tata letak dengan aman.
Memahami mode lebar
Mode lebar diaktifkan saat penampung peta cukup lebar untuk menampilkan komponen UI secara berdampingan.
Baca boolean wideMode dari objek status untuk memosisikan ulang elemen UI kustom Anda dan menjaga bagian tengah peta tetap terlihat jelas bagi pengemudi. Karena
komponen yang disediakan Google seperti kartu belokan dan kartu PWT otomatis menyusut
dan berubah bentuk dalam mode lebar, membaca boolean ini akan memastikan tata letak Anda beradaptasi pada
saat yang sama persis dengan pembaruan komponen Google.
Pertimbangkan contoh berikut untuk memosisikan komponen tata letak dalam mode standar dan lebar:
Mode potret standar: Posisikan kartu belokan di bagian atas layar dan kartu PWT di bagian bawah.
Mode lebar: Pertahankan kartu belokan dan kartu PWT di sepanjang tepi depan layar, dengan kartu belokan di bagian atas dan kartu PWT di bagian bawah. Menempatkan salah satu kartu jauh dari tepi depan akan menghasilkan perilaku yang tidak ditentukan. Anda dapat menempatkan area pandang dan konten Anda sendiri di mana saja; pilihan yang umum adalah sisi akhir kartu.
Memeriksa mode lebar selama transisi status
Jika tata letak Anda mendukung variasi mode lebar, evaluasi boolean wideMode
di dalam setiap callback transisi status, bukan hanya mengandalkan
sizeChanged(navMap:newState:).
enableNavigationUI(navMap:newState:) dan
startGuidance(navMap:newState:oldState:) untuk menangani peluncuran aplikasi awal dalam
orientasi lanskap. Pendekatan
ini memastikan bahwa tata letak Anda mengevaluasi status mode lebar dan mengaktifkan
varian tata letak standar atau lebar yang benar saat status navigasi baru
dimulai.
Menyesuaikan dengan gaya Google
Untuk membantu tampilan kustom Anda menyesuaikan spasi komponen yang disediakan Google, SDK menyediakan class NavigationStyleValues. Properti class-nya menampilkan
pengukuran dalam poin.
Misalnya, untuk menempatkan tombol kustom di sudut atas layar di seberang
kartu belokan, gunakan NavigationStyleValues.headerTopPadding sebagai margin atas
tombol. Tombol kemudian akan sejajar dengan tepi atas kartu belokan.
Pengukuran berikut tersedia:
NavigationStyleValues.buttonHorizontalPaddingNavigationStyleValues.buttonVerticalPaddingNavigationStyleValues.defaultCornerRadiusNavigationStyleValues.elementHorizontalPaddingNavigationStyleValues.headerFooterHorizontalPaddingNavigationStyleValues.headerNominalHeightNavigationStyleValues.headerTopPadding
Tampilan yang disediakan Google juga menyertakan margin bawaan. Saat Anda menumpuk dua
tampilan yang disediakan Google, batasi satu tampilan ke layoutMarginsGuide tampilan lainnya agar
marginnya tidak bertambah. Misalnya, untuk menempatkan widget kecepatan di atas
kartu PWT, batasi anchor bawah speedWidget ke
etaCard.layoutMarginsGuide.topAnchor.
Menyesuaikan perintah
Delegasi tata letak Anda mengontrol cara perintah ditampilkan dan ditutup di layar, serta sudut mana yang dibulatkan.
Perintah animasi
SDK tidak menganimasikan perintah untuk Anda. Delegasi Anda menentukan cara setiap perintah muncul dan menghilang:
- Di
showPrompt(navMap:newPrompt:), tambahkan perintah ke tampilan peta pada posisi awal, lalu animasikan ke tempatnya. Misalnya, mulai perintah tepat di bawah area yang terlihat, atau di belakang panel bawah dengan tepi atasnya sejajar dengan bagian atas panel. - Di
hidePrompt(navMap:oldPrompt:), animasikan perintah agar tidak terlihat, lalu hapus dari superview-nya saat animasi selesai. - Di
changePrompt(navMap:newPrompt:oldPrompt:), jalankan animasi sembunyikan dan tampilkan secara bersamaan untuk mengganti satu perintah dengan perintah lainnya.
Contoh implementasi menggunakan pendekatan ini.
Untuk menonaktifkan perintah terkait lalu lintas, rute yang lebih baik, dan insiden, tetapkan properti shouldDisplayPrompts dari GMSNavigator ke false.
Membulatkan sudut perintah
Prompt sesuai dengan protokol NavigationRoundedCornerView, sehingga Anda dapat memilih
sudut mana yang dibulatkan. Secara default, perintah hanya membulatkan sudut
atasnya, yang sesuai untuk perintah yang ditambatkan ke tepi bawah layar.
Jika Anda menempatkan perintah di atas konten lain, seperti panel bawah, bulatkan keempat sudutnya:
newPrompt.roundedCorners = [
.layerMinXMinYCorner, .layerMaxXMinYCorner,
.layerMinXMaxYCorner, .layerMaxXMaxYCorner,
]
Contoh: Implementasi tata letak berbasis batasan
Contoh berikut menunjukkan delegasi tata letak dasar yang menggunakan batasan Tata Letak Otomatis untuk memosisikan kartu belokan, kartu PWT, tombol, logo Google, dan area pandang. Fitur ini juga menggeser perintah ke dalam dan ke luar layar. Agar contoh tetap singkat, contoh ini tidak menangani mode lebar, widget kecepatan, atau status progres perjalanan, sehingga cocok untuk aplikasi yang hanya mendukung orientasi potret.
import GoogleNavigation
import UIKit
/// A layout delegate that positions the essential navigation UI elements: the
/// turn card, ETA card, buttons, Google logo, and viewport. It also slides
/// prompts on and off the screen.
@MainActor
final class BasicLayoutDelegate: NSObject, NavigationLayoutDelegate {
/// How long prompts take to slide on or off the screen, in seconds.
private static let promptAnimationDuration: TimeInterval = 0.4
/// The views and constraints for one navigation state.
@MainActor
private final class StateElements {
let buttonStack = GMSNavigationHidingStackView(
position: .bottom, alignment: .trailing)
var constraints: [NSLayoutConstraint] = []
private unowned let navMap: GMSMapView
private let buttons: [UIView]
private let topLevelViews: [UIView]
init(
navMap: GMSMapView, buttons: [NavigationUIButton],
topLevelViews: [UIView]
) {
self.navMap = navMap
self.buttons = buttons.map { $0.view }
self.topLevelViews = topLevelViews
}
/// Adds the views to the map view, and then activates the constraints.
func activate() {
topLevelViews.forEach { navMap.addSubview($0) }
buttonStack.arrangedSubviews = buttons
navMap.addSubview(buttonStack)
NSLayoutConstraint.activate(constraints)
}
/// Deactivates the constraints, and then removes the views.
func deactivate() {
NSLayoutConstraint.deactivate(constraints)
buttonStack.removeFromSuperview()
buttonStack.arrangedSubviews = []
topLevelViews.forEach { $0.removeFromSuperview() }
}
}
private var navigationReadyElements: StateElements?
private var activeGuidanceElements: StateElements?
private var currentPrompt: NavigationPromptView?
private var promptBottomConstraint: NSLayoutConstraint?
/// Constraints that apply in both the navigation-ready and active guidance
/// states.
private var sharedConstraints: [NSLayoutConstraint] = []
/// Marks the bottom of the map content area. The guide stays above the ETA
/// card and above any prompt that's on the screen.
private let mapContentsBottomGuide = UILayoutGuide()
// MARK: - Navigation-ready state
func enableNavigationUI(
navMap: GMSMapView, newState: NavigationReadyUIState
) {
let safeArea = navMap.safeAreaLayoutGuide
let bottomGuide = mapContentsBottomGuide
navMap.addLayoutGuide(bottomGuide)
// Keep the guide at the bottom of the safe area unless a higher-priority
// constraint pushes it up.
let lowPriorityBottom = bottomGuide.bottomAnchor.constraint(
equalTo: safeArea.bottomAnchor)
lowPriorityBottom.priority = .defaultLow
sharedConstraints = [
bottomGuide.heightAnchor.constraint(equalToConstant: 0),
lowPriorityBottom,
]
let logo = newState.googleLogo
let viewport = newState.viewport
let elements = StateElements(
navMap: navMap, buttons: newState.buttons,
topLevelViews: [logo, viewport])
let buttonStack = elements.buttonStack
elements.constraints = sharedConstraints + [
buttonStack.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
buttonStack.topAnchor.constraint(equalTo: safeArea.topAnchor),
buttonStack.bottomAnchor.constraint(equalTo: bottomGuide.topAnchor),
logo.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
logo.bottomAnchor.constraint(equalTo: bottomGuide.topAnchor),
viewport.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
viewport.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
viewport.topAnchor.constraint(equalTo: safeArea.topAnchor),
viewport.bottomAnchor.constraint(equalTo: bottomGuide.topAnchor),
]
elements.activate()
navigationReadyElements = elements
}
func disableNavigationUI(
navMap: GMSMapView, oldState: NavigationReadyUIState
) {
currentPrompt?.removeFromSuperview()
currentPrompt = nil
promptBottomConstraint = nil
navigationReadyElements?.deactivate()
navigationReadyElements = nil
navMap.removeLayoutGuide(mapContentsBottomGuide)
}
// MARK: - Active guidance state
func startGuidance(
navMap: GMSMapView, newState: ActiveGuidanceUIState,
oldState: NavigationReadyUIState
) {
navigationReadyElements?.deactivate()
let safeArea = navMap.safeAreaLayoutGuide
let bottomGuide = mapContentsBottomGuide
let turnCard = newState.turnCard
let etaCard = newState.etaCard
let logo = newState.googleLogo
let viewport = newState.viewport
let elements = StateElements(
navMap: navMap, buttons: newState.buttons,
topLevelViews: [turnCard, etaCard, viewport, logo])
let buttonStack = elements.buttonStack
elements.constraints = sharedConstraints + [
turnCard.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
turnCard.topAnchor.constraint(equalTo: navMap.topAnchor),
etaCard.leadingAnchor.constraint(equalTo: navMap.leadingAnchor),
etaCard.bottomAnchor.constraint(equalTo: navMap.bottomAnchor),
bottomGuide.bottomAnchor.constraint(
lessThanOrEqualTo: etaCard.topAnchor),
buttonStack.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
buttonStack.topAnchor.constraint(equalTo: turnCard.bottomAnchor),
buttonStack.bottomAnchor.constraint(equalTo: bottomGuide.topAnchor),
logo.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
logo.bottomAnchor.constraint(equalTo: bottomGuide.topAnchor),
// Frame the camera in the open area below the turn card.
viewport.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
viewport.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
viewport.topAnchor.constraint(equalTo: turnCard.bottomAnchor),
viewport.bottomAnchor.constraint(equalTo: bottomGuide.topAnchor),
]
elements.activate()
activeGuidanceElements = elements
}
func stopGuidance(
navMap: GMSMapView, newState: NavigationReadyUIState,
oldState: ActiveGuidanceUIState
) {
activeGuidanceElements?.deactivate()
activeGuidanceElements = nil
navigationReadyElements?.activate()
}
// MARK: - Prompts
func showPrompt(navMap: GMSMapView, newPrompt: NavigationPromptView) {
navMap.addSubview(newPrompt)
currentPrompt = newPrompt
// Start with the prompt just below the bottom edge of the map view.
let bottomConstraint = newPrompt.bottomAnchor.constraint(
equalTo: navMap.bottomAnchor, constant: newPrompt.bounds.height)
promptBottomConstraint = bottomConstraint
NSLayoutConstraint.activate([
bottomConstraint,
newPrompt.leadingAnchor.constraint(
equalTo: navMap.safeAreaLayoutGuide.leadingAnchor),
// Keep the map content above the prompt.
mapContentsBottomGuide.bottomAnchor.constraint(
lessThanOrEqualTo: newPrompt.topAnchor),
])
// Lay out the prompt in its starting position, and then slide it up.
navMap.layoutIfNeeded()
UIView.animate(withDuration: Self.promptAnimationDuration) {
bottomConstraint.constant = 0
navMap.layoutIfNeeded()
}
}
func hidePrompt(navMap: GMSMapView, oldPrompt: NavigationPromptView) {
guard let bottomConstraint = promptBottomConstraint else { return }
promptBottomConstraint = nil
currentPrompt = nil
// Slide the prompt down, and then remove it.
UIView.animate(withDuration: Self.promptAnimationDuration) {
bottomConstraint.constant = oldPrompt.bounds.height
navMap.layoutIfNeeded()
} completion: { _ in
oldPrompt.removeFromSuperview()
}
}
func changePrompt(
navMap: GMSMapView, newPrompt: NavigationPromptView,
oldPrompt: NavigationPromptView
) {
// Slide the old prompt out and the new prompt in at the same time.
hidePrompt(navMap: navMap, oldPrompt: oldPrompt)
showPrompt(navMap: navMap, newPrompt: newPrompt)
}
}
Untuk menggunakan delegasi, tetapkan di tampilan peta sebelum Anda mengaktifkan navigasi, seperti yang dijelaskan dalam checklist Hal-hal penting.
Batasan dan masalah umum
Penyesuaian tata letak tidak berlaku untuk CarPlay, yang menggunakan template tata letak tetap. Jika Anda memanggil setLayoutDelegate(_:) pada tampilan peta yang Anda buat untuk
layar CarPlay, metode ini akan menampilkan error.
Untuk masalah yang memengaruhi versi SDK tertentu, lihat Masalah umum dalam catatan rilis.