Menambahkan peta ke aplikasi iOS dengan SwiftUI (Swift)

1. Sebelum Memulai

Codelab ini mengajarkan Anda cara menggunakan Maps SDK for iOS dengan SwiftUI.

screenshot-iphone-12-black@2x.png

Prasyarat

  • Pengetahuan dasar Swift
  • Pemahaman dasar tentang SwiftUI

Yang akan Anda lakukan

  • Mengaktifkan dan menggunakan Maps SDK for iOS untuk menambahkan Google Maps ke aplikasi iOS menggunakan SwiftUI.
  • Menambahkan penanda ke peta.
  • Meneruskan status dari tampilan SwiftUI ke objek GMSMapView dan sebaliknya.

Yang akan Anda perlukan

2. Memulai persiapan

Untuk langkah pengaktifan berikut, aktifkan Maps SDK for iOS.

Menyiapkan Google Maps Platform

Jika Anda belum memiliki akun Google Cloud Platform dan project dengan penagihan diaktifkan, lihat panduan Memulai Google Maps Platform untuk membuat akun penagihan dan project.

  1. Di Cloud Console, klik menu drop-down project lalu pilih project yang ingin Anda gunakan untuk codelab ini.

  1. Aktifkan API dan SDK Google Maps Platform yang diperlukan untuk codelab ini di Google Cloud Marketplace. Untuk melakukannya, ikuti langkah-langkah dalam video ini atau dokumentasi ini.
  2. Buat kunci API di halaman Kredensial di Cloud Console. Anda dapat mengikuti langkah-langkah dalam video ini atau dokumentasi ini. Semua permintaan ke Google Maps Platform memerlukan kunci API.

3. Mendownload kode awal

Untuk membantu Anda memulai secepatnya, berikut beberapa kode awal untuk membantu Anda mengikuti codelab ini. Anda dapat langsung ke bagian solusi, namun jika Anda ingin mengikuti semua langkah untuk membuatnya sendiri, baca semuanya.

  1. Lakukan clone repositori jika sudah menginstal git.
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git

Atau, Anda dapat mengklik tombol berikut untuk mendownload kode sumber.

  1. Setelah mendapatkan kode, di terminal cd pilih direktori starter/GoogleMapsSwiftUI.
  2. Jalankan carthage update --platform iOS untuk mendownload Maps SDK for iOS
  3. Terakhir, buka file GoogleMapsSwiftUI.xcodeproj di Xcode

4. Ringkasan Kode

Dalam project permulaan yang Anda download, class berikut telah disediakan dan diterapkan untuk Anda:

  • AppDelegate - UIApplicationDelegate aplikasi. Di sini tempat Maps SDK for iOS akan diinisialisasi.
  • City - struct yang mewakili kota (berisi nama dan koordinat kota).
  • MapViewController - UIViewController UIKit sederhana yang berisi Google Maps (GMSMapView)
  • SceneDelegate - UIWindowSceneDelegate aplikasi tempat instance ContentView dibuat.

Selain itu, class berikut memiliki penerapan parsial dan akan Anda selesaikan pada akhir Codelab ini:

  • ContentView - tampilan SwiftUI tingkat teratas yang berisi aplikasi Anda.
  • MapViewControllerBridge - class yang menjembatani tampilan UIKit ke tampilan SwiftUI. Secara khusus, ini adalah class yang akan membuat MapViewController dapat diakses di SwiftUI.

5. Menggunakan SwiftUI vs. UIKit

SwiftUI diperkenalkan di iOS 13 sebagai framework UI alternatif pengganti UIKit untuk mengembangkan aplikasi iOS. Dibandingkan dengan UIKit pendahulunya, SwiftUI menawarkan sejumlah keuntungan. Di antaranya:

  • Tampilan diperbarui secara otomatis saat status berubah. Menggunakan objek yang disebut Status, setiap perubahan pada nilai dasar di dalamnya akan menyebabkan UI diperbarui secara otomatis.
  • Pratinjau langsung memungkinkan pengembangan yang lebih cepat. Pratinjau langsung meminimalkan kebutuhan untuk mem-build dan men-deploy kode ke emulator untuk melihat perubahan visual karena pratinjau tampilan SwiftUI dapat langsung dilihat di Xcode.
  • Sumber tepercaya ada di Swift. Semua tampilan di SwiftUI dideklarasikan di Swift, sehingga penggunaan Interface Builder tidak lagi diperlukan.
  • Interoperabilitas dengan UIKit. Interoperabilitas dengan UIKit memastikan aplikasi yang ada dapat menggunakan SwiftUI secara bertahap bersama dengan tampilan yang ada. Selain itu, library yang belum mendukung SwiftUI, seperti Maps SDK for iOS, masih dapat digunakan di SwiftUI.

Tetapi ada juga beberapa kekurangan:

  • SwiftUI hanya tersedia di iOS 13 atau versi yang lebih baru.
  • Hierarki tampilan tidak dapat diperiksa dalam pratinjau Xcode.

Status dan aliran data SwiftUI

SwiftUI menawarkan cara baru untuk membuat UI menggunakan pendekatan deklaratif—Anda memberi tahu SwiftUI bagaimana Anda ingin tampilan diperlihatkan bersama dengan semua statusnya yang berbeda, dan sistem akan melakukan sisanya. SwiftUI menangani pembaruan tampilan setiap kali status yang mendasari berubah karena adanya peristiwa atau tindakan pengguna. Desain ini biasanya disebut aliran data searah. Meskipun spesifikasi desain ini berada di luar cakupan dalam codelab ini, sebaiknya Anda membaca cara kerjanya dalam dokumentasi Status dan Aliran Data Apple.

Menjembatani UIKit dan SwiftUI menggunakan UIViewRepresentable atau UIViewControllerRepresentable

Karena Maps SDK for iOS dibuat atas dasar UIKit dan belum menyediakan tampilan yang kompatibel dengan SwiftUI, penggunaannya di SwiftUI harus sesuai dengan UIViewRepresentable atau UIViewControllerRepresentable. Protokol ini memungkinkan SwiftUI menyertakan UIView dan UIViewController yang dibuat UIKit. Meskipun Anda dapat menggunakan salah satu protokol untuk menambahkan Google Maps ke tampilan SwiftUI, pada langkah berikutnya, kita akan melihat penggunaan UIViewControllerRepresentable untuk menyertakan UIViewController yang berisi peta.

6. Menambahkan peta

Di bagian ini, Anda akan menambahkan Google Maps ke tampilan SwiftUI.

add-a-map-screenshot@2x.png

Menambahkan kunci API

Kunci API yang Anda buat di langkah sebelumnya harus diberikan ke Maps SDK for iOS untuk mengaitkan akun Anda dengan peta yang akan ditampilkan di aplikasi.

Untuk memberikan kunci API Anda, buka file AppDelegate.swift lalu buka metode application(_, didFinishLaunchingWithOptions). Saat ini, SDK diinisialisasi melalui GMSServices.provideAPIKey() dengan string "YOUR_API_KEY". Ganti string tersebut dengan kunci API Anda. Dengan menyelesaikan langkah ini, Maps SDK for iOS akan diinisialisasi saat aplikasi diluncurkan.

Menambahkan Google Maps menggunakan MapViewControllerBridge

Setelah kunci API Anda diberikan ke SDK, langkah berikutnya adalah menampilkan peta di aplikasi.

Pengontrol tampilan yang disediakan dalam kode awal, MapViewController, saat ini berisi GMSMapView dalam tampilannya. Namun, karena pengontrol tampilan ini dibuat di UIKit, Anda harus menjembatani class ini ke SwiftUI sehingga dapat digunakan di dalam ContentView. Untuk melakukannya:

  1. Buka file MapViewControllerBridge di Xcode.

Class ini sesuai dengan UIViewControllerRepresentable yang merupakan protokol yang diperlukan untuk menggabungkan UIViewController UIKit, sehingga dapat digunakan sebagai tampilan SwiftUI. Dengan kata lain, mematuhi protokol ini memungkinkan Anda menjembatani tampilan UIKit ke tampilan SwiftUI. Untuk mematuhi protokol ini, diperlukan penerapan dua metode:

  • makeUIViewController(context) - metode ini dipanggil oleh SwiftUI untuk membuat UIViewController yang mendasari. Di sini Anda akan membuat instance UIViewController dan meneruskan status awalnya.
  • updateUIViewController(_, context) - metode ini dipanggil oleh SwiftUI setiap kali status berubah. Di sini Anda akan melakukan modifikasi pada UIViewController yang mendasari untuk bereaksi sebagai respons terhadap perubahan status.
  1. Buat MapViewController

Di dalam fungsi makeUIViewController(context), buat instance MapViewController baru dan tampilkan sebagai hasilnya. Setelah melakukannya, MapViewControllerBridge Anda sekarang akan terlihat seperti ini:

MapViewControllerBridge

import GoogleMaps
import SwiftUI

struct MapViewControllerBridge: UIViewControllerRepresentable {

  func makeUIViewController(context: Context) -> MapViewController {
    return MapViewController()
  }

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
  }
}

Menggunakan MapViewControllerBridge di ContentView

Setelah MapViewControllerBridge membuat instance MapViewController, langkah berikutnya adalah menggunakan struct ini dalam ContentView untuk menampilkan peta.

  1. Buka file ContentView di Xcode.

ContentView dibuat instance-nya di SceneDelegate dan berisi tampilan aplikasi tingkat atas. Peta akan ditambahkan dari dalam file ini.

  1. Buat MapViewControllerBridge dalam properti body.

Dalam properti body file ini, ZStack telah disediakan dan diterapkan untuk Anda. ZStack saat ini berisi daftar kota yang dapat berinteraksi dan dapat ditarik yang akan Anda gunakan di langkah berikutnya. Untuk saat ini, dalam ZStack, buat MapViewControllerBridge sebagai tampilan turunan pertama ZStack, sehingga peta akan ditampilkan di aplikasi di belakang tampilan daftar kota. Setelah melakukannya, konten properti body dalam ContentView akan terlihat seperti ini:

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()
      } // ...
    }
  }
}
  1. Sekarang lanjutkan dan jalankan aplikasi. Anda akan melihat peta dimuat di layar perangkat beserta daftar kota yang dapat ditarik ke bagian bawah layar.

7. Menambahkan penanda ke peta

Pada langkah sebelumnya, Anda menambahkan peta bersama daftar yang dapat berinteraksi yang menampilkan daftar kota. Di bagian ini, Anda akan menambahkan penanda untuk setiap kota dalam daftar tersebut.

map-with-markers@2x.png

Penanda sebagai Status

ContentView saat ini mendeklarasikan properti bernama markers yang merupakan daftar GMSMarker. Kode ini mewakili setiap kota yang dideklarasikan di properti statis cities. Perhatikan bahwa properti ini dianotasi dengan Status wrapper properti SwiftUI untuk menunjukkan bahwa properti ini akan dikelola oleh SwiftUI. Jadi, jika ada perubahan yang terdeteksi dengan properti ini, seperti menambahkan atau menghapus penanda, tampilan yang menggunakan status ini akan diperbarui.

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
  }

Perhatikan bahwa ContentView menggunakan properti markers untuk merender daftar kota dengan meneruskannya ke class CitiesList.

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)
      }
    }
  }
}

Meneruskan Status ke MapViewControllerBridge melalui Binding

Selain daftar kota yang menampilkan data dari properti markers, teruskan properti ini ke struct MapViewControllerBridge agar dapat digunakan untuk menampilkan penanda tersebut pada peta. Untuk melakukannya:

  1. Deklarasikan properti markers baru dalam MapViewControllerBridge yang dianotasi dengan @Binding

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. Di MapViewControllerBridge, perbarui metode updateUIViewController(_, context) untuk memanfaatkan properti markers

Seperti yang disebutkan di langkah sebelumnya, updateUIViewController(_, context) akan dipanggil oleh SwiftUI setiap kali status berubah. Dalam metode inilah kita ingin memperbarui peta sehingga menampilkan penanda di markers. Untuk melakukannya, Anda harus memperbarui properti map setiap penanda. Setelah menyelesaikan langkah ini, MapViewControllerBridge Anda akan terlihat seperti ini:

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 }
  }
}
  1. Teruskan properti markers dari ContentView ke MapViewControllerBridge

Karena Anda menambahkan properti baru di MapViewControllerBridge, maka nilai untuk properti ini harus diteruskan ke penginisialisasi untuk MapViewControllerBridge. Jadi, jika Anda mencoba mem-build aplikasi, Anda akan melihat bahwa aplikasi tidak akan dikompilasi. Untuk memperbaikinya, lakukan pembaruan pada ContentView tempat MapViewControllerBridge dibuat dan teruskan properti markers seperti berikut:

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers)
        // ...
      }
    }
  }
}

Perhatikan bahwa awalan $ digunakan untuk meneruskan markers ke MapViewControllerBridge karena mengharapkan properti terikat. $ adalah awalan yang dicadangkan untuk digunakan dengan wrapper properti Swift. Jika diterapkan ke Status, tindakan ini akan menampilkan Binding.

  1. Lanjutkan dan jalankan aplikasi untuk melihat penanda yang ditampilkan di peta.

8. Menganimasikan ke kota yang dipilih

Pada langkah sebelumnya, Anda menambahkan penanda ke peta dengan meneruskan Status dari satu tampilan SwiftUI ke tampilan lainnya. Pada langkah ini, Anda akan menganimasikan peta ke kota/penanda setelah diketuk di daftar yang dapat berinteraksi. Untuk menjalankan animasi, Anda akan bereaksi terhadap perubahan pada Status dengan memodifikasi posisi kamera peta saat perubahan tersebut terjadi. Untuk mempelajari lebih lanjut konsep kamera peta, lihat Kamera dan Tampilan.

animate-city@2x.png

Menganimasikan peta ke kota yang dipilih

Untuk menganimasikan peta ke kota yang dipilih:

  1. Tentukan Binding baru di MapViewControllerBridge

ContentView memiliki properti Status yang disebut selectedMarker yang diinisialisasi ke nilai nol dan mendapatkan pembaruan setiap kali kota dipilih dalam daftar. Proses ini ditangani oleh tampilan CitiesList buttonAction dalam ContentView.

ContentView

CitiesList(markers: $markers) { (marker) in
  guard self.selectedMarker != marker else { return }
  self.selectedMarker = marker
  // ...
}

Setiap kali selectedMarker berubah, MapViewControllerBridge harus mengetahui perubahan status ini agar dapat menganimasikan peta ke penanda yang dipilih. Jadi, tentukan Binding baru dalam MapViewControllerBridge dari jenis GMSMarker lalu beri nama properti selectedMarker.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?
}
  1. Perbarui MapViewControllerBridge untuk menganimasikan peta setiap kali selectedMarker berubah

Setelah Binding baru dideklarasikan, Anda perlu memperbarui fungsi updateUIViewController_, context) MapViewControllerBridge agar peta dianimasikan ke penanda yang dipilih. Lanjutkan dengan menyalin kode di bawah ini:

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)
          })
        }
      }
    }
  }
}

Fungsi animateToSelectedMarker(viewController) akan menjalankan urutan animasi peta menggunakan fungsi animate(with) GMSMapView.

  1. Teruskan selectedMarker ContentView ke MapViewControllerBridge

Setelah Binding baru MapViewControllerBridge dideklarasikan, lanjutkan dan perbarui ContentView untuk diteruskan ke selectedMarker tempat MapViewControllerBridge dibuat instance-nya.

ContentView

struct ContentView: View {
  // ...
  var body: some View {
    // ...
    GeometryReader { geometry in
      ZStack(alignment: .top) {
        // Map
        MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker)
        // ...
      }
    }
  }
}

Menyelesaikan langkah ini sekarang akan menganimasikan peta setiap kali kota baru dipilih dalam daftar.

Menganimasikan tampilan SwiftUI untuk menekankan kota

SwiftUI membuat animasi tampilan menjadi sangat mudah karena SwiftUI akan menangani performa animasi untuk transisi Status. Untuk mendemonstrasikan ini, Anda akan menambahkan lebih banyak animasi dengan memfokuskan tampilan ke kota yang dipilih setelah animasi peta selesai. Untuk melakukannya, selesaikan langkah-langkah berikut:

  1. Tambahkan penutupan onAnimationEnded ke MapViewControllerBridge

Karena animasi SwiftUI akan dijalankan setelah urutan animasi peta yang Anda tambahkan sebelumnya, deklarasikan penutupan baru bernama onAnimationEnded dalam MapViewControllerBridge, lalu panggil penutupan ini setelah penundaan 0,5 detik setelah animasi peta terakhir dalam metode 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()
            })
          })
        }
      }
    }
  }
}
  1. Terapkan onAnimationEnded di MapViewControllerBridge

Terapkan penutupan onAnimationEnded tempat MapViewControllerBridge dibuat instance-nya dalam ContentView. Salin dan tempelkan kode berikut yang menambahkan Status baru bernama zoomInCenter sekaligus mengubah tampilan menggunakan clipShape dan memvariasikan diameter bentuk yang terpotong bergantung pada nilai 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))
      }
    }
  }
}
  1. Lanjutkan dan jalankan aplikasi untuk melihat animasi.

9. Mengirim peristiwa ke SwiftUI

Pada langkah ini, Anda akan memproses peristiwa yang dikeluarkan dari GMSMapView, dan mengirimkan peristiwa tersebut ke SwiftUI. Secara khusus, Anda akan menetapkan delegasi ke tampilan peta dan memproses peristiwa gerakan kamera, sehingga saat kota difokuskan dan kamera peta bergerak dari gestur, tampilan peta tidak akan fokus agar Anda bisa melihat semakin banyak peta.

Menggunakan Koordinator SwiftUI

GMSMapView memunculkan peristiwa seperti perubahan posisi kamera atau saat penanda diketuk. Mekanisme untuk memproses peristiwa ini adalah melalui protokol GMSMapViewDelegate. SwiftUI memperkenalkan konsep Koordinator yang digunakan secara khusus untuk bertindak sebagai delegasi untuk pengontrol tampilan UIKit. Jadi, dalam dunia SwiftUI, Koordinator harus bertanggung jawab untuk mematuhi protokol GMSMapViewDelegate. Untuk melakukannya, selesaikan langkah-langkah berikut:

  1. Buat Koordinator yang disebut MapViewCoordinator dalam MapViewControllerBridge

Buat class bersarang di dalam class MapViewControllerBridge dan beri nama MapViewCoordinator. Class ini harus sesuai dengan GMSMapViewDelegate dan harus mendeklarasikan MapViewControllerBridge sebagai properti.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    var mapViewControllerBridge: MapViewControllerBridge

    init(_ mapViewControllerBridge: MapViewControllerBridge) {
      self.mapViewControllerBridge = mapViewControllerBridge
    }
  }
}
  1. Terapkan makeCoordinator() di MapViewControllerBridge

Selanjutnya, terapkan metode makeCoordinator() dalam MapViewControllerBridge dan tampilkan instance MapViewCoodinator yang Anda buat di langkah sebelumnya.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeCoordinator() -> MapViewCoordinator {
    return MapViewCoordinator(self)
  }
}
  1. Tetapkan MapViewCoordinator sebagai delegasi tampilan peta

Setelah koordinator kustom dibuat, langkah berikutnya adalah menetapkan koordinator sebagai delegasi untuk tampilan peta pengontrol tampilan. Untuk melakukannya, perbarui inisialisasi pengontrol tampilan di makeUIViewController(context). Koordinator yang dibuat dari langkah sebelumnya akan dapat diakses dari objek Context.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeUIViewController(context: Context) -> MapViewController {
    let uiViewController = MapViewController()
    uiViewController.map.delegate = context.coordinator
    return uiViewController
  }
  1. Tambahkan penutupan ke MapViewControllerBridge sehingga kamera yang akan memindahkan peristiwa dapat diterapkan

Karena tujuannya adalah memperbarui tampilan dengan gerakan kamera, deklarasikan properti penutupan baru yang menerima boolean dalam MapViewControllerBridge yang disebut mapViewWillMove, lalu panggil penutupan ini di metode delegasi mapView(_, willMove) dalam MapViewCoordinator. Teruskan nilai gesture ke penutupan, sehingga tampilan SwiftUI hanya dapat bereaksi terhadap peristiwa gerakan kamera terkait gestur.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  var mapViewWillMove: (Bool) -> ()
  //...

  final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
    // ...
    func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
      self.mapViewControllerBridge.mapViewWillMove(gesture)
    }
  }
}
  1. Perbarui ContentView agar meneruskan nilai untuk mapWillMove

Dengan penutupan baru yang dideklarasikan di MapViewControllerBridge, perbarui ContentView agar dapat meneruskan nilai untuk penutupan baru ini. Dalam penutupan tersebut, alihkan Status zoomInCenter ke false jika peristiwa pergerakan terkait dengan gestur. Ini akan secara efektif menampilkan peta dalam tampilan lengkap lagi saat peta digerakkan oleh gestur.

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
        })
        // ...
      }
    }
  }
}
  1. Lanjutkan dan jalankan aplikasi untuk melihat perubahan baru.

10. Selamat

Selamat karena telah membaca sampai sini. Anda telah mempelajari banyak hal, dan semoga pelajaran yang telah didapatkan tersebut membuat Anda kini bisa membuat sendiri aplikasi SwiftUI menggunakan Maps SDK for iOS.

Yang telah Anda pelajari

Apa selanjutnya?

  • Maps SDK for iOS - dokumentasi resmi untuk Maps SDK for iOS
  • Places SDK for iOS - menemukan bisnis lokal dan lokasi menarik di sekitar Anda
  • maps-sdk-for-ios-samples - kode contoh di GitHub yang menunjukkan semua fitur dalam Maps SDK for iOS.
  • SwiftUI - Dokumentasi resmi Apple tentang SwiftUI
  • Bantu kami membuat konten yang menurut Anda paling berguna dengan menjawab pertanyaan di bawah:

Apa saja codelab lain yang ingin Anda lihat?

Visualisasi data pada peta Selengkapnya tentang cara menyesuaikan gaya peta saya Membuat interaksi 3D di peta

Apakah codelab yang Anda inginkan tidak tercantum di atas? Ajukan permintaan bersama masalah baru di sini.