SwiftUI Mapkit: Как выбрать элементы Mapkit и собственные маркеры

Вопрос или проблема

У меня есть карта с яблоками предопределенными элементами, такими как “пляжи”. И я установил несколько собственных маркеров (которые показывают “мои пляжи”).

Маркеры установлены следующим образом:

private let myMarkers: [(id: Int, name: String, coordinate: CLLocationCoordinate2D)] = [
            (1, "Apple Developer Academy", CLLocationCoordinate2D(latitude: 40.836639, longitude: 14.306602)),
            (2, "Ресторан", CLLocationCoordinate2D(latitude: 40.834890, longitude: 14.304400)),
            (3, "Кофейня", CLLocationCoordinate2D(latitude: 40.836901, longitude: 14.302562)),
            (4, "Пляж", CLLocationCoordinate2D(latitude: 54.41621, longitude: 10.18242))

        ]

Когда я инициализирую карту, я определяю “позицию” и “выбор” (как указано ниже).

Теперь:
Если у меня только элементы карты Apple, я объявляю:

@State private var mySelectedAppleItem: MKMapItem?

и инициализирую:
Map(position: $position, selection: $mySelected**AppleItem**) {//Тип: MKMapItem

И:

Если у меня только “Элементы”-Карт (которые, если я вижу это правильно, не являются MKMapItems, а “только” отмеченными местами), я объявляю:

@State private var mySelectedTag: Int?

и инициализирую:
Map(position: $position, selection: $mySelected**Tag**) {//Тип: Int

Итак:
Когда я выбираю выбор Apple (selection: $mySelectedAppleItem), я могу легко выбрать элементы Apple, но мои собственные маркеры, хотя и отмечены тегом, НЕ выбираются. А когда я выбираю свой выбор (selection: $mySelectedTag), я могу выбрать только свои отмеченные маркеры.

Вот мой вопрос: Есть ли способ, чтобы я мог выбирать ОБА? Например, через расширение MapItem (могу ли я объявить свои “элементы” как “элементы Mapkit”?)

Большое спасибо!

Я много искал, но не смог найти ни одной статьи на эту тему.

Ответ или решение

Вам нужно создать возможность выбора как MKMapItem (предопределенные элементы карты Apple), так и собственных маркеров (например, "мои пляжи") в приложении на SwiftUI, использующем MapKit. К сожалению, в SwiftUI Map, которое по умолчанию предоставляет селектор, нельзя напрямую смешивать разные типы выбора (MKMapItem и Int). Однако, вы можете обойти это ограничение, создав вместе с отдельными элементами карту с кастомизированными маркерами.

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

Шаги для реализации решения

  1. Создайте объединяющую структуру: Создайте тип данных, который будет представлять как MKMapItem, так и ваши собственные маркеры.
import SwiftUI
import MapKit

// Объединяющий тип для выбора как MKMapItem, так и ваших собственных маркеров
enum MapItemType {
    case appleItem(MKMapItem)
    case customMarker((id: Int, name: String, coordinate: CLLocationCoordinate2D))
}

struct MapAnnotationView: View {
    var item: MapItemType

    var body: some View {
        switch item {
        case .appleItem(let mapItem):
            Text(mapItem.name ?? "Unknown")
                .padding(5)
                .background(Color.blue)
                .cornerRadius(5)
        case .customMarker(let marker):
            Text(marker.name)
                .padding(5)
                .background(Color.green)
                .cornerRadius(5)
        }
    }
}
  1. Передайте данные в карту: Используйте Map из SwiftUI с общим типом выбора.
@State private var selectedMapItem: MapItemType? = nil

var body: some View {
    Map(position: $position, selection: $selectedMapItem) {
        ForEach(myMarkers, id: \.id) { marker in
            MapAnnotation(coordinate: marker.coordinate, anchorPoint: CGPoint(x: 0.5, y: 0.5)) {
                MapAnnotationView(item: .customMarker(marker))
                    .onTapGesture {
                        selectedMapItem = .customMarker(marker)
                    }
            }
        }

        // Добавление Apple MKMapItems
        ForEach(appleMapItems, id: \.self) { mapItem in
            MapAnnotation(coordinate: mapItem.placemark.coordinate, anchorPoint: CGPoint(x: 0.5, y: 0.5)) {
                MapAnnotationView(item: .appleItem(mapItem))
                    .onTapGesture {
                        selectedMapItem = .appleItem(mapItem)
                    }
            }
        }
    }
}
  1. Отображение выбранного элемента: Обработайте отображение информации о выбранном элементе.
if let selectedItem = selectedMapItem {
    switch selectedItem {
    case .appleItem(let mapItem):
        Text("Выбранный Apple элемент: \(mapItem.name ?? "Неизвестно")")
    case .customMarker(let marker):
        Text("Выбранный собственный маркер: \(marker.name)")
    }
}

Заключение

Этот подход позволяет вам комбинировать как стандартные элементы карты от Apple, так и собственные маркеры, используя единый тип для выбора. Вы можете легко адаптировать логику показов и действий в зависимости от выбранного элемента. Надеюсь, этот ответ поможет вам реализовать необходимую функциональность в вашем приложении.

Оцените материал
Добавить комментарий

Капча загружается...