SwiftUI:保存 MapKit 注释数据以传递给另一个视图
SwiftUI: Saving MapKit Annotation Data to Pass To Another View
我正在努力保存 MapKit 注释数据(例如名称、地址、坐标等)并将其传回具有 link 到地图视图的视图。我可以 select 使用 didSelect 注释并将我正在寻找的数据打印到终端,但是我不知道如何将它传回。我一直在尝试使用 ObservedObject 但我收到一条错误消息:属性 'self.contentData' not initialized at implicitly generated super.init call.
import SwiftUI
import MapKit
//MARK:- COORDINATOR
class Coordinator: NSObject, MKMapViewDelegate {
//@ObservedObject var contentData: ContentData // << deleted based on answer
var control: MapUIView
var contentData: ContentData // << added based on answer
init(_ control: MapUIView) {
self.control = control
self.contentData = control.contentData // << added based on answer
}
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
if let annotationView = views.first {
if let annotation = annotationView.annotation {
if annotation is MKUserLocation {
let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 8000, longitudinalMeters: 8000)
mapView.setRegion(region, animated: true)
}
}
}
}
func selectAnnotation(_ annotation: MKAnnotation, animated: Bool) {
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if mapView.selectedAnnotations.count > 0 {
if let selectedPinName = mapView.selectedAnnotations[0].title {
print("\(selectedPinName!)")
}
}
let region = MKCoordinateRegion(center: view.annotation!.coordinate, span: mapView.region.span)
mapView.setRegion(region, animated: true)
contentData.selectedLocationName = (mapView.selectedAnnotations[0].title as? String)!
}
}
//MARK:- LOCATION MANAGER
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
@Published var location: CLLocation? = nil
override init() {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLHeadingFilterNone
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print(status)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
return
}
self.location = location
}
}
//MARK:- LANDMARK ANNOTATION
final class LandmarkAnnotation: NSObject, MKAnnotation {
let title: String?
let subtitle: String?
let coordinate: CLLocationCoordinate2D
init(landmark: Landmark) {
self.title = landmark.name
self.subtitle = landmark.title
self.coordinate = landmark.coordinate
}
}
//MARK:- LANDMARK
struct Landmark {
let placemark: MKPlacemark
var id: UUID {
return UUID()
}
var name: String {
self.placemark.name ?? ""
}
var title: String {
self.placemark.title ?? ""
}
var coordinate: CLLocationCoordinate2D {
self.placemark.coordinate
}
}
//MARK:- VIEW
struct MapView: View {
@ObservedObject var locationManager = LocationManager()
@State private var landmarks: [Landmark] = [Landmark]()
@State private var search: String = ""
@State private var tapped: Bool = false
@State private var showCancelButton: Bool = false
@ObservedObject var contentData: ContentData
private func getNearByLandmarks() {
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = search
let search = MKLocalSearch(request: request)
search.start { (response, error) in
if let response = response {
let mapItems = response.mapItems
self.landmarks = mapItems.map {
Landmark(placemark: [=10=].placemark)
}
}
}
}
var body: some View {
ZStack(alignment: .top) {
MapUIView(contentData: contentData, landmarks: landmarks)
HStack {
HStack {
Image(systemName: "magnifyingglass")
TextField("Search", text: $search, onEditingChanged: { _ in
self.showCancelButton = true
self.getNearByLandmarks()
}).foregroundColor(.primary)
Button(action: {
self.search = ""
}) {
Image(systemName: "xmark.circle.fill").opacity(search == "" ? 0 : 1)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.foregroundColor(.secondary)
.background(Color(.secondarySystemBackground))
.cornerRadius(10.0)
}
.padding(EdgeInsets(top: 10, leading: 0, bottom: 1, trailing: 0))
.padding(.horizontal)
}
}
}
//MARK:- MAPUIVIEW
struct MapUIView: UIViewRepresentable {
@ObservedObject var contentData: ContentData
let landmarks: [Landmark]
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.showsUserLocation = true
map.delegate = context.coordinator
return map
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapUIView>) {
updateAnnotations(from: uiView)
}
func updateAnnotations(from mapView: MKMapView) {
mapView.removeAnnotations(mapView.annotations)
let annotations = self.landmarks.map(LandmarkAnnotation.init)
mapView.addAnnotations(annotations)
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView(contentData: ContentData())
}
}
调用地图视图:
NavigationLink(destination: MapView(contentData: contentData).edgesIgnoringSafeArea(.bottom), tag: 1, selection: $tag)
非常感谢任何帮助。非常感谢。
编辑 ----------------------
在实施建议的更改之前和之后添加了注释行为的屏幕截图,以允许使用 ObservableObject 将注释数据传递回之前的 swiftui 视图。
这里是固定部分
class Coordinator: NSObject, MKMapViewDelegate {
var contentData: ContentData // << here !!
var control: MapUIView
init(_ control: MapUIView) {
self.control = control
self.contentData = control.contentData // << here !!
}
// ... other code
}
注意:@ObservedObject
旨在用于 SwiftUI 视图,在 class
中不需要
我正在努力保存 MapKit 注释数据(例如名称、地址、坐标等)并将其传回具有 link 到地图视图的视图。我可以 select 使用 didSelect 注释并将我正在寻找的数据打印到终端,但是我不知道如何将它传回。我一直在尝试使用 ObservedObject 但我收到一条错误消息:属性 'self.contentData' not initialized at implicitly generated super.init call.
import SwiftUI
import MapKit
//MARK:- COORDINATOR
class Coordinator: NSObject, MKMapViewDelegate {
//@ObservedObject var contentData: ContentData // << deleted based on answer
var control: MapUIView
var contentData: ContentData // << added based on answer
init(_ control: MapUIView) {
self.control = control
self.contentData = control.contentData // << added based on answer
}
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
if let annotationView = views.first {
if let annotation = annotationView.annotation {
if annotation is MKUserLocation {
let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 8000, longitudinalMeters: 8000)
mapView.setRegion(region, animated: true)
}
}
}
}
func selectAnnotation(_ annotation: MKAnnotation, animated: Bool) {
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if mapView.selectedAnnotations.count > 0 {
if let selectedPinName = mapView.selectedAnnotations[0].title {
print("\(selectedPinName!)")
}
}
let region = MKCoordinateRegion(center: view.annotation!.coordinate, span: mapView.region.span)
mapView.setRegion(region, animated: true)
contentData.selectedLocationName = (mapView.selectedAnnotations[0].title as? String)!
}
}
//MARK:- LOCATION MANAGER
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
@Published var location: CLLocation? = nil
override init() {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLHeadingFilterNone
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print(status)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
return
}
self.location = location
}
}
//MARK:- LANDMARK ANNOTATION
final class LandmarkAnnotation: NSObject, MKAnnotation {
let title: String?
let subtitle: String?
let coordinate: CLLocationCoordinate2D
init(landmark: Landmark) {
self.title = landmark.name
self.subtitle = landmark.title
self.coordinate = landmark.coordinate
}
}
//MARK:- LANDMARK
struct Landmark {
let placemark: MKPlacemark
var id: UUID {
return UUID()
}
var name: String {
self.placemark.name ?? ""
}
var title: String {
self.placemark.title ?? ""
}
var coordinate: CLLocationCoordinate2D {
self.placemark.coordinate
}
}
//MARK:- VIEW
struct MapView: View {
@ObservedObject var locationManager = LocationManager()
@State private var landmarks: [Landmark] = [Landmark]()
@State private var search: String = ""
@State private var tapped: Bool = false
@State private var showCancelButton: Bool = false
@ObservedObject var contentData: ContentData
private func getNearByLandmarks() {
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = search
let search = MKLocalSearch(request: request)
search.start { (response, error) in
if let response = response {
let mapItems = response.mapItems
self.landmarks = mapItems.map {
Landmark(placemark: [=10=].placemark)
}
}
}
}
var body: some View {
ZStack(alignment: .top) {
MapUIView(contentData: contentData, landmarks: landmarks)
HStack {
HStack {
Image(systemName: "magnifyingglass")
TextField("Search", text: $search, onEditingChanged: { _ in
self.showCancelButton = true
self.getNearByLandmarks()
}).foregroundColor(.primary)
Button(action: {
self.search = ""
}) {
Image(systemName: "xmark.circle.fill").opacity(search == "" ? 0 : 1)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.foregroundColor(.secondary)
.background(Color(.secondarySystemBackground))
.cornerRadius(10.0)
}
.padding(EdgeInsets(top: 10, leading: 0, bottom: 1, trailing: 0))
.padding(.horizontal)
}
}
}
//MARK:- MAPUIVIEW
struct MapUIView: UIViewRepresentable {
@ObservedObject var contentData: ContentData
let landmarks: [Landmark]
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.showsUserLocation = true
map.delegate = context.coordinator
return map
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapUIView>) {
updateAnnotations(from: uiView)
}
func updateAnnotations(from mapView: MKMapView) {
mapView.removeAnnotations(mapView.annotations)
let annotations = self.landmarks.map(LandmarkAnnotation.init)
mapView.addAnnotations(annotations)
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView(contentData: ContentData())
}
}
调用地图视图:
NavigationLink(destination: MapView(contentData: contentData).edgesIgnoringSafeArea(.bottom), tag: 1, selection: $tag)
非常感谢任何帮助。非常感谢。
编辑 ----------------------
在实施建议的更改之前和之后添加了注释行为的屏幕截图,以允许使用 ObservableObject 将注释数据传递回之前的 swiftui 视图。
这里是固定部分
class Coordinator: NSObject, MKMapViewDelegate {
var contentData: ContentData // << here !!
var control: MapUIView
init(_ control: MapUIView) {
self.control = control
self.contentData = control.contentData // << here !!
}
// ... other code
}
注意:@ObservedObject
旨在用于 SwiftUI 视图,在 class