You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI Map中实现不同类型Marker的选中功能

解决SwiftUI Map同时支持两种类型Marker选中的问题

问题背景

现有DestinationMapView中,Place和Accommodation是两个字段不同但都包含经纬度属性的类,当前Map的selection只能绑定单一类型(要么$selectedPlace要么$selectedAccommodation),无法同时实现两种Marker的选中交互。

解决方案

核心思路是用枚举统一两种可选类型,让Map的selection绑定该枚举,从而兼容两种Marker的选中逻辑,具体步骤如下:

  • 定义枚举类型:创建MapSelection枚举,用关联值分别包裹Place和Accommodation,同时让枚举遵循Identifiable协议(满足sheet(item:)的类型要求)。
  • 替换选中状态变量:将原有的两个独立选中变量,替换为一个类型为MapSelection?的@State变量。
  • 修改Marker标签:把两个ForEach中的.tag改为对应的枚举关联值。
  • 更新Map绑定:将Map的selection参数改为绑定新的枚举类型变量。
  • 统一Sheet展示:通过switch语句根据枚举类型,展示对应选中内容。

修改后的完整代码

import SwiftUI
import MapKit

// 定义统一的选中类型枚举
enum MapSelection: Identifiable {
    case place(Place)
    case accommodation(Accommodation)
    
    var id: String {
        switch self {
        case .place(let place):
            return place.id // 假设Place遵循Identifiable,具备id属性
        case .accommodation(let accommodation):
            return accommodation.id // 假设Accommodation遵循Identifiable,具备id属性
        }
    }
}

struct DestinationMapView: View {
    var destination: Destination
    @State private var cameraPosition: MapCameraPosition = .automatic
    @State private var selectedItem: MapSelection? // 统一的选中状态变量
    
    var body: some View {
        Map(position: $cameraPosition, selection: $selectedItem) {
            ForEach(destination.accommodations ?? []) { accommodation in
                Group {
                    if let lat = accommodation.latitude, let lon = accommodation.longitude {
                        Marker(accommodation.name, systemImage: "bed.double.fill", coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon))
                            .tint(.blue)
                    }
                }
                .tag(MapSelection.accommodation(accommodation)) // 标记为枚举类型
            }
            ForEach(destination.places ?? []) { place in
                Group {
                    if let lat = place.latitude, let lon = place.longitude {
                        Marker(place.name, systemImage: place.placeType.systemImage, coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon))
                    }
                }
                .tag(MapSelection.place(place)) // 标记为枚举类型
            }
        }
        .sheet(item: $selectedItem) { selection in
            // 根据选中类型展示对应内容
            switch selection {
            case .place(let selectedPlace):
                Text("Selected Place: \(selectedPlace.name)")
                    .presentationDetents([.medium, .large])
                    .presentationDragIndicator(.visible)
            case .accommodation(let selectedAccommodation):
                Text("Selected Accommodation: \(selectedAccommodation.name)")
                    .presentationDetents([.medium, .large])
                    .presentationDragIndicator(.visible)
            }
        }
        .onAppear {
            if let coordinateRegion = destination.coordinateRegion {
                cameraPosition = MapCameraPosition.region(coordinateRegion)
            }
        }
    }
}

注意事项

  • 确保Place和Accommodation已遵循Identifiable协议,若原本未实现,需为两个类添加唯一标识的id属性。
  • 若id类型不是String,可调整枚举id的返回类型(比如改为AnyHashable),只要保证每个枚举实例的id唯一即可。

内容的提问来源于stack exchange,提问作者Dogahe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 18:21:03