|
|
@@ -0,0 +1,108 @@
|
|
|
+//
|
|
|
+// MapViewController.swift
|
|
|
+// Runner
|
|
|
+//
|
|
|
+// Created by Groot on 2025/5/7.
|
|
|
+//
|
|
|
+
|
|
|
+import UIKit
|
|
|
+import MapKit
|
|
|
+import Combine
|
|
|
+
|
|
|
+class MapViewController: UIViewController {
|
|
|
+
|
|
|
+ required init?(coder: NSCoder) {
|
|
|
+ fatalError("init(coder:) has not been implemented")
|
|
|
+ }
|
|
|
+
|
|
|
+ let viewModel: MapViewModel
|
|
|
+ let mapView = MKMapView()
|
|
|
+ private var cancellables = Set<AnyCancellable>()
|
|
|
+
|
|
|
+ init(viewModel: MapViewModel) {
|
|
|
+ self.viewModel = viewModel
|
|
|
+ super.init(nibName: nil, bundle: nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ override func viewDidLoad() {
|
|
|
+ super.viewDidLoad()
|
|
|
+ setupView()
|
|
|
+ setupMap()
|
|
|
+ bindViewModel()
|
|
|
+ }
|
|
|
+
|
|
|
+ private func setupView() {
|
|
|
+ mapView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
+ view.addSubview(mapView)
|
|
|
+ NSLayoutConstraint.activate([
|
|
|
+ mapView.topAnchor.constraint(equalTo: view.topAnchor),
|
|
|
+ mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
|
|
+ mapView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
|
+ mapView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
|
|
+ ])
|
|
|
+ }
|
|
|
+
|
|
|
+ private func setupMap() {
|
|
|
+ mapView.delegate = self
|
|
|
+ mapView.showsUserLocation = true
|
|
|
+ mapView.setUserTrackingMode(.follow, animated: true)
|
|
|
+ }
|
|
|
+
|
|
|
+ private func bindViewModel() {
|
|
|
+ // 监听区域变化并更新地图
|
|
|
+ viewModel.$currentRegion
|
|
|
+ .compactMap { $0 }
|
|
|
+ .sink { [weak self] region in
|
|
|
+ self?.mapView.setRegion(region, animated: true)
|
|
|
+ }
|
|
|
+ .store(in: &cancellables)
|
|
|
+
|
|
|
+ viewModel.$markers
|
|
|
+ .sink { [weak self] markers in
|
|
|
+ self?.mapView.removeAnnotations(self?.mapView.annotations ?? [])
|
|
|
+ self?.mapView.addAnnotations(markers)
|
|
|
+ }
|
|
|
+ .store(in: &cancellables)
|
|
|
+
|
|
|
+ viewModel.$polylines
|
|
|
+ .sink { [weak self] polylines in
|
|
|
+ self?.mapView.removeOverlays(self?.mapView.overlays ?? [])
|
|
|
+ self?.mapView.addOverlays(polylines.map({ $0.polyline }))
|
|
|
+ }
|
|
|
+ .store(in: &cancellables)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension MapViewController: MKMapViewDelegate {
|
|
|
+ func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
|
|
|
+ var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MapAnnotationView.identifier) as? MapAnnotationView
|
|
|
+
|
|
|
+ // 如果没有可复用的视图,创建新的自定义标注视图
|
|
|
+ if annotationView == nil {
|
|
|
+ annotationView = MapAnnotationView(annotation: annotation, reuseIdentifier: MapAnnotationView.identifier)
|
|
|
+ } else {
|
|
|
+ // 更新现有视图的标注
|
|
|
+ annotationView?.annotation = annotation
|
|
|
+ }
|
|
|
+
|
|
|
+ return annotationView
|
|
|
+ }
|
|
|
+
|
|
|
+ func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
|
|
|
+ guard var marker = view.annotation as? ATMapMarker else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ viewModel.handleMarkerTap(marker: &marker)
|
|
|
+ }
|
|
|
+
|
|
|
+ func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
|
|
+ let renderer = MKPolylineRenderer(overlay: overlay)
|
|
|
+ renderer.lineWidth = 5
|
|
|
+ renderer.strokeColor = .blue
|
|
|
+ renderer.alpha = 1
|
|
|
+ renderer.lineCap = .round
|
|
|
+ renderer.lineJoin = .round
|
|
|
+ return renderer
|
|
|
+ }
|
|
|
+}
|