Reputation: 1
I am trying to implement a turn-by-turn navigation app using Mapkit, all other implementations that I have found are only using Storyboard and not SwiftUI. I have found similar implementation of what I am trying to do here https://github.com/rubyvictor/MapKit-turn-by-turn-Navigation. The issue I am having is that although there are no errors no map appears when the app is run.
import SwiftUI
import MapboxMaps
import MapboxDirections
import MapboxCoreNavigation
import MapboxNavigation
import CoreLocation
import MapKit
import AVFoundation
struct maps: View {
var body: some View {
// Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
MapViewWrapper()
//NavigationLink("Settings", destination: Settings())
.padding(5.0)
}
}
struct maps_Previews: PreviewProvider {
static var previews: some View {
maps()
}
}
struct MapViewWrapper : UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> ViewController {
return ViewController()
}
func updateUIViewController(_ uiViewController: ViewController, context: Context) {
//uiViewController.directionsLabel.self
}
}
class ViewController: UIViewController {
@IBOutlet weak var directionsLabel: UILabel!
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
//MARK: - Step three Store User Coordinates
var currentCoordinates: CLLocationCoordinate2D!
var steps = [MKRoute.Step]()
let speechSynthesizer = AVSpeechSynthesizer()
var stepCounter = 0
override func viewDidLoad() {
super.viewDidLoad()
//MARK: - Step one setup
setupLocationManager()
}
fileprivate func setupLocationManager() {
locationManager.requestAlwaysAuthorization()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.startUpdatingLocation()
}
func getDirections(to destination: MKMapItem) {
//MARK: - Step ten Initialize placemark of current coordinates and initialize mapItem with it
let sourcePlacemark = MKPlacemark(coordinate: currentCoordinates)
let sourceMapItem = MKMapItem(placemark: sourcePlacemark)
let directionRequest = MKDirections.Request()
//MARK: - Step eleven set up direction for source and destination
directionRequest.source = sourceMapItem
directionRequest.destination = destination
//MARK: - Step twelve set up transport type
directionRequest.transportType = .automobile
//MARK: - Step thirteen Initialize directions
let directions = MKDirections(request: directionRequest)
directions.calculate { [weak self] (response, error) in
if let error = error {
return
}
guard let response = response else { return }
guard let mainRoute = response.routes.first else { return }
//MARk: - Step fourteen Add polyline overlay to mapView
self?.mapView.addOverlay(mainRoute.polyline)
//MARK: - Step fifteen Save the steps to an empty array
self?.steps = mainRoute.steps
//MARK: - Step nineteen Before starting Monitoring, must remove monitoring regions
self?.locationManager.monitoredRegions.forEach({ self?.locationManager.stopMonitoring(for: $0)
})
//MARk: - Step seventeen create Geofences On Polyline steps
for i in 0..<mainRoute.steps.count {
let step = mainRoute.steps[i]
print(step.instructions)
print(step.distance)
let region = CLCircularRegion(center: step.polyline.coordinate, radius: 20, identifier: "\(i)")
//MARK: - Step eighteen start monitoring region
self?.locationManager.startMonitoring(for: region)
//MARK: - Step twenty initialize add circle overlay for region
let circle = MKCircle(center: region.center, radius: region.radius)
self?.mapView.addOverlay(circle)
}
//MARK: - Step twenty two create message to update directionsLabel for each step
let initialMessage = "In \(self?.steps[0].distance ?? 0) metres, \(self?.steps[0].instructions ?? "") then in \(self?.steps[1].distance ?? 0) metres, \(self?.steps[1].instructions ?? "")"
self?.directionsLabel.text = initialMessage
//MARK: - Step twenty three create speechUtterance for each message
let speechUtterance = AVSpeechUtterance(string: initialMessage)
self?.speechSynthesizer.speak(speechUtterance)
self?.stepCounter += 1
}
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//MARK: - Step two get user's current location
manager.startUpdatingLocation()
guard let currentLocation = locations.first else { return }
//MARK: - Step four set current coordinate
currentCoordinates = currentLocation.coordinate
//MARK: - Step five set heading to track user direction
//mapView.userTrackingMode = .followWithHeading
}
//MARK: - Step twenty four
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Entered region!")
stepCounter += 1
if stepCounter < steps.count {
let currentStep = steps[stepCounter]
let message = "In \(currentStep.distance) metres, \(currentStep.instructions)"
self.directionsLabel.text = message
let speechUtterance = AVSpeechUtterance(string: message)
speechSynthesizer.speak(speechUtterance)
} else {
let message = "Arrived at destination"
directionsLabel.text = message
let speechUtterance = AVSpeechUtterance(string: message)
speechSynthesizer.speak(speechUtterance)
stepCounter = 0
self.locationManager.monitoredRegions.forEach { self.locationManager.stopMonitoring(for: $0)
}
}
}
}
extension ViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
//MARK: - Step six create search request
let localSearchRequest = MKLocalSearch.Request()
localSearchRequest.naturalLanguageQuery = searchBar.text
//MARK: - Step seven set up region with span
let region = MKCoordinateRegion(center: currentCoordinates, span: MKCoordinateSpan.init(latitudeDelta: 0.1, longitudeDelta: 0.1))
localSearchRequest.region = region
let localSearch = MKLocalSearch(request: localSearchRequest)
//MARK: - Step eight start local search
localSearch.start { [weak self] (response, error) in
if let error = error {
return
}
//MARK: - Step nine get the map items from search response
guard let response = response else { return }
print(response.mapItems)
guard let firstMapItem = response.mapItems.first else { return }
self?.getDirections(to: firstMapItem)
}
}
}
extension ViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
//MARK: - step sixteen create renderer for polyline overlay
if overlay is MKPolyline {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = .blue
renderer.lineWidth = 10
return renderer
}
//MARK: - Step twenty one check renderer for region circle
if overlay is MKCircle {
let renderer = MKCircleRenderer(overlay: overlay)
renderer.strokeColor = .orange
renderer.fillColor = .red
renderer.alpha = 0.5
return renderer
}
return MKOverlayRenderer()
}
}
I have tried changing what is in the ContentView but I expect the issue has something to do with the IBOutlet variables, but there isn't much documentation on them. Basically, I am trying to find a to use the code in the git repo (View Controller file) and use it in SwiftUI instead storyboard.
Upvotes: 0
Views: 321