For some reason my market won't zoom to the local region. In fact, it does not change the zoom no matter what I change. Am I loading it in the wrong part of the code, or am I missing something else? Any help is appreciated.
My code is:
#IBOutlet var here: MKMapView!
var locationManager: CLLocationManager?
var selectedItem: String?
func locationManager
(manager: CLLocationManager!,didUpdateToLocation newLocation: CLLocation!,
fromLocation oldLocation: CLLocation!){
manager.desiredAccuracy = kCLLocationAccuracyBest
var region = self.here.region as MKCoordinateRegion
self.here.setRegion(region, animated: true)
region.span.longitudeDelta = 0.0144927536
region.span.latitudeDelta = 0.0144927536
}
I believe you need to set the lat and long BEFORE you set the region. The setRegion function is what zooms in on a certain part, and the level of the zoom depends on your span. Here's an example of a map that zooms.
let span = MKCoordinateSpanMake(0.075, 0.075)
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: lat, longitude: long), span: span)
mapView.setRegion(region, animated: true)
Related
How to display current location from coordinates manually? I am taking coordinates from another GPS device. How to set it manually?
Where the coordinates come from is largely immaterial: as long as you have one you can set the map to display an area including that point. If you want to display the point itself you can add an annotation:
A simple example method to drop a pin and zoom in to its location:
func createAnnotation(from coordinate: CLLocationCoordinate2D, title: String) -> MKPointAnnotation {
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = title
return annotation
}
func dropPinAndZoomIn(to coordinate: CLLocationCoordinate2D){
var spanDelta = 0.035 //the width/height of the map area in degrees
let annotation = createAnnotation(from: coordinate, title: "My Location")
mapView.removeAnnotations(mapView.annotations) //clear any prev annotations
mapView.addAnnotation(annotation)
let span = MKCoordinateSpan(latitudeDelta: spanDelta, longitudeDelta: spanDelta)
let region = MKCoordinateRegion(center: coordinate, span: span)
let displayRegion = mapView.regionThatFits(region) //ensure the region can be displayed in the mapView's view
mapView.setRegion(displayRegion, animated: true)
}
I am trying to learn MapKit and add some MKPolyLine as an overlay. Couple of questions:
What is the difference between MKPolyLine and MKPolyLineView. Which one should be used when?
For the MKPolyLine init method one of the parameter is a generic type(MKMapPoint) of UnsafePointer? Not really sure what is that supposed to mean. Looking up the various SO questions, it seems we are supposed to pass the memory address of the CLLocationCoordinate2D struct as a parameter, but it doesn't work for me.
let testline = MKPolyline()
let coords1 = CLLocationCoordinate2D(latitude: 52.167894, longitude: 17.077399)
let coords2 = CLLocationCoordinate2D(latitude: 52.168776, longitude: 17.081326)
let coords3 = CLLocationCoordinate2D(latitude: 52.167921, longitude: 17.083730)
let testcoords:[CLLocationCoordinate2D] = [coords1,coords2,coords3]
let line = MKPolyline.init(points: &testcoords, count: testcoords.count)
mapView.add(testline)
I keep getting a "& is not allowed passing array value as 'UnsafePointer<MKMapPoint>" argument".
What is wrong here?
1.
MKPolyLine is a class which holds multiple map-coordinates to define the shape of a polyline, very near to just an array of coordinates.
MKPolyLineView is a view class which manages the visual representation of the MKPolyLine. As mentioned in the Kane Cheshire's answer, it's outdated and you should use MKPolyLineRenderer.
Which one should be used when?
You need to use both MKPolyLine and MKPolyLineRenderer as in the code below.
2.
MKPolyLine has two initializers:
init(points: UnsafePointer<MKMapPoint>, count: Int)
init(coordinates: UnsafePointer<CLLocationCoordinate2D>, count: Int)
When you want to pass [CLLocationCoordinate2D] to MKPolyLine.init, you need to use init(coordinates:count:).
(Or you can create an Array of MKMapPoint and pass it to init(points:count:).)
And when you want to pass an immutable Array (declared with let) to UnsafePointer (non-Mutable), you have no need to prefix &.
The code below is actually built and tested with Xcode 9 beta 3:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let coords1 = CLLocationCoordinate2D(latitude: 52.167894, longitude: 17.077399)
let coords2 = CLLocationCoordinate2D(latitude: 52.168776, longitude: 17.081326)
let coords3 = CLLocationCoordinate2D(latitude: 52.167921, longitude: 17.083730)
let testcoords:[CLLocationCoordinate2D] = [coords1,coords2,coords3]
let testline = MKPolyline(coordinates: testcoords, count: testcoords.count)
//Add `MKPolyLine` as an overlay.
mapView.add(testline)
mapView.delegate = self
mapView.centerCoordinate = coords2
mapView.region = MKCoordinateRegion(center: coords2, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02))
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
//Return an `MKPolylineRenderer` for the `MKPolyline` in the `MKMapViewDelegate`s method
if let polyline = overlay as? MKPolyline {
let testlineRenderer = MKPolylineRenderer(polyline: polyline)
testlineRenderer.strokeColor = .blue
testlineRenderer.lineWidth = 2.0
return testlineRenderer
}
fatalError("Something wrong...")
//return MKOverlayRenderer()
}
}
Change testCoords to be var instead of let. It needs to be mutable (variable) to be passed in as a pointer.
You're also trying to pass an array of CLLocationCoordinate2Ds into an argument that expects an array of MKMapPoints. Either convert your coordinates into points or use the function that takes an array of coordinates instead.
MKPolyLineView is an old way of rendering lines onto maps, Apple's docs say to use MKPolylineRenderer from iOS 7 and onwards: https://developer.apple.com/documentation/mapkit/mkpolylineview
I'm trying to build an app that when you open it it zooms to your current location. Below is my code so far.
class MapVC: UIViewController {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
mapView.zoomToUserLocation()
}
}
extension MKMapView {
func zoomToUserLocation() {
print(userLocation.location?.coordinate)
guard let coordinate = userLocation.location?.coordinate else { return }
let region = MKCoordinateRegionMakeWithDistance(coordinate, 10000, 10000)
setRegion(region, animated: true)
}
}
This code does not solve the problem. I believe this is because the app doesn't have time after receiving location authorisation to obtain the user location. I'm looking to write a function that would wait for the app to have a location and then call the zoomToUserLocation function. I've already tried this with a do-while loop which didn't work. I could set a delay but that would mean the zoom was done at a specific time and instead I want the zoom to be done as soon as possible. I've found solutions to this in objective C but couldn't translate it.
This method might be helpful setUserTrackingMode(_:animated:), but I think that's not what you are looking for.
The solution that may fit best for you is to implement locationManager(_:didChangeAuthorization:) and locationManager(_:didUpdateLocations:) on the CLLocationManager's delegate. Then you call zoomToUserLocation() in didUpdateLocations.
Another observation, is that you shouldn't animate the map inside viewDidLoad() 'cause the view it not on screen yet. This should be done in viewDidAppead().
you need both a span and a region...the span allows you to set how far you want to zoom in...
let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
if let center = location?.coordinate {
let region = MKCoordinateRegion(center: center, span: span)
self.mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
Disclaimer: very beginner level coder here, so excuse any "obvious" mistakes.
I am trying to build an app that shows to user how close they are to a marker.
I have a GoogleMaps map view and I want to refresh user location continuously (every say 3 seconds). calculate and print its linear distance (in meters) from the marker, and set that to my left navigation item button.
I tried doing this through GoogleMaps to no avail. So tried with CLLocation and CoreLocation.
Problem is, I get first value in meters (15m), second value (9m) 3 seconds later, then every other 3 second iteration of my timer only gives 9m forever, no matter if I move around (and my googlemaps view does update successfully the blue user position dot as I move around, laptop and linked ipad in hand).
What I am doing is have my timer fire off "findDistance" function every 3 seconds. The "findDistance" function runs locationmanager (which sets globalUserLocation to current one - if I am not doing something wrong), calculates distance and sets it to GlobalDistance, then updates the left navigation button item to that new distance.
But it seems like the user location is only updated twice (instead of every 3 seconds, forever).
What am I doing wrong? Any help would be greatly appreciated
I have added all the plist requirements, and here is my code:
import UIKit
import GoogleMaps
import CoreLocation
import MapKit
class googleMaps: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
let locationmanager = CLLocationManager()
var globalDistance: CLLocationDistance = 0
var mapView: GMSMapView? = nil
var globalUserLocation = CLLocation(latitude: 40.085260, longitude: 22.601468)
override func viewDidLoad() {
super.viewDidLoad()
let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(googleMaps.findDistance), userInfo: nil, repeats: true)
self.locationmanager.delegate = self
self.locationmanager.desiredAccuracy = kCLLocationAccuracyBest
self.locationmanager.startUpdatingLocation()
timer.fire()
GMSServices.provideAPIKey("**mykeyhere**")
let camera = GMSCameraPosition.camera(withLatitude: 40.085260 , longitude: 22.601468, zoom: 40)
mapView = GMSMapView.map(withFrame: CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 200, height: 500)), camera: camera)
mapView?.isMyLocationEnabled = true
view = mapView
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "\(globalDistance)", style: UIBarButtonItemStyle.plain, target: self, action: #selector(googleMaps.next as (googleMaps) -> () -> ()))
mapView?.mapType = kGMSTypeNormal
self.mapView?.settings.myLocationButton = true
self.mapView?.settings.compassButton = true
}
func locationmanager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
globalUserLocation = locations.last!
}
func findDistance(){
locationmanager
let currentLat = locationmanager.location!.coordinate.latitude
let currentLong = locationmanager.location!.coordinate.longitude
globalUserLocation = CLLocation(latitude: currentLat, longitude: currentLong)
let myMarker = CLLocation(latitude: 40.085260, longitude: 22.601468)
if globalUserLocation != nil {
let distance = globalUserLocation.distance(from: myMarker)
print(distance)
globalDistance = distance
navigationItem.leftBarButtonItem?.title = "\(globalDistance)"
}
}
when getting dynamic google map with using GMSMap the map doesn't show the current location that i gave him and not zoom the map
import UIKit
import GoogleMaps
import MapKit
class LocationItemViewController: UIViewController,GMSMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var lblInfo: UILabel!
#IBOutlet weak var lblTitle: UILabel!
#IBOutlet weak var viewMap: UIView!
#IBOutlet weak var googleMapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
let latitude = (String(format:"%.02f", locationItem.itemLatitude ) as NSString).doubleValue
let longgitude = (String(format:"%.02f", locationItem.itemLongitude) as NSString).doubleValue
let camera = GMSCameraPosition.cameraWithLatitude(latitude,longitude: longgitude, zoom: 7)
let mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
mapView.myLocationEnabled = true
self.googleMapView = mapView
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake((locationItem.itemLatitude as NSString).doubleValue, (locationItem.itemLongitude as NSString).doubleValue)
marker.title = "somelocation"
marker.snippet = "anywhere"
marker.map = mapView
lblTitle.text = locationItem.itemName
lblInfo.text = locationItem.itemAddress
}
I was locate the GMSServices.provideAPIKey("YOUR_API_KEY") in app delegate
To display your current location you have to do the same thing which we do for apple maps to access our location.
In plist you have to add 2 entries and take permission from User
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
Check this link for more details iOS 8 CLLocationManagerDelegate methods are never called
Now regarding your google maps zoom issue
var mapView:GMSMapView?
Now in your viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
GMSServices.provideAPIKey("YOUR_API_KEY")
//Taking HardCoded lat longs for the time being. These lat longs are of New Delhi, India
let camera = GMSCameraPosition.cameraWithLatitude(28.6139, longitude: 77.2090, zoom: 10)
mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
mapView!.myLocationEnabled = true
self.view = mapView
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(28.6139, 77.2090)
marker.title = "Delhi"
marker.snippet = "India"
marker.map = mapView
//As view takes some time to load so I am calling my zoom function after a delay of 1 second. You can use the zoom function code in viewDidAppear too
//Also this syntax is the latest Swift 2.2 syntax. If you are using the old Swift version, make the changes accordingly for performSelector method
self.performSelector(#selector(zoom), withObject: nil, afterDelay: 1.0)
}
Here is the zoom method
func zoom() {
CATransaction.begin()
CATransaction.setValue(1, forKey: kCATransactionAnimationDuration)
// It will animate your camera to the specified lat and long
let camera = GMSCameraPosition.cameraWithLatitude(28.6139, longitude: 77.2090, zoom: 15)
mapView!.animateToCameraPosition(camera)
CATransaction.commit()
}