This is how I init the map - GMSMapView
class ViewController: UIViewController {
var map = GMSMapView()
override func viewDidLoad() {
super.viewDidLoad()
setupGoogleView()
}
private func setupGoogleView() {
guard let coordinates = getUserLocation() else { return }
let camera = GMSCameraPosition.camera(withLatitude: coordinates.latitude, longitude: coordinates.longitude, zoom: 16.0)
self.map = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
map.settings.tiltGestures = false
map.mapType = .satellite
map.delegate = self
map.frame = view.frame
self.view.addSubview(map)
}
}
The problem comes when I call this function from somewhere else in the file
private func animateTo(location: CLLocationCoordinate2D) {
DispatchQueue.main.async {
let cameraPosition = GMSCameraPosition(target: location, zoom: 20)
self.map.animate(toLocation: location)
self.map.animate(to: cameraPosition)
}
}
I am trying to relocate the camera to some coordinates, but nothing happens.
I have tried every solution on stackoverflow and google.
I have lat and lng in the location - checked. The function is called - checked.
I have also tried to self.view.layoutSubviews(), self.view.layoutIfNeeded(), and also for map
try to use CLLocationManagerDelegate
// Handle authorization for the location manager.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .restricted:
print("Location access was restricted.")
case .denied:
print("User denied access to location.")
// Display the map using the default location.
mapView.isHidden = false
case .notDetermined:
print("Location status not determined.")
case .authorizedAlways: fallthrough
case .authorizedWhenInUse:
print("Location status is OK.")
getFilialList()
#unknown default:
fatalError()
}
}
then
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Location: \(location)")
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: 12)
DispatchQueue.main.async {
self.mapView.animate(to: camera)
self.locationManager.stopUpdatingLocation()
}
}
I manage to solve the issue with this:
self.view.subviews.forEach { (view) in
if let mapView = view as? GMSMapView {
// do update on mapView here
}
}
Related
I am using location.requestLocation in swift 5 for my ios app. But its taking way too long time. around 10 seconds. searching for solutions online, they are saying use startUpdatingLocation instead..but problem is I only want it once... not continuous update. I am also not interested in it being accurate.I can have it wrong by some margin.
Because all I want is just zoom to my google map position, and sort stuff by distance using user location. Location can be wrong up to 3 - 4 Kilometers I have no problem.
override func viewDidLoad() {
super.viewDidLoad()
//mapView.showsUserLocation = false
locationManager.delegate = self
print(locationManager.distanceFilter)
switch CLLocationManager.authorizationStatus() {
case CLAuthorizationStatus.notDetermined, .restricted, .denied:
locationManager.requestWhenInUseAuthorization()
case CLAuthorizationStatus.authorizedWhenInUse, .authorizedAlways:
requestLocation()
#unknown default: break
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print("\nStart of locationManager(didChangeAuthorization)")
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == CLAuthorizationStatus.authorizedWhenInUse
|| authStatus == CLAuthorizationStatus.authorizedAlways {
requestLocation()
}
print("\nEnd of locationManager(didChangeAuthorization)")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("\nStart of locationManager(didUpdateLocations)")
zoomInLocation(locations.last!)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
if let err = error as? CLError, err.code == .denied {
manager.stopUpdatingLocation()
return
}
print("\nlocationManager(): \(error.localizedDescription)")
}
private func requestLocation() {
print("\requestLocation() called")
// check if the location service is availalbe on that device
if !CLLocationManager.locationServicesEnabled() {
return
}
locationManager.requestLocation()
}
private func zoomInLocation(_ location: CLLocation) {
loca2 = location
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: 6.0)
(view1 as! GMSMapView).animate(to: camera)
print("\nzoomInUserLocation(): mapView[latitude]=\(location.coordinate.latitude), locationManager[latitude]=\(String(describing: location.coordinate.latitude))")
let coordinateSpan = MKCoordinateSpan(latitudeDelta: 20, longitudeDelta: 20)
_ = MKCoordinateRegion(center: location.coordinate, span: coordinateSpan)
// mapView.centerCoordinate = location.coordinate
//mapView.setRegion(coordinateRegion, animated: true)
if(i1 != 0){
self.sortByDistance()
}
}
I am trying to show on my current location and a blue dot on the map using the map view on swift. However it does not show my location nor the blue dot I'm very positive of my code but I can't get it to show! it's probably an issue with the settings?
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
let regionInMeters: Double = 1000
override func viewDidLoad() {
super.viewDidLoad()
checkLocationServices()
}
func setupLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func centerViewOnUserLocation() {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
mapView.setRegion(region, animated: true)
}
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
setupLocationManager()
checkLocationAuthorrization()
} else {
// Show alert letting the user know they have to turn this on.
}
}
func checkLocationAuthorrization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
centerViewOnUserLocation()
locationManager.startUpdatingLocation()
break
case .denied:
// Show alret instructing them how to turn on permissions
break
case .notDetermined:
break
case .restricted:
// Show alret letting them know what's up
break
case .authorizedAlways:
break
}
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion.init(center: center, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
mapView.setRegion(region, animated: true)
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorrization()
}
}
You have to add below permission in Info.plist file
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Usage Description</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Usage Description</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Usage Description</string>
Import libraries:
import MapKit
import CoreLocation
Set delegates:
CLLocationManagerDelegate,MKMapViewDelegate
Add variable:
private var locationManager: CLLocationManager!
private var currentLocation: CLLocation?
write below code on viewDidLoad():
mapView.delegate = self
mapView.showsUserLocation = true
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
// Check for Location Services
if CLLocationManager.locationServicesEnabled() {
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
Write delegate method for location:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
defer { currentLocation = locations.last }
if currentLocation == nil {
// Zoom to user location
if let userLocation = locations.last {
let viewRegion = MKCoordinateRegion(center: userLocation.coordinate, latitudinalMeters: 2000, longitudinalMeters: 2000)
mapView.setRegion(viewRegion, animated: false)
}
}
}
Thats all, Now you able to see your current location and blue dot.
To show user location on map do following steps:
try this path-
Go to product->Edit Scheme->Options->select Allow Location simulation and select default location.
Here You can also add custom location using GPX file.
After setting clean and run the app.
The problem seems to be in method checkLocationAuthorrization, here you have to ask for locationManager.requestWhenInUseAuthorization() when the status is notDetermined, like so:
func checkLocationAuthorization(authorizationStatus: CLAuthorizationStatus? = nil) {
switch (authorizationStatus ?? CLLocationManager.authorizationStatus()) {
case .authorizedAlways, .authorizedWhenInUse:
locationManager.startUpdatingLocation()
mapView.showsUserLocation = true
case .restricted, .denied:
// show alert instructing how to turn on permissions
print("Location Servies: Denied / Restricted")
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
}
}
Also change the delegate method to pass the current status received
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
self.checkLocationAuthorization(authorizationStatus: status)
}
Also note that locationManager.requestWhenInUseAuthorization() will not work, if Info.plist does not have following usage description(s), so edit the Info.plist file and make sure:
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Message for AlwaysAndWhenInUseUsageDescription</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Message for AlwaysUsageDescription</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Message for WhenInUseUsageDescription</string>
Finally, you got to wait for an location update to call centerViewOnUserLocation, like so
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.setRegion(region, animated: true)
}
Simulator doesn't show current location but you can manually add a location in it by:
Debug -> Location -> Custom Location and then give coordinates.
In your viewDidLoad method please write the below code.
Default value of showsUserLocation is false. So, we have to update it's default value.
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.showsUserLocation = true
checkLocationServices()
}
Refer my updated code.
import UIKit
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapview: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let location = CLLocationCoordinate2D(latitude: "", longitude: "")
let span = MKCoordinateSpanMake(0.5, 0.5)
let region = MKCoordinateRegion(center: location, span: span)
mapview.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "your title"
mapview.addAnnotation(annotation)
}
I have been looking at the google documentation to get the current location, but i am struggling to specify the location in the ViewDidLoad, as you can see i have set the Location fixed to Syndey Australia. In the google doc documentation when specifying the current location, they are using the "default location.coordinate" , i cannot access defaultLocation.coordinate in my code .
here is a link to the documenation : https://developers.google.com/maps/documentation/ios-sdk/current-place-tutorial
this is the code inside the viewDidLoad
GMSServices.provideAPIKey("AIzaSyARsPfNs54hrUAC4yKtHeu2jXfGjeA0b-E")
GMSPlacesClient.provideAPIKey("AIzaSyARsPfNs54hrUAC4yKtHeu2jXfGjeA0b-E ")
let camera = GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 6.0)
mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
view = mapView
// creating the marker //
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: -33.86, longitude: 151.20)
marker.title = "Sydney"
marker.snippet = "Australia"
marker.map = mapView
This is my extenstion code
extension MapsViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location : CLLocation = locations.last!
print("Location:\(location)")
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: zoomLevel)
if mapView.isHidden {
mapView.isHidden = false
mapView.camera = camera
}
else {
mapView.animate(to: camera)
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .restricted:
// display the map the default location
mapView.isHidden = false
case .denied :
print("User denied access to location")
mapView.isHidden = false
case .notDetermined :
print("Location status not deteremined")
case .authorizedAlways : fallthrough
case . authorizedWhenInUse :
print("Location status is OK")
}
}
You have added wrong code in your method searchLocationPressed, Please update it as follow.
#IBAction func searchLocationPressed(_ sender: UIBarButtonItem) {
let autocomplete = GMSAutocompleteViewController()
autocomplete.delegate = self
self.present(autocomplete, animated: true, completion: nil)
}
Your mistake is you are presenting UISearchController instead of GMSAutocompleteViewController.
i have a maps to show current location using google maps sdk. the maps setup is in this code
override func viewDidAppear(_ animated: Bool) {
if CLLocationManager.locationServicesEnabled() {
startMonitoringLocation()
addCurrentLocationMarker()
}
}
func startMonitoringLocation() {
if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.activityType = CLActivityType.automotiveNavigation
locationManager.distanceFilter = 1
locationManager.headingFilter = 1
locationManager.requestWhenInUseAuthorization()
locationManager.startMonitoringSignificantLocationChanges()
locationManager.startUpdatingLocation()
}
}
func stopMonitoringLocation() {
locationManager.stopMonitoringSignificantLocationChanges()
locationManager.stopUpdatingLocation()
}
func addCurrentLocationMarker() {
currentLocationMarker?.map = nil
currentLocationMarker = nil
if let location = locationManager.location {
currentLocationMarker = GMSMarker(position: location.coordinate)
currentLocationMarker?.icon = #imageLiteral(resourceName: "GeolocalizacioĢn")
currentLocationMarker?.map = mapView
currentLocationMarker?.rotation = locationManager.location?.course ?? 0
}
}
func zoomToCoordinates(_ coordinates: CLLocationCoordinate2D) {
let camera = GMSCameraPosition.camera(withLatitude: coordinates.latitude, longitude: coordinates.longitude, zoom: 14)
mapView.camera = camera
}
//MARK:- Location Manager Delegate
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("location manager erroe -> \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
break
case .restricted:
break
case .denied:
stopMonitoringLocation()
break
default:
addCurrentLocationMarker()
startMonitoringLocation()
break
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("location update")
if let lastLocation = locations.last {
currentLocationMarker?.position = lastLocation.coordinate
currentLocationMarker?.rotation = lastLocation.course
self.zoomToCoordinates(lastLocation.coordinate)
self.stopMonitoringLocation()
}
}
so when i select a place using places autocomplete i want to show a a marker in that position, the camera moves to the places but then returns to the currente location. the places complete code to show the new marker is this.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
// print("Place name: \(place.name)")
// print("Place address: \(place.formattedAddress)")
// print("Place attributions: \(place.attributions)")
if punto1{
print("is text1")
punto1Text.text = place.formattedAddress
punto1Cordinate = place.coordinate//place.viewport?.southWest
let newMarker = GMSMarker(position: punto1Cordinate!)
newMarker.icon = UIImage(named: "desde")
newMarker.map = self.mapView
self.mapView.animate(toLocation: punto1Cordinate!)
self.mapView.camera = GMSCameraPosition.camera(withTarget: punto1Cordinate!, zoom: 14.0)
//self.zoomToCoordinates(punto1Cordinate!)
if punto2Cordinate != nil{
self.drawPath(origin: "\(punto1Cordinate!.latitude),\(punto1Cordinate!.longitude)", destination: "\(punto2Cordinate!.latitude),\(punto2Cordinate!.longitude)")
let mapsBound = GMSCoordinateBounds(coordinate: punto1Cordinate!, coordinate: punto2Cordinate!)
//self.mapView.camera(for: mapsBound, insets: <#T##UIEdgeInsets#>)
// self.mapView.cameraTargetBounds = mapsBound
self.mapView.animate(with: GMSCameraUpdate.fit(mapsBound, withPadding: 120.0))
}
}else{
print("is text2")
punto2Text.text = place.formattedAddress
punto2Cordinate = place.coordinate//viewport?.southWest
let newMarker = GMSMarker(position: punto2Cordinate!)
newMarker.icon = UIImage(named: "hasta")
newMarker.map = self.mapView
if punto1Cordinate != nil {
self.drawPath(origin: "\(punto1Cordinate!.latitude),\(punto1Cordinate!.longitude)", destination: "\(punto2Cordinate!.latitude),\(punto2Cordinate!.longitude)")
let mapsBound = GMSCoordinateBounds(coordinate: punto1Cordinate!, coordinate: punto2Cordinate!)
//self.mapView.camera(for: mapsBound, insets: <#T##UIEdgeInsets#>)
// self.mapView.cameraTargetBounds = mapsBound
self.mapView.animate(with: GMSCameraUpdate.fit(mapsBound, withPadding: 120.0))
//self.mapView.camera = GMSCameraPosition.
}
}
dismiss(animated: true, completion: nil)
}
when there are two points the camera must center in the route between the two points but no way that camera move.
i have stoped updating location with this funtion in.
func textFieldDidBeginEditing(_ textField: UITextField) {
self.stopMonitoringLocation()
if textField == punto1Text{
punto1 = true
}else{
punto1 = false
}
self.servicioOrigen.isHidden = true
self.servicioHoras.isHidden = true
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.delegate = self
let filter = GMSAutocompleteFilter()
filter.country = "es"
//filter.
//filter.type = .region
//filter.type = .address
autocompleteController.autocompleteFilter = filter
present(autocompleteController, animated: true, completion: nil)
}
if location is disable then in the firstPoint the animation is working, and after add the second point i have to move the map to make it center in the route, but is device location is on then no way the camera get focus on the selected location.
i'm a beginner in developing an i'm adding a google map on a view of my application, following a tutorial i used this code
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Location: \(location)")
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: zoomlevel)
let marker = GMSMarker()
marker.title = "My Position"
marker.map = mapView
if mapView.isHidden {
mapView.isHidden = false
mapView.camera = camera
} else {
mapView.animate(to: camera)
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .restricted:
print("Location access was restricted.")
case .denied:
print("User denied access to location.")
mapView.isHidden = false
case .notDetermined:
print("Location status not determined.")
case .authorizedAlways: fallthrough
case .authorizedWhenInUse:
print("Location status is OK.")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationManager.stopUpdatingLocation()
print("Error: \(error)")
}
to find the user location, now i would like to see on the map the places (google places) that are on a X distance from the user position, how can i do it? i searched on the google places doc but not find a valid answer
Add another marker onTap on mapView and make it draggable and use CLLocationDistance to measure distance between 2 locations.
let distanceInMeters = self.locationManager.location?.distance(from: newMarkerLocation!)