//
|
// YYMapViewManager.swift
|
// OKProject
|
//
|
// Created by alvin_y on 2020/6/2.
|
// Copyright © 2020 yangwang. All rights reserved.
|
//
|
|
import UIKit
|
import RxCocoa
|
import RxSwift
|
import AMapSearchKit
|
import HandyJSON
|
/// 当前状态
|
enum MapViewManagerState {
|
/// 现在
|
case now
|
/// 预约
|
case appointment
|
/// 代叫
|
case call
|
}
|
|
/// 呼叫状态
|
enum CallState {
|
/// 普通状态
|
case normal
|
/// 呼叫状态
|
case called
|
}
|
|
enum CarpoolingType:Int,HandyJSONEnum{
|
case none = 0
|
case seating = 3 //拼座
|
case exclusive = 1 //独享
|
case onePrice = 2 //一口价
|
}
|
|
/// 用于判断是否选择起点后 地址名称发生变化
|
enum AddressNameType {
|
case normal // 默认
|
case search // 搜索后不变
|
}
|
/// 乘车人模型
|
struct PassengerModel {
|
var name: String = ""
|
var phone: String = ""
|
}
|
|
/// 地图管理
|
class YYMapViewManager: NSObject {
|
|
var interaction = true
|
// 用于判断是否选择起点后 地址名称发生变化
|
var addressNameType = BehaviorRelay<AddressNameType>(value: .normal)
|
/// 出行方式
|
let orderType = BehaviorRelay<OrderType>(value: .taxi)
|
|
/// 搜索管理类
|
private var manager: LocationSearchManager = LocationSearchManager()
|
|
/// 单例
|
static let share: YYMapViewManager = YYMapViewManager()
|
|
/// 当前状态
|
var state = BehaviorRelay<MapViewManagerState>(value: .now)
|
|
/// 当前状态
|
var callState = BehaviorRelay<CallState>(value: .normal)
|
|
/// 记录最后一次状态
|
var lastCallState = false
|
|
/// 当前定位经纬度
|
var currentLocation = BehaviorRelay<CLLocationCoordinate2D?>(value: nil)
|
|
/// 用户经纬度
|
var userLocation: CLLocationCoordinate2D {
|
return self.mapView.userLocation.coordinate
|
}
|
|
/// 搜索的位置信息
|
let searchInfo = BehaviorRelay<AddressModelInfo?>(value: nil)
|
/// 开始位置信息
|
let originInfo = BehaviorRelay<AddressModelInfo?>(value: nil)
|
|
/// 目的地位置信息
|
let destination = BehaviorRelay<AddressModelInfo?>(value: nil)
|
|
/// 预约时间戳
|
let timeStamp = BehaviorRelay<Double?>(value: nil)
|
|
/// 送达时间
|
let arrivetimeStamp = BehaviorRelay<Double?>(value: nil)
|
|
/// 乘车人
|
let passenger = BehaviorRelay<PassengerModel?>(value: nil)
|
|
let passengerNum = BehaviorRelay<Int>(value: 1)
|
|
/// 小费
|
let tip = BehaviorRelay<String?>(value: nil)
|
|
/// 计费方式 计费方式(1单程计费,2=包车计费)
|
let calType = BehaviorRelay<Int?>(value: nil)
|
|
/// 用户位置
|
private var userLocationView: LocationAnnotationView?
|
|
/// 中心动画
|
var animation = Delegate<Void, Void>()
|
|
/// 地图将要发生移动时调用此接口
|
var mapWillMoveByUser = Delegate<Void, Void>()
|
|
/// viewModel
|
let viewModel = YYMapViewManagerViewModel()
|
|
/// 用户点数据
|
private var pointArray: [PointAnnotation] = []
|
|
///搜索类
|
private let search = AMapSearchAPI()
|
|
/// 路线数据
|
private var pathPolylines: [MAOverlay] = []
|
|
/// 加入终点
|
private var destinationAnnotationView: UserAnnotationView?
|
|
/// 当前城市
|
let currentCity = BehaviorRelay<String?>(value: nil)
|
|
let carpoolingType = BehaviorRelay<CarpoolingType>(value: .seating)
|
|
/// 地图
|
let mapView: MAMapView = {
|
let view = MAMapView()
|
view.mapType = .standard
|
view.showsUserLocation = true // YES 为打开定位,NO为关闭定位
|
view.zoomLevel = 17
|
view.isRotateCameraEnabled = false
|
view.isRotateEnabled = false
|
view.userTrackingMode = .follow
|
view.pausesLocationUpdatesAutomatically = false
|
// view.allowsBackgroundLocationUpdates = true
|
view.isRotateEnabled = false
|
view.showsCompass = false
|
view.showsScale = false
|
return view
|
}()
|
|
override init() {
|
super.init()
|
setup()
|
bindRx()
|
}
|
|
//MARK: - Rx
|
func bindRx() {
|
|
viewModel.time
|
.subscribe(onNext: { (string) in
|
DispatchQueue.main.async {
|
self.destinationAnnotationView?.title = string
|
}
|
}).disposed(by: rx.disposeBag)
|
|
let ob1 = originInfo.map{value in
|
return value != nil
|
}
|
let ob2 = destination.map{value in
|
return value != nil
|
}
|
let ob = Observable.combineLatest(ob1,ob2).map{originInfo,destination in
|
return originInfo && destination
|
}
|
ob.observeOn(MainScheduler.instance)
|
.subscribe(onNext: { (b) in
|
if self.lastCallState == b{
|
return
|
}
|
self.callState.accept(b ? .called : .normal)
|
self.lastCallState = b
|
if b == true{
|
// 绘点
|
self.drawAnnotation()
|
}else{
|
// 取消绘点
|
self.removeAnnotations()
|
}
|
}).disposed(by: rx.disposeBag)
|
|
}
|
|
|
/// 绘制点标记
|
func drawAnnotation() {
|
guard let originInfo = self.originInfo.value,let destination = self.destination.value else {return}
|
|
/// 加入起点
|
let startPointAnnotation = PointAnnotation()
|
startPointAnnotation.coordinate = CLLocationCoordinate2DMake(originInfo.lat, originInfo.lon)
|
startPointAnnotation.title = nil
|
startPointAnnotation.type = 1
|
pointArray.append(startPointAnnotation)
|
|
let destinationAnnotation = PointAnnotation()
|
destinationAnnotation.coordinate = CLLocationCoordinate2DMake(destination.lat, destination.lon)
|
destinationAnnotation.title = "大约行驶0分钟"
|
destinationAnnotation.type = 2
|
pointArray.append(destinationAnnotation)
|
self.mapView.addAnnotations(pointArray)
|
self.mapView.showAnnotations(pointArray, edgePadding: UIEdgeInsets(top: navH + 90, left: 10, bottom: 280, right: 10), animated: true)
|
|
// 绘线
|
/// 路径规划
|
let startCoordinate = CLLocationCoordinate2DMake(CLLocationDegrees(originInfo.lat), CLLocationDegrees(originInfo.lon))
|
let destinationCoordinate = CLLocationCoordinate2DMake(CLLocationDegrees(destination.lat), CLLocationDegrees(destination.lon))
|
let request = AMapDrivingRouteSearchRequest()
|
request.origin = AMapGeoPoint.location(withLatitude: CGFloat(startCoordinate.latitude), longitude: CGFloat(startCoordinate.longitude))
|
request.destination = AMapGeoPoint.location(withLatitude: CGFloat(destinationCoordinate.latitude), longitude: CGFloat(destinationCoordinate.longitude))
|
request.requireExtension = true
|
search?.aMapDrivingRouteSearch(request)
|
}
|
|
/// 清除点标记
|
func removeAnnotations() {
|
if pointArray.count > 0{
|
self.mapView.removeAnnotations(pointArray)
|
pointArray.removeAll()
|
}
|
removeOverlays()
|
}
|
|
/// 清除路线
|
func removeOverlays() {
|
if pathPolylines.count > 0{
|
mapView.removeOverlays(pathPolylines)
|
pathPolylines.removeAll()
|
}
|
}
|
|
/// 设置
|
func setup() {
|
mapView.delegate = self
|
search?.delegate = self
|
manager.searchDelegate = self
|
let r = MAUserLocationRepresentation()
|
r.fillColor = UIColor.color(hexString: "#22CD7D",0.11)
|
r.strokeColor = UIColor.color(hexString: "#0AC346",0.24)
|
r.lineWidth = 2
|
mapView.update(r)
|
}
|
|
|
/// 清除数据
|
func clearData() {
|
YYMapViewManager.share.destination.accept(nil)
|
YYMapViewManager.share.timeStamp.accept(nil)
|
YYMapViewManager.share.passenger.accept(nil)
|
YYMapViewManager.share.tip.accept(nil)
|
YYMapViewManager.share.calType.accept(nil)
|
guard let coordinate = originInfo.value else{return}
|
self.mapView.setCenter(CLLocationCoordinate2D.init(latitude: coordinate.lat, longitude: coordinate.lon), animated: false)
|
self.mapView.zoomLevel = 17
|
}
|
|
/// 复位
|
func position() {
|
if YYLocationManager.shared.isValidated.value{
|
YYLocationManager.shared.requestLocation(success: { (model) in
|
YYLocationManager.shared.province = model.province
|
YYLocationManager.shared.currentCity = model.city
|
YYLocationManager.shared.district = model.district
|
YYLocationManager.shared.currentCityCode = model.citycode
|
self.currentCity.accept(model.city)
|
}) { (error) in
|
}
|
self.mapView.setCenter(self.mapView.userLocation.coordinate, animated: true)
|
}else{
|
self.mapView.setCenter(CLLocationCoordinate2D(latitude: YYLocationManager.shared.latitude, longitude: YYLocationManager.shared.longitude), animated: true)
|
}
|
|
}
|
|
/// 设置地图中心点
|
func setCenter(center: CLLocationCoordinate2D) {
|
self.mapView.setCenter(center, animated: true)
|
}
|
|
/// 定位
|
private func positioning() {
|
let coordinate = self.mapView.centerCoordinate
|
self.currentLocation.accept(CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude))
|
manager.startReverseSearch(lat: coordinate.latitude, lng: coordinate.longitude)
|
}
|
}
|
|
/// MARK: LocationSearchDelegate
|
extension YYMapViewManager: LocationSearchDelegate
|
{
|
func onSearchDone(address: [AddressModelInfo]) {
|
if address.count > 0{
|
let model = address[0]
|
model.lat = currentLocation.value?.latitude ?? 0
|
model.lon = currentLocation.value?.longitude ?? 0
|
if self.addressNameType.value == .search {
|
self.originInfo.accept(self.searchInfo.value)
|
}else{
|
self.originInfo.accept(model)
|
}
|
}
|
}
|
}
|
//MARK: - MAMapViewDelegate
|
extension YYMapViewManager: MAMapViewDelegate
|
{
|
func mapView(_ mapView: MAMapView!, regionDidChangeAnimated animated: Bool) {
|
// 判断是否定位
|
if self.callState.value == .normal{
|
positioning()
|
}
|
}
|
|
func mapView(_ mapView: MAMapView!, mapWillMoveByUser wasUserAction: Bool) {
|
mapWillMoveByUser.call()
|
}
|
|
func mapView(_ mapView: MAMapView!, mapDidMoveByUser wasUserAction: Bool) {
|
//做动画
|
animation.call()
|
}
|
|
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
|
if annotation.isKind(of: MAUserLocation.classForCoder()){
|
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: "icon_coordinate"))
|
|
return annotationView
|
}else if annotation.isKind(of: PointAnnotation.classForCoder()) {
|
let annotation = annotation as! PointAnnotation
|
var imageName: String = ""
|
let identifier = "annotation"
|
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? UserAnnotationView
|
if annotationView == nil{
|
annotationView = UserAnnotationView(annotation: annotation, reuseIdentifier: identifier)
|
}
|
switch annotation.type {
|
// 开始位置
|
case 1:
|
imageName = "starting_point"
|
case 2:
|
imageName = "end_point"
|
annotationView?.yy_tintColor = ThemeColor
|
annotationView?.yy_isTintColor = true
|
self.destinationAnnotationView = annotationView
|
viewModel.queryExpectedTime()
|
case 3:// 结束位置
|
imageName = "end"
|
case 4:
|
imageName = "origin-1"
|
case 5:
|
imageName = "terminus"
|
case 6://司机位置
|
imageName = "bus_location"
|
default:
|
return nil
|
}
|
let image = UIImage(named: imageName)
|
annotationView?.image = image
|
if annotation.title != nil{
|
annotationView?.title = annotation.title
|
}
|
return annotationView
|
}
|
return nil
|
}
|
|
func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
|
let renderer: MAPolylineRenderer = MAPolylineRenderer(overlay: overlay)
|
renderer.lineWidth = 6.0
|
renderer.strokeColor = UIColor.color(hexString: "#00C47A")
|
return renderer
|
}
|
|
func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!, updatingLocation: Bool) {
|
if !updatingLocation && userLocation != nil {
|
self.userLocationView?.rotateDegree = CGFloat(userLocation.heading.trueHeading) - mapView.rotationDegree
|
}
|
}
|
}
|
|
// MARK: - AMapSearchDelegate
|
extension YYMapViewManager:AMapSearchDelegate{
|
func onRouteSearchDone(_ request: AMapRouteSearchBaseRequest!, response: AMapRouteSearchResponse!) {
|
if response.count > 0 {
|
//解析response获取路径信息
|
let path = response.route.paths[0].coverToPilyline()
|
guard let polylines = path else {
|
return
|
}
|
removeOverlays()
|
pathPolylines.append(polylines)
|
mapView.addOverlays(pathPolylines)
|
}
|
}
|
func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {
|
print("Error:\(String(describing: error))")
|
}
|
}
|