I've followed the steps of adding a map to my iOS app and then created a struct to "bridge" between swiftUI and UIkit but for some reason when I call the struct nothing would show whatsoever.
This is my viewcontroller:
import CoreLocation
import UIKit
import GoogleMaps
class ViewController: UIViewController, CLLocationManagerDelegate{
let manager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
GMSServices.provideAPIKey("xxx")
print("License: \n\n\(GMSServices.openSourceLicenseInfo())")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else {
return
}
let coordinate = location .coordinate
let camera = GMSCameraPosition.camera(withLatitude: coordinate.latitude, longitude: coordinate.longitude, zoom: 6.0)
let mapView = GMSMapView.map(withFrame: view.frame, camera: camera)
view.addSubview(mapView)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: -coordinate.latitude, longitude: coordinate.longitude)
marker.title = "Sydney"
marker.snippet = "Australia"
marker.map = mapView
}
}
and this is the struct created in my content view:
struct YourViewControllerView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> ViewController {
return ViewController()
}
func updateUIViewController(_ uiViewController: ViewController, context: Context) {
}
}
I've searched for similar problems but everyone else had the problem of the map not loading (marker and google logo still show), whereas in my case nothing shows on the screen at all.
Just to reiterate, my Maps SDK for iOS is enabled.
I've been trying to find a solution for a week now so help is greatly appreciated.
Related
I want to detect a user tap on the map so i can add a marker and get the coordinates of that point. I was able to do that on android and with react but it seems impossible in swiftui because i can't find new ways to do that.
Currently i have my mapview like this.
import SwiftUI
import UIKit
import MapboxMaps
struct MapBoxMapView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MapViewController {
return MapViewController()
}
func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
}
}
class MapViewController: UIViewController {
internal var mapView: MapView!
override func viewDidLoad() {
super.viewDidLoad()
let myResourceOptions = ResourceOptions(accessToken: "MY_TOKEN")
let myCameraOptions = CameraOptions(center: CLLocationCoordinate2D(latitude: 0, longitude: 0), zoom: 10)
let initOptions = MapInitOptions(
resourceOptions: myResourceOptions,
cameraOptions: myCameraOptions,
styleURI: StyleURI(rawValue: StyleURI.satellite.rawValue)
)
mapView = MapView(frame: view.bounds, mapInitOptions: initOptions)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(mapView)
}
}
What can i do to make it possible? I searched on v10 documentation but found nothing.
currently I am playing around with swiftui, CoreData and CoreLocation.
My goal is to store waypoints and calculate their distances to the current Location while moving. These distances should be written to CoreData and shown in the UI.
I am getting location updates in the Location Managers "didUpdateLocations", but what is the smartest way to write to CoreData from here?
I thought, I could just "merge" the DataController and LocationManager into one class, but
1: I can not access CoreData in the DataController itself
2: I can not create an observed object of the LocationManager anymore, since it does not provide a fetchrequest.
I'd really appreciate a slight hint here, since I don't know what to google anymore ;)
My DataController looks like this:
import CoreData
import Foundation
class DataController: ObservableObject {
let container = NSPersistentContainer(name: "Positions")
init() {
container.loadPersistentStores { description, error in
if let error = error {
print("Core Data failed to load: \(error.localizedDescription)")
}
}
}
}
And my LocationManager looks like this:
import Foundation
import Combine
import CoreLocation
class LocManager: NSObject, ObservableObject, CLLocationManagerDelegate {
#Published var location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 0, longitude: 0)
#Published var altitude: Double = 0
#Published var degrees: Double = 0
private let locationManager: CLLocationManager
override init() {
//LocationManager INIT
self.locationManager = CLLocationManager()
super.init()
self.locationManager.delegate = self
self.setup()
}
private func setup() {
// set accuracy
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
//update filter
//self.locationManager.headingFilter = kCLHeadingFilterNone //High Power usage
self.locationManager.headingFilter = 0.5
self.locationManager.distanceFilter = 1
if CLLocationManager.headingAvailable() {
self.locationManager.startUpdatingLocation()
self.locationManager.startUpdatingHeading()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
self.degrees = -1 * newHeading.magneticHeading
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
location = locations.first!.coordinate
altitude = locations.first!.altitude
/*
I cant access CoreData here, can I?
*/
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch locationManager.authorizationStatus {
case .authorizedWhenInUse:
locationManager.requestWhenInUseAuthorization()
break
case .restricted:
break
case .denied:
break
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
break
default:
break
}
}
}
Thanks for your help!
can someone please help me with my problem?
I have a SwiftUI Project and wrote a MKMapView File. I would like to store the Center coordinates in a #EnvironmentObject variable.
Unfortunately, I can't manage to pack the center coordinates into the EnvironmentObject variable.
my code looks like this:
struct MapView: UIViewRepresentable {
#EnvironmentObject var messpunkt_manager: Messpunkt_Manager
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.showsUserLocation = true // zeigt den aktuellen Standort des Users
map.delegate = context.coordinator // ermöglich die Bedienung
// shows annotations already in array
for location in messpunkt_manager.messpunkte {
let annotation = MKPointAnnotation()
annotation.title = location.title
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
map.addAnnotation(annotation)
}
return map
}
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
// start coordinates
let coordinate = CLLocationCoordinate2D(latitude: messpunkt_manager.centerCoordinate.latitude, longitude: messpunkt_manager.centerCoordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: messpunkt_manager.centerZoom.latitudeDelta, longitudeDelta: messpunkt_manager.centerZoom.longitudeDelta)
let region = MKCoordinateRegion(center: coordinate, span: span)
uiView.setRegion(region, animated: true)
// Adds annotation to the map
for location in messpunkt_manager.messpunkte {
let annotation = MKPointAnnotation()
annotation.title = location.title
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
uiView.addAnnotation(annotation)
}
if messpunkt_manager.karteAusgeaehlt == 0 {
uiView.mapType = .standard
}
if messpunkt_manager.karteAusgeaehlt == 1 {
uiView.mapType = .hybrid
}
if messpunkt_manager.karteAusgeaehlt == 2 {
uiView.mapType = .satellite
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
the center coordinates should then be put into this #EnvironmentObject variable
#Published var position = CLLocationCoordinate2D()
thanks for your help!
And sorry for my naming. For me its easier to name the variables, functions ... in my native language German. I hope its not a big deal.
In your class Coordinator you need to set the value. Assuming your coordinator is set up like this:
class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView
init(_ parent: MapView) {
self.parent = parent
}
...
}
Then you would add this function:
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
parent. messpunkt_manager.position = mapView.region
}
It is really helpful to post a Minimal Reproducible Example (MRE). As you can see, you left out an important piece
Here's my code. As soon as I fire up the app in Simulator. I see following messages in the debug window.
2020-05-02 23:01:37.931720-0400 SwiftMapView[42245:6851218] Metal API Validation Enabled
2020-05-02 23:01:38.216200-0400 SwiftMapView[42245:6851218] libMobileGestalt MobileGestalt.c:1647: Could not retrieve region info
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
var locationManager = CLLocationManager()
func setupManager() {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
//locationManager.requestWhenInUseAuthorization()
locationManager.requestAlwaysAuthorization()
// Set Geofencing region
//let locValue:CLLocationCoordinate2D = self.locationManager.location!.coordinate
let locValue:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 15.833826, longitude: 78.845220)
let geofencingRegion: CLCircularRegion = CLCircularRegion(center:locValue, radius: 100, identifier: "Crap")
geofencingRegion.notifyOnExit = true
geofencingRegion.notifyOnEntry = true
// Start monitoring
locationManager.startMonitoring(for: geofencingRegion)
}
func makeUIView(context: Context) -> MKMapView {
setupManager()
let mapView = MKMapView(frame: UIScreen.main.bounds)
//mapView.centerCoordinate = CLLocationCoordinate2D(latitude: 15.833826, longitude: 78.845220)
mapView.showsUserLocation = true
mapView.userTrackingMode = .follow
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
// Show current user location
//uiView.showsUserLocation = true
// Requst location when in use
self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled()
&& (CLLocationManager.authorizationStatus() == .authorizedAlways || CLLocationManager.authorizationStatus() == .authorizedWhenInUse)
{
//self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.locationManager.startUpdatingLocation()
let locValue:CLLocationCoordinate2D = self.locationManager.location!.coordinate
let coordinate = CLLocationCoordinate2D(latitude: locValue.latitude, longitude: locValue.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 0)
let region = MKCoordinateRegion(center: coordinate, span: span)
uiView.setRegion(region, animated: true)
}
}
}
class MapAppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var locationManager: CLLocationManager?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.locationManager = CLLocationManager()
self.locationManager!.delegate = self
return true
}
}
extension MapAppDelegate{
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("Hello World")
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Welcome Home")
}
}
In simulator you have to add a location, then your code works for me (at least if your info.plist is correct):
I'm getting the error:
Type 'NavView' does not conform to protocol 'UIViewRepresentable'
Here is my code. What should I do? Thanks. Using SwiftUI
struct NavView: UIViewRepresentable{
func makeUIView(context: Context) -> NavigationViewController {
var viewController: NavigationViewController
// Define two waypoints to travel between
let origin = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047), name: "Mapbox")
let destination = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House")
// Set options
let options = NavigationRouteOptions(waypoints: [origin, destination])
// Request a route using MapboxDirections.swift
Directions.shared.calculate(options) { (waypoints, routes, error) in
guard let route = routes?.first else { return }
// Pass the generated route to the the NavigationViewController
viewController = NavigationViewController(for: route)
viewController.modalPresentationStyle = .fullScreen
}
return viewController
}
func updateUIView(_ uiView: NavigationViewController, context: Context) {
}
}
For this case it should be used UIViewControllerRepresentable, like below
struct NavView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> NavigationViewController {
var viewController: NavigationViewController
// Define two waypoints to travel between
let origin = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047), name: "Mapbox")
let destination = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House")
// Set options
let options = NavigationRouteOptions(waypoints: [origin, destination])
// Request a route using MapboxDirections.swift
Directions.shared.calculate(options) { (waypoints, routes, error) in
guard let route = routes?.first else { return }
// Pass the generated route to the the NavigationViewController
viewController = NavigationViewController(for: route)
viewController.modalPresentationStyle = .fullScreen
}
return viewController
}
func updateUIViewController(_ uiViewController: NavigationViewController, context: Context) {
}
}