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

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

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

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

Предпосылки

  • Базовые знания Swift
  • Базовые знания SwiftUI

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

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

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

2. Настройте

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

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

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

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

  1. Включите API и SDK платформы Google Карт, необходимые для этой лабораторной работы, в Google Cloud Marketplace . Для этого следуйте инструкциям в этом видео или в этой документации .
  2. Сгенерируйте ключ API на странице «Учётные данные» в Cloud Console. Вы можете следовать инструкциям в этом видео или в этой документации . Для всех запросов к платформе Google Карт требуется ключ 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 по состоянию и потоку данных .

Объедините UIKit и SwiftUI с помощью UIViewRepresentable или UIViewControllerRepresentable

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

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

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

add-a-map-screenshot@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 State , что указывает на то, что оно должно управляться 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 .

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 с помощью @Binding

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

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

MapViewControllerBridge

struct MapViewControllerBridge: : UIViewControllerRepresentable {
  @Binding var markers: [GMSMarker]
  // ...
}
  1. В 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 }
  }
}
  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. Анимация в выбранном городе

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

animate-city@2x.png

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

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

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

У ContentView есть свойство State под названием selectedMarker , которое инициализируется значением nil и обновляется при выборе города в списке. Это обрабатывается функцией buttonAction представления CitiesList в 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 .

После объявления новой привязки необходимо обновить функцию updateUIViewController_, context) объекта MapViewControllerBridge , чтобы карта анимировалась в соответствии с выбранным маркером. Для этого скопируйте следующий код:

struct MapViewControllerBridge: UIViewControllerRepresentable {
  @Binding var selectedMarker: GMSMarker?

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
    markers.forEach { $0.map = uiViewController.map }
    selectedMarker?.map = uiViewController.map
    animateToSelectedMarker(viewController: uiViewController)
  }

  private func animateToSelectedMarker(viewController: MapViewController) {
    guard let selectedMarker = selectedMarker else {
      return
    }

    let map = viewController.map
    if map.selectedMarker != selectedMarker {
      map.selectedMarker = selectedMarker
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        map.animate(toZoom: kGMSMinZoomLevel)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
          map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
            map.animate(toZoom: 12)
          })
        }
      }
    }
  }
}

Функция animateToSelectedMarker(viewController) выполнит последовательность анимаций карты с помощью функции animate(with) GMSMapView .

  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 , где 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 , чтобы событие перемещения камеры могло распространяться вверх

Поскольку цель — обновлять представление в соответствии с перемещениями камеры, объявите новое свойство замыкания mapViewWillMove , принимающее логическое значение, в MapViewControllerBridge и вызовите это замыкание в методе делегата 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.

Что вы узнали

  • Различия между SwiftUI и UIKit
  • Как объединить SwiftUI и UIKit с помощью UIViewControllerRepresentable
  • Как внести изменения в вид карты с помощью State and Binding
  • Как отправить событие из представления карты в SwiftUI с помощью координатора

Что дальше?

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

Какие еще практические занятия вы хотели бы увидеть?

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

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