Location manager show bad location in gmsMapView swift 4.2 - swift

I have a problem that a I cannot resolve. I'm trying to get the current location to update the mapview and center the camera, but when I close the view controller and init a new Mapviewcontroller the "current location" show a location incorrect, near to my position but not the current location. Can anyone guide me o help me? this is my code:
class MapContainerViewController: UIViewController{
#IBOutlet weak var mapView: GMSMapView!
var locationManager = CLLocationManager()
var myLocation: CLLocation?
var autorizeChange: Bool?
var geofire: GeoFire?
var createGeoforme: Bool?
var INITIAL_CENTER: CLLocation?
var searchCircle: GMSCircle?
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
autorizeChange = true
checkLocationServices()
createGeoforme = false
mapView.delegate = self
// Do any additional setup after loading the view.
}
func setupLocationManager(){
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 100
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.startMonitoringSignificantLocationChanges()
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func checkLocationServices(){
if CLLocationManager.locationServicesEnabled(){
setupLocationManager()
checkLocationAutorization()
} else {
}
}
func checkLocationAutorization(){
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
//Do map stuff
if (mapView.isMyLocationEnabled == false ){
mapView.isMyLocationEnabled = true
mapView.settings.myLocationButton = true
var ref: DatabaseReference
ref = Database.database().reference()
geofire = GeoFire(firebaseRef: ref)
}
break
case .denied:
//Show alert instructing
break
case .notDetermined:
//location manager
locationManager.requestWhenInUseAuthorization()
break
case .restricted:
//Show alert letting them know
break
case .authorizedAlways:
break
default:
}
}
}
}
extension MapContainerViewController: GMSMapViewDelegate{
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition)
{
mapView.clear()
let coordinate = mapView.projection.coordinate(for: mapView.center)
var cooordinate2d = CLLocationCoordinate2D.init(latitude: coordinate.latitude, longitude: coordinate.longitude)
var circ = GMSCircle.init(position: coordinate, radius: zoomLevelToRadius(zoomLevel: Double(position.zoom)))
circ.fillColor = UIColor.init(displayP3Red: 0, green: 255, blue: 255, alpha: 0.15)
circ.strokeColor = UIColor.init(displayP3Red: 0, green: 0, blue: 0, alpha: 0.15)
circ.strokeWidth = 0.5
circ.map = mapView;
}
func zoomLevelToRadius(zoomLevel: Double) -> Double{
// Approximation to fit circle into view
return (16384000/pow(2, zoomLevel))
}
}
extension MapContainerViewController: CLLocationManagerDelegate{
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation: CLLocation = locations[0]
let location = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
mapView.camera = GMSCameraPosition.camera(withTarget: location, zoom: 14)
let centerLocation = mapView.projection.coordinate(for: mapView.center)
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAutorization()
}
}

This sample code can be your solution you can find here https://github.com/SwiftGuides/Google_Place_Picker
This is sample code i wrote for Google place picker to pick exact pin point custom location (not nearby location)
In your case you can apply this too. Just check the example code you will get you solution

Related

Google Maps does not animate to user's location

I am trying to get my google maps map to center on my user's location. The user's location updates properly and shows the blue dot indicating their location. However, the camera, also set to the same coordinate locations, instead places itself at (0, 0). I have modified the program below so that it does move to the proper location after it loads. However, since my Bool is a state variable, it gives me a warning that I cannot update State variables during view updates. See the code below:
import SwiftUI
import GoogleMaps
import GoogleMapsUtils
struct GoogleMapsView: UIViewRepresentable {
#ObservedObject var locationManager = LocationManager()
var marker: GMSMarker = GMSMarker()
#Binding var heatmapWeightedData: [GMUWeightedLatLng]
#State var heatmapLayer = GMUHeatmapTileLayer()
#State var isCenteredOnCamera = false
func makeUIView(context: Context) -> GMSMapView {
let camera = GMSCameraPosition.camera(withLatitude: locationManager.latitude, longitude: locationManager.longitude, zoom: 15)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
heatmapLayer.radius = 75
heatmapLayer.weightedData = heatmapWeightedData
heatmapLayer.map = mapView
mapView.isMyLocationEnabled = true
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: UIViewRepresentableContext<GoogleMapsView>) {
if self.isCenteredOnCamera == false {
mapView.animate(to: GMSCameraPosition(latitude: locationManager.latitude, longitude: locationManager.longitude, zoom: 15))
self.isCenteredOnCamera = true //Gives me the error
}
heatmapLayer.weightedData = heatmapWeightedData
heatmapLayer.map = mapView
}
}
Here is the locationManager code:
import Foundation
import CoreLocation
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
#Published var location: CLLocation? {
willSet { objectWillChange.send() }
}
var latitude: CLLocationDegrees {
return location?.coordinate.latitude ?? 0
}
var longitude: CLLocationDegrees {
return location?.coordinate.longitude ?? 0
}
override init() {
super.init()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
extension LocationManager: CLLocationManagerDelegate {
func locationManager( manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print(status)
}
func locationManager( manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
return
}
self.location = location
}
}
Presumably, the camera is just reading the optional longitude and latitude variables and setting them to 0, for reasons I do not know.
Is there a way for me to update the camera location just once so that it does not infinitely update the camera location? If so, what should I do?

Onchange of variable in class

I have a class such as:
class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
#Published var lastSeenLocation: CLLocation?
#Published var currentPlacemark: CLPlacemark?
#Published var authorizationStatus: CLAuthorizationStatus
private let locationManager: CLLocationManager
override init() {
locationManager = CLLocationManager()
authorizationStatus = locationManager.authorizationStatus
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
func requestPermission() {
locationManager.requestAlwaysAuthorization()
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
authorizationStatus = manager.authorizationStatus
}
}
I'm trying to check if last seen location = cordinates using this code:
let radius: Double = 5 // miles
let userLocation = CLLocation(latitude: locationViewModel.lastSeenLocation?.coordinate.latitude, longitude: locationViewModel.lastSeenLocation?.coordinate.longitude)
let venueLocation = CLLocation(latitude: 51.500909, longitude: -0.177366)
let distanceInMeters = userLocation.distanceFromLocation(venueLocation)
let distanceInMiles = distanceInMeters * 0.00062137
if distanceInMiles < radius {
// user is near the venue
}
The only problem is, that I don't know how to run that code to check constantly. I was thinking .onChange but couldn't figure out how to test for lastSeenlocation in a class. What can I do?
I found a solution here.
For a quick overview:
//I put this code in my LocationViewModel class
func getUserLocation() {
locationManager.startUpdatingLocation()
locationManager.delegate = self
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
print("latitude: \(location.coordinate.latitude), longitude: \(location.coordinate.longitude)")
}
}
//I put this code in my ContentView()
.onAppear {
locationViewModel.getUserLocation()
}
Then it prints your latitude & longitude every time your location changes.

How to Display User's Place on Snippet Google Maps Swift

I have google map and want to display user's place (like city) in snippet.
How to do that?
here's my current code:
class ViewController: UIViewController, GMSMapViewDelegate, CLLocationManagerDelegate{
#IBOutlet weak var mapView: GMSMapView!
var latitude = -7.034323799999999
var longitude = 110.42400399999997
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
mapView.delegate = self
let camera = GMSCameraPosition.camera(withLatitude: Double(latitude), longitude: Double(longitude), zoom: 17)
mapView.animate(to: camera)
let markerImage = UIImage(named: "ic_home_detail_marker_location")
let markerView = UIImageView(image: markerImage)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(Double(latitude), Double(longitude))
marker.isDraggable = true
marker.snippet = "\(marker.position)"
mapView.selectedMarker = marker
marker.iconView = markerView
mapView.selectedMarker = marker
marker.map = mapView
}
}
If you want to get the user's city or state name you have to use CLGeocoder.
var currentLatitude:Double!
var currentLongitude:Double!
var cityName:String!
var stateName:String!
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locationManager function called")
// Fetch current location coordinates
let locValue:CLLocationCoordinate2D = (locationManager.location?.coordinate)!
currentLatitude = locValue.latitude
currentLongitude = locValue.longitude
print("Current Location = \(currentLatitude!), \(currentLongitude!)")
// Zoom to current location
let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: currentLatitude!, longitude: currentLongitude!, zoom: 17.0)
viewMap.camera = camera
// check for current city
CLGeocoder().reverseGeocodeLocation(locationManager.location!, completionHandler: {(placemarks, error) -> Void in
if error != nil {
print("Reverse geocoder failed with error" + (error?.localizedDescription)!)
return
}
if (placemarks?.count)! > 0 {
let pm = placemarks?[0]
self.cityName = (pm?.locality)!
self.stateName = (pm?.administrativeArea)
print("Current City: \(self.cityName!)")
print("Curret State: \(self.stateName!)")
}
else {
print("Problem with the data received from geocoder")
}
})
locationManager.stopUpdatingLocation()
}
Now you have the current city stored in a variable.
The next step is that when the user touches a marker, it should display the cityname. For this to achieve implement this:
This delegate must be added:
GMSMapViewDelegate
and this is the marker function, when user taps on it.
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
mapView.delegate = self
marker.snippet = ("Current city: \(cityName!)")
// return false so as to show the marker details or
// return true to hide marker details.
return false
}

Why the MKPolyline didn't show up in my application?

I am trying to create an application, one of its function is to drawing the line while users are moving.
Here is the class
class traceuserViewController: UIViewController,CLLocationManagerDelegate, MKMapViewDelegate {
var locationManager = CLLocationManager()
var startLocation: CLLocation?
var endLocation: CLLocation?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.locationManager.distanceFilter = 30.0
self.locationManager.startMonitoringSignificantLocationChanges()
self.locationManager.startUpdatingLocation()
mapView.showsUserLocation = true
mapView.mapType = .hybrid
self.mapView.delegate = self
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//user's current location
let nowlocation = locations.last
userLocations.append(nowlocation!)
print("HERE IS THE LOCATION ARRAY")
print(userLocations)
//show the current location region
let center = CLLocationCoordinate2D(latitude: nowlocation!.coordinate.latitude, longitude: nowlocation!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.7, longitudeDelta: 0.7))
self.mapView.setRegion(region, animated: true)
drawRoute(locationArray: userLocations)
}
func drawRoute(locationArray: [CLLocation]) {
if (locationArray.count) > 1 {
var destinationLocIndex = (locationArray.count) - 1
var startLocIndex = (locationArray.count) - 2
let destinationloc = locationArray[destinationLocIndex].coordinate
let startLoc = locationArray[startLocIndex].coordinate
var routeArray = [startLoc, destinationloc]
//test if the function works well or not
print(routeArray)
var geodesicLine = MKGeodesicPolyline(coordinates: routeArray , count: routeArray.count)
mapView.add(geodesicLine, level: .aboveRoads)
}
}
//draw in the mapview
private func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer! {
if overlay is MKPolyline{
let polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blue
polylineRenderer.lineWidth = 5.0
return polylineRenderer
}else{
os_log("Failed to draw the polyline", log: OSLog.default, type: .debug)
return nil
}
}
After many times trying, I still have no idea why it doesn't draw the route on the map when the user is moving, can anyone please I've me some hints?
cheers
I'm inferring that you are using Swift 3 from the code snippet (e.g. the signature of didUpdateLocations; the use of .hybrid rather than Swift 2.3's .Hybrid; etc.).
But, the signature for mapView(_:rendererFor:) is incorrect. In Swift 3, it is:
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
...
}
If you ever have a delegate method that doesn't appear to work, add a breakpoint in it and you can confirm if it's called at all or not (and if it is called, you can step through it and diagnose the problem further).

Location Manager not work in simulator But run in Iphone properly

App runs in iPhone but when i am trying to run in simulator its shows error as given in image
please help me & thank you in advanced
// THIS IS MY CODE:
locationManager.delegate = self
var locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.Authorized)
{
let latitude1 = locManager.location!.coordinate.latitude.description
latitude = latitude1
let longitude1 = locManager.location!.coordinate.longitude.description
longnitude = longitude1
print(latitude)
print(longnitude)
} else {
latitude = ""
longnitude = ""
}
Try this code: Tested in Xcode simulator(Swift 3)
Update your plist:
Privacy - Location When In Use Usage Description == Some Value
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
print(location)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)
{
print("Errors: " + error.localizedDescription)
}
}
Output from the code:
You'll have to import the framework as
import CoreLocation