Добавьте карту в свое приложение для iOS с помощью SwiftUI (Swift).

1. Прежде чем начать

В этой лабораторной работе вы узнаете, как использовать Maps SDK для iOS со SwiftUI.

скриншот-iphone-12-black@2x.png

Предпосылки

  • Базовые знания Swift
  • Базовое знакомство со SwiftUI

Что ты будешь делать

  • Включите и используйте Maps SDK для iOS, чтобы добавить Карты Google в приложение iOS с помощью SwiftUI.
  • Добавьте маркеры на карту.
  • Передать состояние из представления SwiftUI в объект GMSMapView и наоборот.

Что вам понадобится

2. Настройте

Для следующего этапа активации включите Maps SDK для iOS .

Настройте платформу Google Карт

Если у вас еще нет учетной записи Google Cloud Platform и проекта с включенным выставлением счетов, ознакомьтесь с руководством по началу работы с платформой Google Maps , чтобы создать платежную учетную запись и проект.

  1. В Cloud Console щелкните раскрывающееся меню проекта и выберите проект, который вы хотите использовать для этой лаборатории кода.

  1. Включите API и SDK платформы Google Maps, необходимые для этой лаборатории кода, в Google Cloud Marketplace . Для этого выполните действия, описанные в этом видео или в этой документации .
  2. Создайте ключ API на странице учетных данных Cloud Console. Вы можете выполнить действия, описанные в этом видео или в этой документации . Для всех запросов к платформе Google Maps требуется ключ API.

3. Загрузите стартовый код

Чтобы вы начали как можно быстрее, вот некоторый начальный код, который поможет вам следовать этой кодовой лаборатории. Мы приветствуем вас, чтобы перейти к решению, но если вы хотите выполнить все шаги, чтобы создать его самостоятельно, продолжайте читать.

  1. Клонируйте репозиторий, если у вас установлен git .
git clone https://github.com/googlecodelabs/maps-ios-swiftui.git

Кроме того, вы можете нажать следующую кнопку, чтобы загрузить исходный код.

  1. Получив код, в терминале cd в каталог starter/GoogleMapsSwiftUI .
  2. Запустите carthage update --platform iOS , чтобы загрузить Maps SDK для iOS.
  3. Наконец, откройте файл GoogleMapsSwiftUI.xcodeproj в Xcode.

4. Обзор кода

В загруженном вами начальном проекте для вас были предоставлены и реализованы следующие классы:

  • AppDelegateUIApplicationDelegate приложения. Здесь будет инициализирован Maps SDK для iOS.
  • City — структура, представляющая город (содержит название и координату города).
  • MapViewController — простой UIKit UIViewController , содержащий карту Google ( GMSMapView )
  • SceneDelegateUIWindowSceneDelegate приложения, из которого создается экземпляр ContentView .

Кроме того, следующие классы имеют частичные реализации и будут завершены вами к концу этой лаборатории кода:

  • ContentView — представление SwiftUI верхнего уровня, содержащее ваше приложение.
  • MapViewControllerBridge — класс, который соединяет представление UIKit с представлением SwiftUI. В частности, это класс, который сделает MapViewController доступным в SwiftUI.

5. Использование SwiftUI против UIKit

SwiftUI был представлен в iOS 13 как альтернативная платформа пользовательского интерфейса по сравнению с UIKit для разработки приложений iOS. По сравнению со своим предшественником UIKit, SwiftUI предлагает ряд преимуществ. Назвать несколько:

  • Представления обновляются автоматически при изменении состояния. Используя объекты с именем State , любое изменение содержащегося в нем базового значения приведет к автоматическому обновлению пользовательского интерфейса.
  • Предварительный просмотр в реальном времени ускоряет разработку. Предварительный просмотр в реальном времени сводит к минимуму необходимость создания и развертывания кода в эмуляторе, чтобы увидеть визуальные изменения, поскольку предварительный просмотр представления SwiftUI можно легко увидеть в Xcode.
  • Источник истины находится в Swift. Все представления в SwiftUI объявлены в Swift, поэтому использование Interface Builder больше не требуется.
  • Взаимодействует с UIKit. Взаимодействие с UIKit гарантирует, что существующие приложения могут постепенно использовать SwiftUI со своими существующими представлениями. Кроме того, библиотеки, которые еще не поддерживают SwiftUI, например Maps SDK для iOS, по-прежнему можно использовать в SwiftUI.

Есть и недостатки:

  • SwiftUI доступен только на iOS 13 или выше.
  • Иерархию представлений нельзя проверить в предварительных просмотрах Xcode.

Состояние SwiftUI и поток данных

SwiftUI предлагает новый способ создания пользовательского интерфейса с использованием декларативного подхода — вы указываете SwiftUI, как вы хотите, чтобы ваше представление выглядело вместе со всеми различными состояниями для него, а система сделает все остальное. SwiftUI обрабатывает обновление представления всякий раз, когда базовое состояние изменяется из-за события или действия пользователя. Этот дизайн обычно называют однонаправленным потоком данных . Хотя особенности этого дизайна выходят за рамки этой кодовой лаборатории, мы рекомендуем прочитать о том, как это работает, в документации Apple State and Data Flow .

Соединение UIKit и SwiftUI с помощью UIViewRepresentable или UIViewControllerRepresentable

Поскольку Maps SDK для iOS создан на основе UIKit и еще не предоставляет представление, совместимое со SwiftUI, для его использования в SwiftUI требуется соответствие либо UIViewRepresentable , либо UIViewControllerRepresentable . Эти протоколы позволяют SwiftUI включать встроенные в UIView и UIViewController соответственно. Хотя вы можете использовать любой протокол для добавления карты Google в представление SwiftUI, на следующем шаге мы рассмотрим использование UIViewControllerRepresentable для включения UIViewController , содержащего карту.

6. Добавьте карту

В этом разделе вы добавите Карты Google в представление SwiftUI.

добавить-карту-скриншот@2x.png

Добавьте свой ключ API

Ключ API, который вы создали на предыдущем шаге, необходимо предоставить Maps SDK для iOS, чтобы связать вашу учетную запись с картой, которая будет отображаться в приложении.

Чтобы предоставить ключ API, откройте файл AppDelegate.swift и перейдите к методу application(_, didFinishLaunchingWithOptions) . В настоящее время SDK инициализируется с помощью GMSServices.provideAPIKey() со строкой "YOUR_API_KEY". Замените эту строку своим ключом API. Выполнение этого шага приведет к инициализации Maps SDK для iOS при запуске приложения.

Добавьте карту Google с помощью MapViewControllerBridge

Теперь, когда ваш ключ API предоставлен SDK, следующим шагом будет отображение карты в приложении.

Контроллер представления, предоставленный в начальном коде, MapViewController в настоящее время содержит GMSMapView в своем представлении. Однако, поскольку этот контроллер представления был создан в UIKit, вам потребуется связать этот класс со SwiftUI, чтобы его можно было использовать внутри ContentView . Для этого:

  1. Откройте файл MapViewControllerBridge в Xcode.

Этот класс соответствует протоколу UIViewControllerRepresentable , необходимому для создания оболочки UIKit UIViewController чтобы его можно было использовать в качестве представления SwiftUI. Другими словами, соответствие этому протоколу позволяет вам соединить представление UIKit с представлением SwiftUI. Соответствие этому протоколу требует реализации двух методов:

  • makeUIViewController(context) — этот метод вызывается SwiftUI для создания базового UIViewController . Здесь вы должны создать экземпляр своего UIViewController и передать ему его начальное состояние.
  • updateUIViewController(_, context) — этот метод вызывается SwiftUI при каждом изменении состояния. Здесь вы можете вносить любые изменения в базовый UIViewController , чтобы реагировать на изменение состояния.
  1. Создайте 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 для отображения карты.

  1. Откройте файл ContentView в Xcode.

ContentView создается в SceneDelegate и содержит представление приложения верхнего уровня. Карта будет добавлена ​​из этого файла.

  1. Создайте 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()
      } // ...
    }
  }
}
  1. Теперь запустите приложение. Теперь вы должны увидеть загрузку карты на экране вашего устройства вместе с перетаскиваемым списком городов в нижней части экрана.

7. Добавьте маркеры на карту

На предыдущем шаге вы добавили карту вместе с интерактивным списком, отображающим список городов. В этом разделе вы добавите маркеры для каждого города в этом списке.

карта-с-маркерами@2x.png

Маркеры как состояние

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

Передать состояние в MapViewControllerBridge через привязку

В дополнение к списку городов, отображающих данные из свойства markers , передайте это свойство в структуру MapViewControllerBridge , чтобы его можно было использовать для отображения этих маркеров на карте. Для этого:

  1. Объявите новое свойство markers в MapViewControllerBridge , аннотированное с помощью @Binding

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. В MapViewControllerBridge обновите метод updateUIViewController(_, context) , чтобы использовать свойство markers .

Как упоминалось на предыдущем шаге, SwiftUI будет вызывать updateUIViewController(_, context) при каждом изменении состояния. Именно в этом методе мы хотим обновить карту, чтобы отобразить маркеры в 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 }
  }
}
  1. Передайте свойство 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 .

  1. Идите вперед и запустите приложение, чтобы увидеть маркеры, отображаемые на карте.

8. Анимация в выбранный город

На предыдущем шаге вы добавили маркеры на карту, передав состояние из одного представления SwiftUI в другое. На этом шаге вы перейдете к городу/маркеру после того, как вы коснетесь его в интерактивном списке. Чтобы выполнить анимацию, вы будете реагировать на изменения состояния, изменяя положение камеры на карте, когда происходит изменение. Чтобы узнать больше о концепции камеры карты, см. раздел Камера и вид .

анимация-город@2x.png

Анимация карты для выбранного города

Чтобы анимировать карту для выбранного города:

  1. Определите новую привязку в MapViewControllerBridge

ContentView имеет свойство State, называемое selectedMarker , которое инициализируется равным нулю и обновляется всякий раз, когда город выбирается в списке. Это обрабатывается CitiesList представления buttonAction в ContentView .

ContentView

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

Всякий раз, когда selectedMarker изменяется, MapViewControllerBridge должен знать об этом изменении состояния, чтобы он мог анимировать карту для выбранного маркера. Итак, определите новую привязку внутри MapViewControllerBridge типа GMSMarker и назовите свойство selectedMarker .

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?
}
  1. Обновите MapViewControllerBridge , чтобы анимировать карту при каждом изменении selectedMarker .

После объявления новой привязки вам необходимо обновить MapViewControllerBridge 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) будет выполнять последовательность анимаций карты с использованием GMSMapView animate(with) .

  1. Передайте selectedMarker маркер ContentView в MapViewControllerBridge

Как только MapViewControllerBridge новую привязку, обновите ContentView , чтобы передать в selectedMarker , где создается экземпляр MapViewControllerBridge .

ContentView

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

Выполнение этого шага теперь будет анимировать карту всякий раз, когда в списке будет выбран новый город.

Анимируйте представление SwiftUI, чтобы выделить город

SwiftUI делает анимацию представлений очень простой, поскольку он будет выполнять анимацию для переходов между состояниями. Чтобы продемонстрировать это, вы добавите больше анимаций, сфокусировав вид на выбранном городе после завершения анимации карты. Для этого выполните следующие шаги:

  1. Добавьте замыкание 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()
            })
          })
        }
      }
    }
  }
}
  1. Реализовать onAnimationEnded в MapViewControllerBridge

onAnimationEnded замыкание 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))
      }
    }
  }
}
  1. Идите вперед и запустите приложение, чтобы увидеть анимацию!

9. Отправить событие в SwiftUI

На этом шаге вы будете прослушивать события, исходящие от GMSMapView , и отправлять это событие в SwiftUI. В частности, вы настроите делегата на представление карты и будете прослушивать события перемещения камеры, чтобы, когда город сфокусировался и камера карты перемещалась из-за жеста, представление карты расфокусировалось, чтобы вы могли видеть больше карты.

Использование координаторов SwiftUI

GMSMapView генерирует такие события, как изменение положения камеры или касание маркера. Механизм прослушивания этих событий осуществляется через протокол GMSMapViewDelegate . SwiftUI представляет концепцию координатора, который специально используется для работы в качестве делегата для контроллеров представления UIKit. Таким образом, в мире SwiftUI координатор должен отвечать за соответствие протоколу GMSMapViewDelegate . Для этого выполните следующие шаги:

  1. Создайте координатора с именем MapViewCoordinator в MapViewControllerBridge

Создайте вложенный класс внутри класса MapViewControllerBridge и назовите его MapViewCoordinator . Этот класс должен соответствовать GMSMapViewDelegate и должен объявлять MapViewControllerBridge как свойство.

MapViewControllerBridge

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

    init(_ mapViewControllerBridge: MapViewControllerBridge) {
      self.mapViewControllerBridge = mapViewControllerBridge
    }
  }
}
  1. Реализовать makeCoordinator() в MapViewControllerBridge

Затем реализуйте метод makeCoordinator() в MapViewControllerBridge и верните экземпляр MapViewCoodinator , созданный на предыдущем шаге.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeCoordinator() -> MapViewCoordinator {
    return MapViewCoordinator(self)
  }
}
  1. Установите MapViewCoordinator в качестве делегата представления карты

После создания пользовательского координатора следующим шагом будет установка координатора в качестве делегата для представления карты контроллера представления. Для этого обновите инициализацию контроллера представления в makeUIViewController(context) . Созданный координатор из предыдущего шага будет доступен из объекта Context.

MapViewControllerBridge

struct MapViewControllerBridge: UIViewControllerRepresentable {
  // ...
  func makeUIViewController(context: Context) -> MapViewController {
    let uiViewController = MapViewController()
    uiViewController.map.delegate = context.coordinator
    return uiViewController
  }
  1. Добавьте замыкание в 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)
    }
  }
}
  1. Обновите 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
        })
        // ...
      }
    }
  }
}
  1. Идите вперед и запустите приложение, чтобы увидеть новые изменения!

10. Поздравления

Поздравляем! Вы многое узнали, и, надеюсь, полученные уроки позволят вам создать собственное приложение SwiftUI с помощью Maps SDK для iOS.

Что вы узнали

Что дальше?

  • Maps SDK для iOS – официальная документация по Maps SDK для iOS.
  • Places SDK для iOS — находите местные предприятия и достопримечательности рядом с вами
  • maps-sdk-for-ios-samples — пример кода на GitHub, демонстрирующий все функции Maps SDK для iOS.
  • SwiftUI — официальная документация Apple по SwiftUI.
  • Помогите нам создать наиболее полезный для вас контент, ответив на вопрос ниже:

Какие еще кодлабы вы хотели бы увидеть?

Визуализация данных на картах Подробнее о настройке стиля моих карт Создание 3D-взаимодействий на картах

Нужная вам кодовая лаборатория не указана выше? Запросите его с новым выпуском здесь .