//
|
// YYMapViewController.swift
|
// OKProject
|
//
|
// Created by alvin_y on 2020/9/17.
|
// Copyright © 2020 yangwang. All rights reserved.
|
//
|
|
import UIKit
|
import RxSwift
|
import RxCocoa
|
import AMapSearchKit
|
|
class YYMapViewModel: YYViewModel {
|
|
|
|
|
}
|
|
class YYMapViewController: YYViewController {
|
|
/// 地图
|
let mapView = MAMapView()
|
|
/// 屏幕中心标记
|
var centerAnnonation: MAPointAnnotation?
|
|
/// 起点
|
var startAnnotation: MAPointAnnotation?
|
|
/// 目的地
|
var destinationAnnotation: MAPointAnnotation?
|
|
/// 起点到终点的线
|
var startToDestinationLine: MAPolyline?
|
|
/// 等待应答标记
|
var waitingForResponseAnnotation: YYTitleAnnotation?
|
|
/// 等待应答提示
|
var waitingForResponseAnnotationView: YYTitleAnnotationView?
|
|
/// 司机位置
|
var driverAnnotation: MAAnimatedAnnotation?
|
|
var isCarpool = false //拼车
|
|
/// 用户位置
|
private var userLocationView: LocationAnnotationView?
|
|
lazy var label_waitingTitle: UILabel = {
|
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 120, height: 30))
|
label.backgroundColor = .red
|
return label
|
}()
|
|
/// insets 嵌入边界
|
var edgePadding: UIEdgeInsets = .zero
|
|
let search = AMapSearchAPI()!
|
|
/// 区域改变完成回调
|
let mapDidMoveByUserSubject = PublishSubject<Bool>()
|
|
let viewModel = YYMapViewModel()
|
|
override func viewDidLoad() {
|
super.viewDidLoad()
|
|
search.delegate = self
|
}
|
|
|
override func setupViews() {
|
super.setupViews()
|
mapView.userTrackingMode = .follow
|
mapView.zoomLevel = 17
|
mapView.showsCompass = false
|
mapView.showsScale = false
|
mapView.isRotateEnabled = false
|
mapView.isRotateCameraEnabled = false
|
mapView.delegate = self
|
mapView.mapType = .standard
|
mapView.showsUserLocation = true // YES 为打开定位,NO为关闭定位
|
mapView.pausesLocationUpdatesAutomatically = false
|
|
view.addSubview(mapView)
|
|
}
|
|
override func defineLayouts() {
|
super.defineLayouts()
|
|
mapView.snp.makeConstraints { (make) in
|
make.edges.equalTo(view)
|
}
|
}
|
|
override func bindRx() {
|
super.bindRx()
|
|
// Observable.combineLatest(viewModel.startAnnotation, viewModel.destinationAnnotation)
|
// .subscribe(onNext: { (startAnnotation, destinationAnnotation) in
|
// self.mapView.removeAnnotations(self.mapView.annotations)
|
// self.mapView.removeOverlays(self.mapView.overlays)
|
//
|
// if let startAnnotation = startAnnotation, destinationAnnotation == nil {
|
// let edgePadding = self.viewModel.edgePadding.value ?? .zero
|
// self.mapView.addAnnotation(startAnnotation)
|
// self.mapView.showAnnotations([startAnnotation], edgePadding: edgePadding, animated: false)
|
// }
|
//
|
// else if let startAnnotation = startAnnotation, let destinationAnnotation = destinationAnnotation {
|
// let edgePadding = self.viewModel.edgePadding.value ?? .zero
|
// self.mapView.addAnnotations([startAnnotation, destinationAnnotation])
|
// self.showPolyline(startCoorninate: startAnnotation.coordinate, endCoordinate: destinationAnnotation.coordinate)
|
// self.mapView.showAnnotations([startAnnotation, destinationAnnotation], edgePadding: edgePadding, animated: false)
|
// }
|
//
|
// })
|
// .disposed(by: disposeBag)
|
}
|
|
}
|
extension YYMapViewController {
|
|
/// 显示屏幕中心点标记
|
func showCenterAnnotation() {
|
|
cleanCenterAnnotation()
|
|
var point = mapView.center
|
point.y -= 15
|
|
let annotation = MAPointAnnotation()
|
annotation.isLockedToScreen = true
|
annotation.lockedScreenPoint = point
|
annotation.title = "固定点"
|
mapView.addAnnotation(annotation)
|
self.centerAnnonation = annotation
|
|
}
|
|
/// 设置地图中心点
|
///
|
/// - Parameter coordinate: 坐标
|
func setCenter(coordinate: CLLocationCoordinate2D) {
|
mapView.setCenter(coordinate, animated: false)
|
}
|
|
/// 添加起点和终点的标记
|
///
|
/// - Parameters:
|
/// - startLocation: 起点坐标
|
/// - destinationLocation: 终点坐标
|
/// - edgePadding: 显示边界
|
func setAnnotations(startLocation: CLLocationCoordinate2D, destinationLocation: CLLocationCoordinate2D, edgePadding: UIEdgeInsets) {
|
|
cleanAll()
|
|
let startAnnotation = MAPointAnnotation()
|
startAnnotation.coordinate = startLocation
|
startAnnotation.title = "起点"
|
|
let destinationAnnotation = MAPointAnnotation()
|
destinationAnnotation.coordinate = destinationLocation
|
destinationAnnotation.title = "终点"
|
|
self.edgePadding = edgePadding
|
self.startAnnotation = startAnnotation
|
self.destinationAnnotation = destinationAnnotation
|
mapView.addAnnotations([startAnnotation, destinationAnnotation])
|
showPolyline(startCoorninate: startAnnotation.coordinate, endCoordinate: destinationAnnotation.coordinate)
|
mapView.showAnnotations([startAnnotation, destinationAnnotation], edgePadding: edgePadding, animated: false)
|
}
|
|
/// 显示等待应答图标
|
///
|
/// - Parameter waitingForResponseLocation: 叫车地点坐标
|
func setAnnotation(waitingForResponseLocation: CLLocationCoordinate2D?) {
|
|
guard let waitingForResponseLocation = waitingForResponseLocation else { return }
|
|
cleanAll()
|
|
let annotation = YYTitleAnnotation()
|
annotation.coordinate = waitingForResponseLocation
|
annotation.title = "等待应答"
|
mapView.addAnnotation(annotation)
|
mapView.showAnnotations([annotation], animated: true)
|
waitingForResponseAnnotation = annotation
|
}
|
|
/// 显示起点
|
///
|
/// - Parameter startLocation: 起点坐标
|
func setAnnotation(startLocation: CLLocationCoordinate2D?) {
|
|
guard let startLocation = startLocation else { return }
|
|
cleanAll()
|
|
let startAnnotation = MAPointAnnotation()
|
startAnnotation.coordinate = startLocation
|
startAnnotation.title = "起点"
|
|
mapView.addAnnotation(startAnnotation)
|
}
|
|
/// 显示起点
|
///
|
/// - Parameter startLocation: 起点坐标
|
func setAnnotation(startLocation: CLLocationCoordinate2D?,title: String) {
|
|
guard let startLocation = startLocation else { return }
|
|
cleanAll()
|
|
let startAnnotation = YYTitleAnnotation()
|
startAnnotation.coordinate = startLocation
|
startAnnotation.title = title
|
mapView.addAnnotation(startAnnotation)
|
}
|
|
/// 显示终点
|
///
|
/// - Parameter startLocation: 起点坐标
|
func setAnnotation(destinationLocation: CLLocationCoordinate2D?) {
|
|
guard let destinationLocation = destinationLocation else { return }
|
|
cleanAll()
|
|
let destinationAnnotation = MAPointAnnotation()
|
destinationAnnotation.coordinate = destinationLocation
|
destinationAnnotation.title = "终点"
|
|
mapView.addAnnotation(destinationAnnotation)
|
}
|
|
|
/// 显示司机位置
|
///
|
/// - Parameter driverLocation: 司机坐标
|
func setAnnotation(driverLocation: CLLocationCoordinate2D?) {
|
|
guard let driverLocation = driverLocation else { return }
|
|
let driverAnnotation = MAAnimatedAnnotation()
|
driverAnnotation.coordinate = driverLocation
|
driverAnnotation.title = "司机"
|
mapView.addAnnotation(driverAnnotation)
|
self.driverAnnotation = driverAnnotation
|
}
|
|
/// 更新司机位置
|
///
|
/// - Parameter driverLocation: 司机坐标
|
func updateAnnotation(driverLocation: CLLocationCoordinate2D) {
|
|
cleanDriverAnnotation()
|
let driverAnnotation = MAAnimatedAnnotation()
|
driverAnnotation.coordinate = driverLocation
|
driverAnnotation.title = "司机"
|
mapView.addAnnotation(driverAnnotation)
|
self.driverAnnotation = driverAnnotation
|
// guard let myDriverAnnotation = self.driverAnnotation, (myDriverAnnotation.coordinate.latitude != driverLocation.latitude || myDriverAnnotation.coordinate.longitude != driverLocation.longitude) else { return }
|
//
|
// let point = UnsafeMutablePointer<CLLocationCoordinate2D>.allocate(capacity: 1)
|
// point.initialize(to: driverLocation)
|
// self.driverAnnotation?.addMoveAnimation(withKeyCoordinates: point,
|
// count: 1,
|
// withDuration: 0.3,
|
// withName: nil,
|
// completeCallback: { (isFinished) in
|
//
|
// }, stepCallback: { (annototaion) in
|
//
|
// })
|
}
|
|
/// 清除地图所有点和线
|
func cleanAll() {
|
let annotations = mapView.annotations.compactMap { $0 }.filter { (annotation) -> Bool in
|
if let annotation = annotation as? MAPointAnnotation, annotation == centerAnnonation,let _ = annotation as? MAUserLocation {
|
return false
|
} else {
|
return true
|
}
|
}
|
mapView.removeAnnotations(annotations)
|
waitingForResponseAnnotationView = nil
|
let overlays = mapView.overlays.filter { (data) -> Bool in
|
let d = data as! MAOverlay
|
return d.coordinate.latitude != mapView.userLocation?.coordinate.latitude && d.coordinate.longitude != mapView.userLocation?.coordinate.longitude
|
}
|
mapView.removeOverlays(overlays)
|
// mapView.removeOverlays(mapView.overlays.compactMap { $0 })
|
}
|
|
/// 清除司机定位
|
func cleanDriverAnnotation() {
|
mapView.removeAnnotation(driverAnnotation)
|
self.driverAnnotation = nil
|
}
|
|
/// 清除中心点
|
func cleanCenterAnnotation() {
|
mapView.removeAnnotation(centerAnnonation)
|
self.centerAnnonation = nil
|
}
|
|
/// 显示当前定位
|
func showCurrentLocation(edgePadding: UIEdgeInsets) {
|
self.edgePadding = edgePadding
|
mapView.showAnnotations([mapView.userLocation!], animated: false)
|
}
|
|
/// 显示起点到终点的导航路径
|
///
|
/// - Parameters:
|
/// - startCoorninate: 起点坐标
|
/// - endCoordinate: 终点坐标
|
func showPolyline(startCoorninate: CLLocationCoordinate2D?, endCoordinate: CLLocationCoordinate2D?,geoPoints:[AMapGeoPoint]? = nil) {
|
|
guard let startCoorninate = startCoorninate, let endCoordinate = endCoordinate else { return }
|
|
let request = AMapDrivingRouteSearchRequest()
|
request.origin = AMapGeoPoint.location(withLatitude: CGFloat(startCoorninate.latitude), longitude: CGFloat(startCoorninate.longitude))
|
request.destination = AMapGeoPoint.location(withLatitude: CGFloat(endCoordinate.latitude), longitude: CGFloat(endCoordinate.longitude))
|
if geoPoints != nil{
|
request.waypoints = geoPoints!
|
}
|
request.requireExtension = true
|
search.aMapDrivingRouteSearch(request)
|
}
|
}
|
|
extension YYMapViewController: MAMapViewDelegate {
|
|
func mapView(_ mapView: MAMapView!, mapDidMoveByUser wasUserAction: Bool) {
|
mapDidMoveByUserSubject.onNext(wasUserAction)
|
}
|
|
func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
|
if overlay.isKind(of: MAPolyline.self) {
|
let renderer: MAPolylineRenderer = MAPolylineRenderer(overlay: overlay)
|
renderer.lineWidth = 6.0
|
renderer.strokeColor = UIColor.color(hexString: "#00C47A")
|
return renderer
|
} else {
|
return nil
|
}
|
}
|
|
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
|
|
if annotation.isMember(of: MAUserLocation.self) {
|
let userLocationStyleReuseIndetifier = "userLocationStyleReuseIndetifier"
|
|
var annotationView:MAAnnotationView! = mapView.dequeueReusableAnnotationView(withIdentifier: userLocationStyleReuseIndetifier)
|
|
if annotationView == nil {
|
annotationView = LocationAnnotationView(annotation: annotation, reuseIdentifier: userLocationStyleReuseIndetifier)
|
annotationView.canShowCallout = true
|
}
|
|
userLocationView = annotationView as? LocationAnnotationView
|
userLocationView?.updateImage(image: UIImage(named: "start"))
|
|
return annotationView
|
}
|
|
else if annotation.isMember(of: MAPointAnnotation.self) {
|
let pointReuseIndetifier = "pointReuseIndetifier"
|
var annotationView: MAPinAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier) as! MAPinAnnotationView?
|
if annotationView == nil {
|
annotationView = MAPinAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier)
|
}
|
annotationView!.canShowCallout = false
|
annotationView!.animatesDrop = false
|
annotationView!.isDraggable = false
|
|
|
switch annotation.title {
|
case "固定点":
|
annotationView!.animatesDrop = true
|
annotationView?.image = #imageLiteral(resourceName: "icon_location")
|
annotationView?.customCalloutView = nil
|
case "起点":
|
annotationView?.image = #imageLiteral(resourceName: "starting_point")
|
annotationView?.customCalloutView = nil
|
case "终点":
|
annotationView?.image = #imageLiteral(resourceName: "end_point")
|
annotationView?.customCalloutView = nil
|
case "等待应答":
|
annotationView?.image = #imageLiteral(resourceName: "icon_location")
|
annotationView?.customCalloutView = MACustomCalloutView(customView: label_waitingTitle)
|
case "司机":
|
annotationView?.image = #imageLiteral(resourceName: "car")
|
annotationView?.customCalloutView = nil
|
default:
|
annotationView?.image = nil
|
annotationView?.customCalloutView = nil
|
}
|
|
return annotationView!
|
}
|
|
else if annotation.isMember(of: MAAnimatedAnnotation.self) {
|
|
let animatedReuseIndetifier = "animatedPointReuseIndetifier"
|
var annotationView: MAAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: animatedReuseIndetifier)
|
if annotationView == nil {
|
annotationView = MAAnnotationView(annotation: annotation, reuseIdentifier: animatedReuseIndetifier)
|
}
|
annotationView!.canShowCallout = false
|
annotationView!.isDraggable = false
|
annotationView?.image = #imageLiteral(resourceName: "car")
|
if isCarpool{
|
annotationView?.image = #imageLiteral(resourceName: "icon_driver")
|
}
|
annotationView?.customCalloutView = nil
|
|
return annotationView
|
}
|
|
else if annotation.isMember(of: YYTitleAnnotation.self) {
|
|
if waitingForResponseAnnotationView == nil {
|
waitingForResponseAnnotationView = YYTitleAnnotationView(annotation: annotation, reuseIdentifier: YYTitleAnnotationView.reuseIdentifier)
|
}
|
if annotation.title ?? "" != "等待应答"{
|
waitingForResponseAnnotationView?.label_title.text = annotation.title ?? ""
|
waitingForResponseAnnotationView?.image = #imageLiteral(resourceName: "starting_point")
|
}else{
|
waitingForResponseAnnotationView?.image = #imageLiteral(resourceName: "icon_location")
|
}
|
|
|
return waitingForResponseAnnotationView!
|
}
|
|
else if annotation.isKind(of: CarpoolPointAnnotation.self) {
|
let annotation = annotation as! CarpoolPointAnnotation
|
if annotation.pointType == .me{
|
let identifier = "meAnnotation"
|
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? CarpoolingAnnotationView
|
if annotationView == nil{
|
annotationView = CarpoolingAnnotationView(annotation: annotation, reuseIdentifier: identifier)
|
annotationView?.canShowCallout = false
|
annotationView?.setSelected(true, animated: false)
|
annotationView?.setText(annotation.title)
|
}
|
|
if annotation.isStart{
|
annotationView?.image = UIImage(named: "person_blue")
|
}else{
|
annotationView?.image = UIImage(named: "end_point")
|
}
|
|
return annotationView
|
}else if annotation.pointType == .other{
|
let identifier = "otherAnnotation"
|
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? CarpoolingAnnotationView
|
if annotationView == nil{
|
annotationView = CarpoolingAnnotationView(annotation: annotation, reuseIdentifier: identifier)
|
annotationView?.canShowCallout = false
|
annotationView?.setSelected(true, animated: false)
|
annotationView?.setText(annotation.title)
|
}
|
if annotation.isStart{
|
annotationView?.image = UIImage(named: "person_yellow")
|
}else{
|
annotationView?.image = UIImage(named: "end_point")
|
}
|
return annotationView
|
}else if annotation.pointType == .driver{
|
let identifier = "driverAnnotation"
|
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? CarpoolingAnnotationView
|
if annotationView == nil{
|
annotationView = CarpoolingAnnotationView(annotation: annotation, reuseIdentifier: identifier)
|
annotationView?.canShowCallout = false
|
annotationView?.setSelected(false, animated: false)
|
annotationView?.setText("")
|
}
|
annotationView?.image = UIImage(named: "icon_driver")
|
return annotationView
|
}
|
}
|
|
else {
|
return nil
|
}
|
return nil
|
}
|
|
func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!, updatingLocation: Bool) {
|
if !updatingLocation && userLocation != nil {
|
self.userLocationView?.rotateDegree = CGFloat(userLocation.heading.trueHeading) - mapView.rotationDegree
|
}
|
}
|
}
|
|
extension YYMapViewController: AMapSearchDelegate {
|
|
func onRouteSearchDone(_ request: AMapRouteSearchBaseRequest!, response: AMapRouteSearchResponse!) {
|
|
if response.count > 0 {
|
|
guard let path = response.route.paths.first, let polyline = path.coverToPilyline() else { return }
|
let overlays = mapView.overlays.filter { (data) -> Bool in
|
let d = data as! MAOverlay
|
return d.coordinate.latitude != mapView.userLocation?.coordinate.latitude && d.coordinate.longitude != mapView.userLocation?.coordinate.longitude
|
}
|
mapView.removeOverlays(overlays)
|
// mapView.removeOverlays(mapView.overlays.compactMap { $0 })
|
mapView.add(polyline)
|
}
|
}
|
}
|
|
//extension AMapPath {
|
//
|
// func coverToPilyline() -> MAPolyline? {
|
// let coordinateStrings = steps.map { $0.polyline.components(separatedBy: ";") }.reduce([String](), +)
|
// var coordinates = coordinateStrings.map { (cs) -> CLLocationCoordinate2D in
|
// let temp = cs.components(separatedBy: ",")
|
// let coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(temp[1]) ?? 0.0, longitude: CLLocationDegrees(temp[0]) ?? 0.0)
|
// return coordinate
|
// }
|
// let polyLine = MAPolyline(coordinates: &coordinates, count: UInt(coordinates.count))
|
// return polyLine
|
// }
|
//}
|