// // 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 ?? []) var polyinesList = [MKPolyline](); for polyline in polylines { let polylineItem : MKPolyline = polyline.polyline polylineItem.associatedLineId = polyline.id polylineItem.associatedLineType = polyline.lineType polylineItem.associatedColor = polyline.color polylineItem.associatedWidth = polyline.width polyinesList.append(polylineItem) } self?.mapView.addOverlays(polyinesList) //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) //移动至多个点的位置,并提供设置padding距离 viewModel.$suitableLocation .receive(on: DispatchQueue.main) .sink{ [weak self] polylines in if let padding = polylines.last?.mapPadding { if let atMapPoint : [CLLocationCoordinate2D] = polylines.last?.points { self?.mapView.moveToSuitableLocation(points: atMapPoint, padding: padding) } } } .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 { guard let polyline = overlay as? MKPolyline else { return MKOverlayRenderer(overlay: overlay) } let renderer = ArrowPolylineRenderer(polyline: polyline) renderer.lineWidth = 6 //rgba(123, 125, 255, 1) renderer.strokeColor = UIColor(red: 0.27, green: 0.46, blue: 1, alpha: 1)//UIColor.init(hex: "#4476FF");//UIColor(red: 123 / 255, green: 125 / 255, blue: 255 / 255, alpha: 1) renderer.lineCap = .round renderer.lineJoin = .round // 设置箭头样式 renderer.arrowColor = UIColor.white // 箭头颜色 renderer.arrowSize = 12 // 增大箭头大小 renderer.arrowSpacing = 40 // 减小箭头间距 renderer.borderWidth = 1 renderer.borderColor = UIColor(red: 0.35, green: 0.36, blue: 0.99, alpha: 1)//UIColor.hex(0x5A5DFD) //normal error selected color if polyline.associatedLineType == "normal" { renderer.strokeColor = UIColor(red: 0.27, green: 0.46, blue: 1, alpha: 1) } else if polyline.associatedLineType == "error" { renderer.strokeColor = UIColor(red: 1, green: 0.43, blue: 0.43, alpha: 1) } else if polyline.associatedLineType == "selected" { renderer.strokeColor = UIColor(red: 0.08, green: 0.8, blue: 0.63, alpha: 1) } return renderer } }