点击地图标记时的 SwiftUI .popover

问题描述 投票:0回答:1

我正在尝试让

.popover
与“地图”>“标记”一起使用,但似乎无法实现。我尝试通过获取坐标并基于此呈现
.popover
来解决此问题,但我无法让它工作。简单地将
.popover
修饰符放在
Image("Logo")
上似乎也不起作用。这是我当前的代码

import SwiftUI
import MapKit

struct MapView: View {
    @State private var region: MKCoordinateRegion
    var libraries: [Library]
    @State private var selectedLibrary: Library?

    init(libraries: [Library]) {
        if let firstLibrary = libraries.first {
            _region = State(initialValue: MKCoordinateRegion(
                center: firstLibrary.coordinate,
                span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
            ))
        } else {
            _region = State(initialValue: MKCoordinateRegion())
        }
        self.libraries = libraries
    }

    var body: some View {
        ZStack {
            Map {
                ForEach(libraries) { library in
                    Marker(coordinate: library.coordinate) {
                        Image("Logo")
                            .resizable()
                            .scaledToFit()
                            .frame(width: 30, height: 30)
                    }
                    .tint(.purple)
                }
            }
            .edgesIgnoringSafeArea(.all)

            GeometryReader { geometry in
                ForEach(libraries) { library in
                    Button(action: {
                        self.selectedLibrary = library
                    }, label: {
                        Color.clear
                    })
                    .frame(width: 44, height: 44)
                    .position(self.coordinateToPoint(library.coordinate, in: geometry))
                    .popover(isPresented: Binding<Bool>(
                        get: { self.selectedLibrary == library },
                        set: { if !$0 { self.selectedLibrary = nil } }
                    )) {
                        Text("Annotation details here")
                            .padding()
                    }
                }
            }
        }
    }

    private func coordinateToPoint(_ coordinate: CLLocationCoordinate2D, in geometry: GeometryProxy) -> CGPoint {
        let mapWidthDegrees = region.span.longitudeDelta
        let mapHeightDegrees = region.span.latitudeDelta

        let widthPerDegree = geometry.size.width / mapWidthDegrees
        let heightPerDegree = geometry.size.height / mapHeightDegrees

        let xCoordinate = (coordinate.longitude - region.center.longitude + mapWidthDegrees / 2) * widthPerDegree
        let yCoordinate = (region.center.latitude - coordinate.latitude + mapHeightDegrees / 2) * heightPerDegree

        return CGPoint(x: xCoordinate, y: yCoordinate)
    }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView(libraries: LibraryData.libraries)
    }
}

这是我的图书馆数据和图书馆供参考

import CoreLocation

struct Library: Identifiable, Equatable {
    let id = UUID()
    let coordinate: CLLocationCoordinate2D

    static func == (lhs: Library, rhs: Library) -> Bool {
        lhs.id == rhs.id &&
        lhs.coordinate.latitude == rhs.coordinate.latitude &&
        lhs.coordinate.longitude == rhs.coordinate.longitude
    }
}

struct LibraryData {
    static let libraries = [
        Library(coordinate: CLLocationCoordinate2D(latitude: 37.33182, longitude: -122.03118)),
        Library(coordinate: CLLocationCoordinate2D(latitude: 37.34182, longitude: -122.03218)),
        Library(coordinate: CLLocationCoordinate2D(latitude: 37.34182, longitude: -122.04118))
    ]
}

当我点击地图内的标记时,什么也没有发生。任何帮助,将不胜感激。预先感谢。

swift swiftui mapkit
1个回答
0
投票

您可以尝试使用不同的方法,使用

Annotation
而不是
Marker
.popover()

示例代码展示了如何点击任意

Annotation
并弹出自定义视图。

struct ContentView: View {
    var body: some View {
        MapView(libraries: LibraryData.libraries)
    }
}

struct MapView: View {
    @State private var region: MKCoordinateRegion
    var libraries: [Library]
    @State private var selectedLibrary: Library?
    
    // for testing
    @State private var cameraPosition: MapCameraPosition = .camera(
        MapCamera(centerCoordinate: CLLocationCoordinate2D(latitude: 37.33182, longitude: -122.03118), distance: 8000.0, heading: 0, pitch: 0)
    )
    
    init(libraries: [Library]) {
        if let firstLibrary = libraries.first {
            _region = State(initialValue: MKCoordinateRegion(
                center: firstLibrary.coordinate,
                span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
            ))
        } else {
            _region = State(initialValue: MKCoordinateRegion())
        }
        self.libraries = libraries
    }
    
    @State private var toggler = false  // <-- here to toggle the popup view
    
    var body: some View {
        Map(position: $cameraPosition) {
            ForEach(libraries) { library in
                Annotation("", coordinate: library.coordinate) {
                    ZStack {
                        Image(systemName: "mappin.circle.fill")
                            .resizable()
                            .scaledToFit()
                            .frame(width: 30, height: 30)
                            .onTapGesture {
                                selectedLibrary = library
                                toggler.toggle()
                            }
                            .foregroundStyle(.white, .purple)
                        if selectedLibrary == library && toggler {
                            PopupView(library: selectedLibrary).offset(x: 0, y: -30)
                        } else {
                            EmptyView()
                        }
                    }
                }
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

// just for testing, adjust the looks as needed
struct PopupView: View {
    @State var library: Library?
    
    var body: some View {
        if let lib = library {
            Button("Poping: \(String(lib.id.uuidString.prefix(4)))") { }
            .buttonStyle(.bordered)
            .foregroundStyle(.purple)
        } else {
            Text("no data")
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.