// // 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() init(viewModel: MapViewModel) { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) mapView.showsUserLocation = false } 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 = false mapView.mapType = .mutedStandard } private func bindViewModel() { viewModel.$currentRegion .compactMap { $0 } .receive(on: DispatchQueue.main) .sink { [weak self] region in self?.mapView.setRegion(region, animated: true) } .store(in: &cancellables) viewModel.$markers .receive(on: DispatchQueue.main) .sink { [weak self] markers in self?.mapView.removeAnnotations(self?.mapView.annotations ?? []) UIView.animate(withDuration: 0.3) { self?.mapView.addAnnotations(markers) } } .store(in: &cancellables) viewModel.$polylines .receive(on: DispatchQueue.main) .sink { [weak self] polylines in self?.mapView.removeOverlays(self?.mapView.overlays ?? []) self?.mapView.addOverlays(polylines.map({ $0.polyline })) if let padding = polylines.last?.mapPadding { self?.mapView.fitsAllPoints( points: polylines.last?.points.compactMap({ MKMapPoint($0) }) ?? [], padding: padding.padding, animated: true ) } } .store(in: &cancellables) } } extension MapViewController: MKMapViewDelegate { func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { guard let marker = annotation as? ATMapMarker else { return nil } let annotationView = (mapView.dequeueReusableAnnotationView(withIdentifier: MapAnnotationView.identifier) as? MapAnnotationView) ?? MapAnnotationView(annotation: marker, reuseIdentifier: MapAnnotationView.identifier) annotationView.marker = marker annotationView.prepareForDisplay() 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 = 6 //rgba(123, 125, 255, 1) renderer.strokeColor = UIColor(red: 123 / 255, green: 125 / 255, blue: 255 / 255, alpha: 1) renderer.lineCap = .round renderer.lineJoin = .round return renderer } }