262 lines
8.1 KiB
Swift
262 lines
8.1 KiB
Swift
//
|
|
// MapViewController.swift
|
|
// PatternsSwift
|
|
//
|
|
// Created by mrustaa on 19/05/2020.
|
|
// Copyright © 2020 mrustaa. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import MapKit
|
|
import CoreLocation
|
|
import ContainerControllerSwift
|
|
|
|
class MapViewManager: NSObject {
|
|
|
|
// MARK: Map Properties
|
|
|
|
var mapView: MKMapView?
|
|
var compass: MKCompassButton!
|
|
|
|
var locationManager: CLLocationManager?
|
|
|
|
var selectAnnotation: MKPointAnnotation?
|
|
var routeOverlay: MKOverlay?
|
|
var setMoveMyLocationOnce: Bool = false
|
|
|
|
// MARK: - Callbacks
|
|
|
|
var changeRegionCallback: (() -> ())?
|
|
var selectPinCallback: (() -> ())?
|
|
|
|
// MARK: - Init
|
|
|
|
public init(mapView: MKMapView) {
|
|
super.init()
|
|
|
|
mapView.delegate = self
|
|
self.mapView = mapView
|
|
|
|
loadLocation()
|
|
updateCompass()
|
|
}
|
|
|
|
// MARK: - Location Manager
|
|
|
|
func loadLocation() {
|
|
|
|
if CLLocationManager.locationServicesEnabled() {
|
|
locationManager = CLLocationManager()
|
|
locationManager?.delegate = self
|
|
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
|
|
locationManager?.requestAlwaysAuthorization()
|
|
locationManager?.startUpdatingLocation()
|
|
}
|
|
}
|
|
|
|
// MARK: - Map Compass
|
|
|
|
func updateCompass() {
|
|
|
|
mapView?.showsCompass = false
|
|
|
|
compass = MKCompassButton(mapView:mapView)
|
|
compass.x = (ContainerDevice.width - 47)
|
|
compass.compassVisibility = .adaptive
|
|
|
|
mapView?.addSubview(compass)
|
|
}
|
|
|
|
public func closeRoute(showSelectPin: Bool) {
|
|
|
|
if let route = routeOverlay {
|
|
mapView?.removeOverlay(route)
|
|
}
|
|
selectPinAnimation(show: showSelectPin)
|
|
}
|
|
|
|
public func selectPinAnimation(show: Bool) {
|
|
|
|
if let selectPin = selectAnnotation {
|
|
if show {
|
|
mapView?.selectAnnotation(selectPin, animated: true)
|
|
} else {
|
|
mapView?.deselectAnnotation(selectPin, animated: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
public func addMapPinFrom(longPress: UILongPressGestureRecognizer) {
|
|
|
|
guard let mapView = mapView else { return }
|
|
|
|
if let anotationMap = selectAnnotation {
|
|
mapView.removeAnnotations([anotationMap]);
|
|
}
|
|
|
|
let point: CGPoint = longPress.location(in: mapView)
|
|
let coordinate: CLLocationCoordinate2D = mapView.convert(point, toCoordinateFrom: mapView)
|
|
|
|
let annotation = MKPointAnnotation()
|
|
annotation.coordinate = coordinate
|
|
mapView.addAnnotation(annotation)
|
|
|
|
selectAnnotation = annotation
|
|
|
|
mapView.selectAnnotation(annotation, animated: true)
|
|
}
|
|
|
|
|
|
// MARK: - Map Show Route
|
|
|
|
public func showRouteOnMapMyLocation() {
|
|
if let pickupCoord = mapView?.userLocation.location?.coordinate,
|
|
let destinationCoord = selectAnnotation {
|
|
|
|
showRouteOnMap(pickupCoordinate: pickupCoord, destinationCoordinate: destinationCoord.coordinate)
|
|
}
|
|
}
|
|
|
|
public func showRouteOnMap(pickupCoordinate: CLLocationCoordinate2D, destinationCoordinate: CLLocationCoordinate2D) {
|
|
|
|
closeRoute(showSelectPin: false)
|
|
|
|
let sourcePlacemark = MKPlacemark(coordinate: pickupCoordinate, addressDictionary: nil)
|
|
let sourceMapItem = MKMapItem(placemark: sourcePlacemark)
|
|
|
|
let destinationPlacemark = MKPlacemark(coordinate: destinationCoordinate, addressDictionary: nil)
|
|
let destinationMapItem = MKMapItem(placemark: destinationPlacemark)
|
|
|
|
let directionRequest = MKDirections.Request()
|
|
directionRequest.source = sourceMapItem
|
|
directionRequest.destination = destinationMapItem
|
|
directionRequest.transportType = .automobile
|
|
|
|
|
|
let directions = MKDirections(request: directionRequest)
|
|
|
|
directions.calculate { [weak self] (response, error) -> Void in
|
|
guard let _self = self else { return }
|
|
|
|
guard let response = response else { return }
|
|
|
|
let route = response.routes[0]
|
|
|
|
_self.routeOverlay = route.polyline
|
|
|
|
_self.mapView?.addOverlay((route.polyline), level: MKOverlayLevel.aboveRoads)
|
|
|
|
let rect: MKMapRect = route.polyline.boundingMapRect
|
|
|
|
let coordReg: MKCoordinateRegion = MKCoordinateRegion(rect)
|
|
|
|
let mapButtonWidth: CGFloat = 45
|
|
|
|
let padding: CGFloat = 35
|
|
let bottom: CGFloat = ContainerDevice.isPortrait ? (261 + padding) : padding
|
|
let left: CGFloat = ContainerDevice.isPortrait ? padding : (261 + padding * 2)
|
|
let right: CGFloat = (mapButtonWidth + 8 + padding)
|
|
|
|
let insets = UIEdgeInsets(top: padding, left: left, bottom: bottom, right: right)
|
|
|
|
_self.mapView?.setVisibleRegion(mapRegion: coordReg, edgePadding: insets, animated: true)
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Map-Delegate
|
|
|
|
extension MapViewManager: MKMapViewDelegate {
|
|
|
|
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
|
|
if !animated {
|
|
changeRegionCallback?()
|
|
}
|
|
}
|
|
|
|
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
|
|
if !animated {
|
|
changeRegionCallback?()
|
|
}
|
|
}
|
|
|
|
// MARK: - Map Select-Pin
|
|
|
|
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
|
|
|
|
let region = MKCoordinateRegion(center: view.annotation!.coordinate, span: mapView.region.span)
|
|
mapView.setRegion(region, animated: true)
|
|
|
|
selectPinCallback?()
|
|
|
|
if let route = routeOverlay {
|
|
mapView.removeOverlay(route)
|
|
}
|
|
}
|
|
|
|
// MARK: - Map Route-Color
|
|
|
|
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
|
|
|
let renderer = MKPolylineRenderer(overlay: overlay)
|
|
|
|
renderer.strokeColor = Colors.rgb(17, 147, 255)
|
|
renderer.lineWidth = 8.0
|
|
|
|
return renderer
|
|
}
|
|
|
|
}
|
|
|
|
// MARK: - Update Location Delegate
|
|
|
|
extension MapViewManager: CLLocationManagerDelegate {
|
|
|
|
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
|
|
|
|
if setMoveMyLocationOnce { return }
|
|
|
|
if let location = locations.last {
|
|
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
|
|
|
|
let radius: CLLocationDistance = 3200
|
|
let region = MKCoordinateRegion(center: center, latitudinalMeters: radius, longitudinalMeters: radius)
|
|
|
|
mapView?.setRegion(region, animated: false)
|
|
|
|
let annotation = MKPointAnnotation()
|
|
annotation.coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude + 0.01, longitude: location.coordinate.longitude + 0.01)
|
|
mapView?.addAnnotation(annotation)
|
|
selectAnnotation = annotation
|
|
|
|
setMoveMyLocationOnce = true
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// MARK: - Map Extension
|
|
|
|
extension MKCoordinateRegion {
|
|
var mapRect: MKMapRect {
|
|
get {
|
|
let a = MKMapPoint( CLLocationCoordinate2DMake(
|
|
self.center.latitude + self.span.latitudeDelta / 2,
|
|
self.center.longitude - self.span.longitudeDelta / 2))
|
|
|
|
let b = MKMapPoint( CLLocationCoordinate2DMake(
|
|
self.center.latitude - self.span.latitudeDelta / 2,
|
|
self.center.longitude + self.span.longitudeDelta / 2))
|
|
|
|
return MKMapRect(x: min(a.x,b.x), y: min(a.y,b.y), width: abs(a.x-b.x), height: abs(a.y-b.y))
|
|
}
|
|
}
|
|
}
|
|
|
|
extension MKMapView {
|
|
func setVisibleRegion(mapRegion: MKCoordinateRegion, edgePadding insets: UIEdgeInsets, animated animate: Bool) {
|
|
self.setVisibleMapRect(mapRegion.mapRect, edgePadding: insets , animated: animate)
|
|
}
|
|
}
|