Google Maps iOS SDK Prevent camera zoom after each location update - ios

I have an app which requires the user's location to be constantly updated so I can display their current coordinates and altitude. I'm doing this using the didUpdateLocations function:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
mapView.camera = GMSCameraPosition(target: locationManager.location!.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
let locValue : CLLocationCoordinate2D = manager.location!.coordinate
let altitude : CLLocationDistance = Double(round(1000*manager.location!.altitude)/1000)
let long = Double(round(10000*locValue.longitude)/10000)
let lat = Double(round(10000*locValue.latitude)/10000)
let alt = String(altitude) + " m"
latitudeLabel.text = String(lat)
longitudeLabel.text = String(long)
altitudeLabel.text = alt
showLearningObjectsWithinRange(location)
}
}
The problem is, when I try to zoom in on a certain spot on the map, if I move the device even slightly the camera zooms back out again. Obviously this is because of the first line in my didUpdateLocations function setting the camera position, but if I remove that line, the map doesn't center to their location at all.
I tried moving the GMSCameraPosition code to the viewDidLoad, viewWillAppear, and several other places, but this caused the app to crash because it couldn't locate the user in time.
Does anyone have any suggestions on how to make this work? Thanks.

use this instead of that certain line (mapview.camera = ...)
mapView.animate(toLocation: CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude))

With regards to implementing location update, there was an issue posted in GitHub - Implement Responsive User Location Tracking Mode due to location update optimization and going through the thread, a given workaround to show the user location on the map is to call
nMapView.setMyLocationEnabled(true);
instead of:
nMapView.setMyLocationTrackingMode(MyLocationTrackingMode.TRACKING_FOLLOW);
Then, with regards to camera zoom, as discussed in Camera and View - Zoom, you can try setting a minimum or maximum zoom to restrict zoom level. As stated,
You can restrict the range of zoom available to the map by setting a min and max zoom level.
You may also try the solutions given in this SO post - Google Maps iOS SDK, Getting Current Location of user. Hope it helps.

Related

Current location issue in ArcGIS Maps in iOS

I'm developing an application in which I have a map. I'm using ArcGIS SDK for showing map. Here I'm trying to show my current location when the map loads. I have passed my latitude and longitude to the x and y parameters of the ArcGIS function. This is the code for that function,
let lat = gpsLocation.location?.coordinate.latitude
let lng = gpsLocation.location?.coordinate.longitude
print(lat)
print(lng)
//zoom to custom view point
self.mapView.setViewpointCenter(AGSPoint(x: lat!, y: lng!, spatialReference: AGSSpatialReference.webMercator()), scale: 4e7, completion: nil)
self.mapView.interactionOptions.isMagnifierEnabled = true
But when I run the app it shows the wrong location in the map. It points to the wrong location. I have printed the lat and lng also. They are correct but the display of location is wrong in the map. How can I get the map to load my current location?
This is what it shows location when loads,
You're using latitude and longitude, i.e. a number of degrees (probably in WGS 1984), but then you're telling ArcGIS that they are in Web Mercator, i.e. a number of meters. That will definitely cause the behavior you see.
To fix it, simply replace webMercator() with WGS84().
Also, you are mixing up latitude and longitude. Latitude is y and longitude is x, and you have it the other way around.
In summary, replace your setViewpointCenter call with this:
self.mapView.setViewpointCenter(
AGSPoint(x: lon!, y: lat!, spatialReference: AGSSpatialReference.WGS84()),
scale: 4e7,
completion: nil
)

GMS Map View always showing Europe

I'm trying to use Google Maps SDK to display a map of my current location (Berkeley, CA) as the focus, but regardless of what lat/lon I put in, it always shows Europe, as shown below:
Here is the code for the map view:
let camera = GMSCameraPosition.cameraWithLatitude(37.8750360, longitude: -122.2573240, zoom: 1)
mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
mapView.myLocationEnabled = true
mapView.delegate = self
I'm doing very similar things in other parts of my application, but have never gotten an issue. If someone knows how to fix this, please let me know! Thanks
Please make sure that you are test on real device. not be Simulator,
If you use Simulator than enter latitude and longitude manually.
Like this-
You can test is on simulator as well and you can change location without enter lat-long
for that you need to change location from your Xcode (above console Please rifler the below screen shot
)
Maybe this is because you are setting the mapView's frame to CGRectZero. This may cause the map to have zero height and zero width.
Example based from this tutorial:
override func viewDidLoad()
{
let camera: GMSCameraPosition = GMSCameraPosition.cameraWithLatitude(37.8750360, longitude: -122.2573240, zoom: 1)
mapView = GMSMapView.mapWithFrame(self.view.frame, camera: camera)
mapView.camera = camera
}
Check these related questions:
Current Location in Google Maps with swift
Show GoogleMaps on View in Swift?
You're setting up your view before even setting your delegate (so your code isn't even attached to your instance of mapView). Fix it like this:
1: Make sure you've defined your GMSMapViewDelegate for the class
2: Set your delegates first
mapView.delegate = self
mapView.myLocationEnabled = true
let camera = GMSCameraPosition.cameraWithLatitude(37.8750360, longitude: -122.2573240, zoom: 1)
mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)

Custom user location dot in Google maps for iOS (GMSMapview)

Is there an official way to set a custom user location dot in Google maps for iOS (GMSMapView)?
Is there a known way to "hack" it? Like iterating through all subviews and layers and fish the blue dot?
Even if you can't customise its appearance, can you control its z order index? When you have many markers, the little blue dot becomes hidden, and sometimes you want it to be visible at all times.
Thanks
You can try to find the image on:
GoogleMaps.framework > Resources > GoogleMaps.bundle
OR
GoogleMaps.framework > Resources > GoogleMaps.bundle > GMSCoreResources.bundle
I did a quick search on those and the only associated file I found with that blue dot is GMSSprites-0-1x.
Please read the google maps terms and conditions because this might not be legal.
You can set the maps myLocationEnabled to NO. That will hide the default location dot. Then use an instance of CLLocationManager to give you your position. Inside CLLocationManager didUpdateLocations method you can set a custom GMSMarker. Set its icon property to whatever you want your dot to look like using [UIImage imageNamed:]. This will allow you to achieve the desired effect.
Swift 4
Disable the default Google Map current location marker (it's disabled by default):
mapView.isMyLocationEnabled = false
Create a marker as an instance property of the view controller (because a delegate will need access to this):
let currentLocationMarker = GMSMarker()
The GMSMarker initializer allows for a UIImage or a UIView as a custom graphic, not a UIImageView unfortunately. If you want more control over the graphic, use a UIView. In your loadView or viewDidLoad (wherever you configured the map), configure the marker and add it to the map:
// configure custom view
let currentLocationMarkerView = UIView()
currentLocationMarkerView.frame.size = CGSize(width: 40, height: 40)
currentLocationMarkerView.layer.cornerRadius = 40 / 4
currentLocationMarkerView.clipsToBounds = true
let currentLocationMarkerImageView = UIImageView(frame: currentLocationMarkerView.bounds)
currentLocationMarkerImageView.contentMode = .scaleAspectFill
currentLocationMarkerImageView.image = UIImage(named: "masterAvatar")
currentLocationMarkerView.addSubview(currentLocationMarkerImageView)
// add custom view to marker
currentLocationMarker.iconView = currentLocationMarkerView
// add marker to map
currentLocationMarker.map = mapView
All that remains is giving the marker a coordinate (initially and every time the user's location changes), which you do through the CLLocationManagerDelegate delegate.
extension MapViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let lastLocation = locations.last!
// update current location marker
currentLocationMarker.position = CLLocationCoordinate2D(latitude: lastLocation.coordinate.latitude, longitude: lastLocation.coordinate.longitude)
}
}
The first few locations that the location manager produces may not be very accurate (although sometimes it is), so expect your custom marker to jump around a bit at first. You can wait until the location manager has gathered a few coordinates before applying it to your custom marker by waiting until locations.count > someNumber but I don't find this approach very attractive.

MKMapView not staying rotated

Easy to reproduce:
- create a new project
- put an MKMapView on the screen
- try to rotate it with 2 fingers
It rotates a little and stops, and when you release the fingers, it goes back to the original position.
How do I make it stay rotated?
And rotate as much as I want?
I'm using latest iOS (8.something), iPhone 6 simulator and Swift.
I figured out the problem.
Actually there is no solution, what was happening is that MKMapView does not allow you to stay rotated if the map region is too big.
If you zoom in you can rotate normally.
Please try this
Gloabally declare :
let regionRadius: CLLocationDistance = 1000
And in viewdidload:
let initialLocation = CLLocation(latitude: 21.282778, longitude: -157.829444)
centerMapOnLocation(initialLocation)
And then create a helper class:
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapview.setRegion(coordinateRegion, animated: true)
}
Try with rotateEnabled property of MKMapView :
rotateEnabled -
A Boolean value indicating whether the map camera’s heading information is used.
Declaration
SWIFT
var rotateEnabled: Bool
When this property is set to YES and a valid camera is associated with the map, the camera’s heading angle is used to rotate the plane of the map around its center point. When this property is set to NO, the camera’s heading angle is ignored and the map is always oriented so that true north is situated at the top of the map view.
You have to override CLLocationManager.didUpdateLocations (part of CLLocationManagerDelegate) to get notified when the location manager retrieves the current location and don't do anything there:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
// Don't do update the map to the new location
}

Take an action if MapKit Map has zoomed into users location

I am using this to zoom into the users location at startup.
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) {
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
var newRegion = MKCoordinateRegion(center: coord, span: MKCoordinateSpanMake(spanX, spanY))
mapView.setRegion(newRegion, animated: true)
}
Now I'd like to take an action if the map has been zoomed into the users location. I've tried to use the mapDidChange delegate method, but this is fired a few times. Any thoughts how to do this the clever way? (iOS 8 / Swift)
Just In my opinion , you can compare newRegion's span values with map view's current span values in regionDidChangeAnimated. If span values are the same, you can secondly play with "mapview.region". May be getting visible mapView.region and comparing it with newRegion or getting centre coordinate of current visible region and comparing it with current location's coordinate can work.

Resources