-
Notifications
You must be signed in to change notification settings - Fork 57
/
MapView.swift
95 lines (77 loc) · 2.86 KB
/
MapView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import MapKit
import SwiftUI
#if os(macOS)
public typealias ViewRepresentable = NSViewRepresentable
#elseif os(iOS)
public typealias ViewRepresentable = UIViewRepresentable
#endif
public struct MapView: ViewRepresentable {
let pointsOfInterest: [PointOfInterest]
@Binding var region: CoordinateRegion?
public init(
pointsOfInterest: [PointOfInterest],
region: Binding<CoordinateRegion?>
) {
self.pointsOfInterest = pointsOfInterest
self._region = region
}
#if os(macOS)
public func makeNSView(context: Context) -> MKMapView {
self.makeView(context: context)
}
#elseif os(iOS)
public func makeUIView(context: Context) -> MKMapView {
self.makeView(context: context)
}
#endif
#if os(macOS)
public func updateNSView(_ mapView: MKMapView, context: NSViewRepresentableContext<MapView>) {
self.updateView(mapView: mapView, delegate: context.coordinator)
}
#elseif os(iOS)
public func updateUIView(_ mapView: MKMapView, context: Context) {
self.updateView(mapView: mapView, delegate: context.coordinator)
}
#endif
public func makeCoordinator() -> MapViewCoordinator {
MapViewCoordinator(self)
}
private func makeView(context: Context) -> MKMapView {
let mapView = MKMapView(frame: .zero)
mapView.showsUserLocation = true
return mapView
}
private func updateView(mapView: MKMapView, delegate: MKMapViewDelegate) {
mapView.delegate = delegate
if let region = self.region {
mapView.setRegion(region.asMKCoordinateRegion, animated: true)
}
let currentlyDisplayedPOIs = mapView.annotations.compactMap { $0 as? PointOfInterestAnnotation }
.map { $0.pointOfInterest }
let addedPOIs = Set(pointsOfInterest).subtracting(currentlyDisplayedPOIs)
let removedPOIs = Set(currentlyDisplayedPOIs).subtracting(pointsOfInterest)
let addedAnnotations = addedPOIs.map(PointOfInterestAnnotation.init(pointOfInterest:))
let removedAnnotations = mapView.annotations.compactMap { $0 as? PointOfInterestAnnotation }
.filter { removedPOIs.contains($0.pointOfInterest) }
mapView.removeAnnotations(removedAnnotations)
mapView.addAnnotations(addedAnnotations)
}
}
private class PointOfInterestAnnotation: NSObject, MKAnnotation {
let pointOfInterest: PointOfInterest
init(pointOfInterest: PointOfInterest) {
self.pointOfInterest = pointOfInterest
}
var coordinate: CLLocationCoordinate2D { self.pointOfInterest.coordinate }
var subtitle: String? { self.pointOfInterest.subtitle }
var title: String? { self.pointOfInterest.title }
}
public class MapViewCoordinator: NSObject, MKMapViewDelegate {
var mapView: MapView
init(_ control: MapView) {
self.mapView = control
}
public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
self.mapView.region = CoordinateRegion(coordinateRegion: mapView.region)
}
}