Here's my code, that works but it doesn't get updated and it's not accurate. I simply want to apply the camera lat and lng to another variable.
let cameraLat = self.mapView.camera.centerCoordinate.latitude
let cameraLng = self.mapView.camera.centerCoordinate.longitude
for google maps:
if you have set the mapView.delegate = self and you have implemented the GMSMapViewDelegate it's pretty easy to get the an event everytime the camera changes, so you mapView view changes.
you could either implement the func mapView(mapView: GMSMapView, didChangeCameraPosition position: GMSCameraPosition) or func mapView(mapView: GMSMapView, idleAtCameraPosition position: GMSCameraPosition) method.
and then access the new camera values (lat/lng) like you did before, so just reassign your variables to the new values.
or MapKit:
add delegate to class like
class ViewController: UIViewController, MKMapViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
...
mapView.delegate = self
}
}
This method is called whenever the currently displayed map region changes. During scrolling, this method may be called many times to report updates to the map position. Therefore, your implementation of this method should be as lightweight as possible to avoid affecting scrolling performance.
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let lat = mapView.camera.centerCoordinate.latitude
let lng = mapView.camera.centerCoordinate.longitude
}
Related
I have a MKMapView that has annotations. My goal is to hide the annotation, if one is selected, when the map finished scrolling.
When an annotation is called I assign the annotation into a variable to keep track of it.
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
lastSelectedAnnotation = view.annotation
}
I know of:
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool){ }
However, I cannot figure out (beginner here), how to detect that the map finished changing its region so I can call my function:
func hideSelectedAnnotation(_ mapView: MKMapView) {
DispatchQueue.main.async {
mapView.deselectAnnotation(self.lastSelectedAnnotation, animated: true)
self.lastSelectedAnnotation = nil
}
}
I hide the annotation also when an accessory button is tapped:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl){
hideSelectedAnnotation(mapView)}
I have tried saving the coordinate of the region, and comparing them to the map but the map does not neccessarily center the annotation. I could also start a timer and when regionDidChangeAnimated is no longer called hide the annotation. But that seams like butchering it.
Thanks for any help!
I think you already figured it out...
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool){
// Call your function here
}
Should fire every time the map view region changes (unless the change was inflicted by the user's finger)
----- EDIT -----
Unfortunately, you have to detect user input using a UIPanGestureRecognizer.
I have used, with success, A UIPanGestureRecognizer like the following:
lazy var mapPanGestureRecognizer: UIPanGestureRecognizer = {
let gr = UIPanGestureRecognizer(target: self, action: #selector(draggedMap))
gr.delegate = self
return gr
}()
You will also have to add the UIPanGestureRecognizer to the map with
yourMap.addGestureRecognizer(mapPanGestureRecognizer)
You can then manage what happens in the #selector function by checking the state of the gesture, like so
#objc func draggedMap(panGestureRecognizer: UIPanGestureRecognizer) {
// Check to see the state of the passed panGestureRocognizer
if panGestureRecognizer.state == UIGestureRecognizer.State.began {
// Do something
}
}
The state is what allows you to determine if the user ended a gesture, is in the middle of a gesture, or began a gesture.
List of possible states
The blue dot does not appear on the map. It appears there is some disconnect between the CLLocation manager and the self.mapView.userLocation.coordinate value.
The CLLocation manager correctly returns the Apple Campus coordinates, but the mapView.userLocation.coordinate value returns 0,0 for both latitude and longitude.
I have debugged this for hours and hours.
More Information Below:
In viewDidAppear and viewDidLoad, I printed the user's current location to the console as follows:
print(self.mapView.userLocation.coordinate)
This is the output that is rendered in the console:
CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
This is what my MapViewController looks like:
import UIKit
import CoreLocation
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var manager: CLLocationManager? = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// map stuff
manager?.delegate = self
manager?.desiredAccuracy = kCLLocationAccuracyBest
self.mapView.delegate = self
// print user's current location to console
print("user location in view did load:")
print(self.mapView.userLocation.coordinate)
}
override func viewDidAppear(_ animated: Bool) {
manager?.requestAlwaysAuthorization()
manager?.startUpdatingLocation()
self.mapView.showsUserLocation = true
self.mapView.userTrackingMode = .follow
// print user's current location to console
print("user location in view did appear:")
print(self.mapView.userLocation.coordinate)
animateMapToUserLocation()
}
}
Notes:
I have added the relevant Privacy messages to the Info.plist file.
The MapView in the storyboard is connected, with a solid circle, to the correct ViewController.
The MapViewController is instantiated as follows:
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let mapVC = storyboard.instantiateViewController(withIdentifier: "MapVC") as? MapViewController
self.present(mapVC!, animated: true, completion: nil)
Have you implemented the viewForAnnotation function? are you checking that you're not drawing (or failing to draw) a different sort of pin for the MKUserLocation?
e.g.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
...
}
Check also Settings > Privacy > Location Services > Your app
My control flow was off. The map would render before the app had permission to retrieve the user location. It is working now.
I'm using google map and I set markers to my map like this:
var marker = GMSMarker(position: CLLocationCoordinate2D(latitude: Double(item.lat)!, longitude: Double(item.lon)!))
marker.map = mapview
now,I would like to detect when user click on these markers.
How can I do?
you should set your mapview delegate to self UIViewController in viewDidLoad
self.mapview.delegate = self
your UIViewController should
extension ViewControllerClass: GMSMapViewDelegate {
//class code
#objc(mapView:didTapMarker:) func mapView(_: GMSMapView, didTap marker: GMSMarker) -> Bool {
//do something
return true
}
}
maybe this method can be implemented some other way already, but Xcode forced me to make it this way while migrating from Swift 2 to Swift 3
For Swift 3
You can implement GMSMapViewDelegatesomething like this:
extension YourViewConytoller: GMSMapViewDelegate {
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print ("MarkerTapped Locations: \(marker.position.latitude), \(marker.position.longitude)")
return true
}
}
I want to add and remove Marker(pin) in Google Maps.
I want to drop pin with long touch and remove it. I want to use it to select my destination. How can I do it?
let position = CLLocationCoordinate2DMake(10, 10)
let marker = GMSMarker(position: position)
marker.map = mapView
For the ones who're looking for a complete code snippet using Swift:
Implement Protocol GMSMapViewDelegate
Drag an Instance of GMSMapView #IBOutlet weak var googleMapView: GMSMapView!
Mention GMSMapView Delegate within viewDidLoad() as googleMapView.delegate = self
Implement the didTapAt delegate function:
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D){
print("You tapped at \(coordinate.latitude), \(coordinate.longitude)")
googleMapView.clear() // clearing Pin before adding new
let marker = GMSMarker(position: coordinate)
marker.map = googleMapView
}
This code should help you!
//MARK: GMSMapViewDelegate Implimentation.
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
plotMarker(AtCoordinate: coordinate, onMapView: mapView)
}
//MARK: Plot Marker Helper
private func plotMarker(AtCoordinate coordinate : CLLocationCoordinate2D, onMapView vwMap : GMSMapView) {
let marker = GMSMarker(position: coordinate)
marker.map = vwMap
}
PS: Dont forget to confirm to GMSMapViewDelegate in ViewController and assign googleMap.delegate = self somewhere in viewDidLoad()
Hope that helps!
I'm trying to find the latitude and longitude of the user's location so that I can center the map on the user in viewdidload.
I've implemented what seems to be the right code but the values of userLat (latitude) and userLon (longitude) are way off.
N.B. Somebody else had the same problem as me but his answer was never resolved:
Mapbox iOS8 Swift mapView.showUsersLocation
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate, CLLocationManagerDelegate {
// let locationManager = CLLocationManager()
#IBOutlet weak var mapView: MGLMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Initalise map's center coordinate as vancouver
mapView.setCenterCoordinate(CLLocationCoordinate2D(latitude: 49.283382,
longitude: -123.117394),
zoomLevel: 15, animated: false)
view.addSubview(mapView)
// Set the delegate property of our map view to self after instantiating it.
mapView.delegate = self
// User location
mapView.showsUserLocation = true
let userLoc = mapView.userLocation!
userLoc.title = "Hello"
userLoc.subtitle = "I am here!"
let userLat = userLoc.coordinate.latitude
let userLon = userLoc.coordinate.longitude
print(userLat, userLon)
/*
self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}*/
}
func mapView(mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
}
Resulting print:
3.40282346638529e+38 3.40282346638529e+38
The strange thing is that the annotation works fine, and when I click my location I get the title and subtitle.
The easiest way to center the map on the user's location is to set MGLMapView.userTrackingMode = .follow (MGLUserTrackingModeFollow in Objective C). This will automatically move the map when a location is available.
The reason why you're seeing bogus numbers for MGLMapView.userLocation is that the user's location typically isn't available yet in viewDidLoad. Use the mapView:didUpdateUserLocation: delegate method to be notified when the user's location becomes available and when it updates.
There is a delegate method called mapViewDidFinishLoadingMap. Set the center of the map to the user coordinates in this method.
func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {
mapView.setCenter((mapView.userLocation?.coordinate)!, animated: false)
}