Swift - map returns to starting point - ios

I have a map in my app but when i move the map around, the second I let go, it returns to the starting point. I do not want this to happen..
My ViewController looks like this atm:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (CLLocationManager.locationServicesEnabled())
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
let location = locations.last as CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.map.setRegion(region, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

CLLocationManager's startUpdatingLocation sends updates to the User's location to locationManager:didUpdateLocations:.
Calling this method causes the location manager to obtain an initial location fix (which may take several seconds) and notify your delegate by calling its locationManager:didUpdateLocations: method.
So then in locationManager:didUpdateLocations: the region you're moving the map to with setRegion:animated: is the location that just got sent, i.e., the User's location.

You set the region of your mapView in the didUpdateLocations delegate method.
Once you start to call startUpdatingLocation(), it will start to keep retrieving your location coordinate, and your didUpdateLocations method will be called, and your mapView will be update by the setRegion() in your method.
You can change the value of location manager's distanceFilter to a bigger number, so it will update less frequently. By default, kCLDistanceFilterNone is used, so your didUpdateLocations will be called of all movements.

So it seems like I just had to add locationManager.stopUpdatingLocation() to the didUpdateLocations function

Related

User Interaction is unavailable while mapkit.setRegion is set

import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapKitView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapKitView.delegate = self
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = CLLocationCoordinate2D(latitude: locations[0].coordinate.latitude, longitude: locations[0].coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.001, longitudeDelta: 0.001)
let region = MKCoordinateRegion(center: location, span: span)
mapKitView.setRegion(region, animated: true)
}
}
mapKitView.setRegion(region, animated: true) is blocking User Interaction in mapkit and I can't zooming, scrolling and rotating
It seems from the code that you are trying to keep the map centered on the user's location.
To do this while preserving user interaction it's better to delete the line:
mapKitView.setRegion(region, animated: true)
and instead set the userTrachingMode property on mapKitView to .follow or .followWithHeading.
with this, the map's visible region will follow the user as the location updates.
Here's the documentation of the userTrackingMode property on MKMapView: https://developer.apple.com/documentation/mapkit/mkmapview/1616208-usertrackingmode

Swift 4, Xcode 9: Getting and displaying the user's location

I am trying to get and display the user's location, but the simulator will only load the country I am in. I set up the required info.plist sections (privacy - location when in use and always), linked the mapView in Main.storyoard to the delegate (control-dragged to View Controller Icon), attached the IBOutlet (checked it to make sure it is properly connected) and wrote this code in viewController.swift:
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
mapView.mapType = MKMapType.standard
let location = locations[0]
let myLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: myLocation, span: span)
mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
}
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am just getting my feet wet with MapKit and this issue has been keeping me back for quite some time. Would appreciate any help.
Please use iPhone Device to get the current location. In the simulator, you have to set location then get that location. So can do this easily using the device. Your code will work with the real device.
If you want to test it with simulator the follow https://medium.com/#abhimuralidharan/location-simulation-in-xcode-ff7db9042710

iOS MKMapView Center on User Location and then allow unlimited Scrolling in Swift 3.0

I don't believe this question has been asked yet in Swift 3.0 - three goals:
Upon viewDidLoad the Map Centers to the User Location at a certain zoom level that can be set (for example let span: MKCoordinateSpan = MKCoordinateSpanMake(40.0, 40.0))
Once the map loads and centers on the User Location, the User can then move and scroll the map to any other location WITHOUT the map automatically snapping back to the original User Location
Allow the User to ONLY zoom in to a certain level but allow the User to zoom out fully to view the entire global map (no restrictions on the zoom out level)
Here is my code thus far:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span: MKCoordinateSpan = MKCoordinateSpanMake(40.0, 40.0)
let userLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(userLocation, span)
mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
}
1. Should work with the code you have now.
2. Add check for subsequent location updates
In the didUpdateLocations method, add a Bool to check whether the region was centered on the user already or not.
var regionHasBeenCentered = false
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
if !regionHasBeenCentered {
let span: MKCoordinateSpan = MKCoordinateSpanMake(40.0, 40.0)
let userLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(userLocation, span)
mapView.setRegion(region, animated: true)
regionHasBeenCentered = true
}
self.mapView.showsUserLocation = true
}
Now the map will no longer center on the user after the first update, until you change regionHasBeenCentered back to false. This will allow the user to scroll and zoom freely.
3. Implement MKMapViewDelegate method to detect map region changes
Implement MKMapViewDelegate on your view controller so that you can check for region changes.
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
…and set the view controller as the delegate:
override func viewDidLoad() {
// other things…
mapView.delegate = self
}
Then implement the following method which will be called right before the region changes. Here you can check to see if the span's dimensions are too small, and set them to a minimum appropriate.
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
if mapView.region.span.latitudeDelta <= 40 && mapView.region.span.longitudeDelta <= 40 {
let minimumSpan = MKCoordinateSpan(latitudeDelta: 40, longitudeDelta: 40)
let minimumRegion= MKCoordinateRegion(center: mapView.centerCoordinate, span: minimumSpan)
mapView.setRegion(minimumRegion, animated: false)
}
}
Important note: From the MKCoordinateSpan documentation, the longitudeDelta will change as you move toward/away from the equator.
longitudeDelta
The amount of east-to-west distance (measured in degrees) to display for the map region. The number of kilometers spanned by a longitude range varies based on the current latitude. For example, one degree of longitude spans a distance of approximately 111 kilometers (69 miles) at the equator but shrinks to 0 kilometers at the poles.
Furthermore, MKCoordinateSpan's dimensions are measured in degrees, and 40 degrees is quite a bit so you probably want to change these values, otherwise the user will not be able to zoom in much at all.

update center of screen with current location

I have successfully made an app that shows a blinking blue dot where the user currently is. However as of right now the center of the screen does not follow the blue dot as the user moves, so if the user moves the blue dot just exits the screen and the user would have to scroll to keep up with it. That isnt user friendly! I have the below code:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
let locationManager = CLLocationManager()
var mapp = MKMapView.self
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (CLLocationManager.locationServicesEnabled())
{
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.map.showsUserLocation = true
}
else
{
print("Location services are not enabled")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
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.002, longitudeDelta: 0.002))
self.map.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
}
My only thoughts are that I could get rid of the "stopUpdatingLocation() section and maybe then it would continuously update the region with the new center for every new location, however I am not sure if not having the stopUpdatingLocation is bad practice? Thanks for all advice!
Use userTrackningMode which causes the map view to center the map on that location and begin tracking the user’s location. If the map is zoomed out, the map view automatically zooms in on the user’s location, effectively changing the current visible region.
To use it
mapView.setUserTrackingMode(.follow, animated:true)

Can't display user current location Mapbox iOS API

I want to display user's current location immediately after they open the app. I use Mapbox iOS SDK. But it doesn't work at all. I don't know what's wrong. I can only see an irrelevant map after I open it.
import UIKit
import Mapbox
import CoreLocation
class ViewController: UIViewController, MGLMapViewDelegate, CLLocationManagerDelegate
{
#IBOutlet weak var mapView: MGLMapView!
let locationManager = CLLocationManager()
override func viewDidLoad()
{
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let mapView = MGLMapView(frame: view.bounds)
mapView.userTrackingMode = .Follow
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
mapView.setCenterCoordinate(center, zoomLevel: 15, animated: true)
view.addSubview(mapView)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print ("Errors:" + error.localizedDescription)
}
}
I think the issue might be the iOS Simulator. When you run an app on the simulator, it doesn't simulate your location until you tell it to.
If you look at your Xcode, you'll see a navigate button at the bottom.
Try changing the location to something, and it should show up :)

Resources