I have this func for populate pins on mapView:
func obervePins(){
let magRef = Database.database().reference().child("map")
magRef.observe(.value) { (snapshot) in
//var tempCoord = [CoordinatesOfMagazine]()
for child in snapshot.children {
if let chidSnapshot = child as? DataSnapshot,
let dictMag = chidSnapshot.value as? [String: Any],
let title = dictMag["Title"] as? String,
let latitude = dictMag["Latitude"] as? String,
let longitude = dictMag["Longitude"] as? String {
// let imageOfMagazine = dictMag["imageOfMagazine"] as? String,
// let url = URL(string: imageOfMagazine) {
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: Double(latitude)!, longitude: Double(longitude)!)
annotation.title = title
print(annotation)
self.mapView.addAnnotations([annotation])
// let coordinates = CoordinatesOfMagazine(imageOfMagazine: url, Title: title)
// tempCoord.append(coordinates)
}
}
//self.coordinates = tempCoord
}
}
My data in Firebase looks like:
Pins in mapView is correct.
I don't know, how to display images for magazine in mapView. Help plz
Create a custom MKAnnotation class.
class ImageAnnotation : NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
var imageOfMagazine: String?
override init() {
self.coordinate = CLLocationCoordinate2D()
self.title = nil
self.subtitle = nil
self.imageOfMagazine = nil
}
}
Set data and add the annotation to your mapView.
let annotation = ImageAnnotation()
annotation.coordinate = coordinate1
annotation.title = "title"
annotation.subtitle = "subtitle"
annotation.imageOfMagazine = imageOfMagazine
self.mapView.addAnnotation(annotation)
Implement mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) delegate method.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? ImageAnnotation else {
return nil
}
let reuseId = "Pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pinView == nil {
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.canShowCallout = true
let data = NSData(contentsOf: URL(string: annotation.imageOfMagazine!)!)
pinView?.image = UIImage(data: data! as Data)
}
else {
pinView?.annotation = annotation
}
return pinView
}
// here take marker as global varible
var marker : GMSMarker?
self.ref.observe(.value) { snapshot in
let dict = snapshot.value as! NSDictionary
self.marker?.map?.clear()
if let lat = dict["latitude"] as? CLLocationDegrees ,let long = dict["longitude"] as? CLLocationDegrees {
var camera = GMSCameraPosition.camera(withLatitude: lat, longitude: longt, zoom: 12)
var position: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, longt)
self.marker = GMSMarker(position: position)
self.marker?.icon = UIImage(named: imageName) // set your image here
self.marker?.map = self.mapview
self.mapview?.animate(to: camera)
}
}
Related
I am using map in Two viewcontrollers
Initially in first viewcontroller i am getting current location in map..
in second viewcontroller i am getting new location coordinates, which i am sending to firstview controller using delegate.. but here how to replace the delegate method coordinates with current location coordinates in first view controller
first view controller code: here in delegate method i am successfully having new location coordinates which i need replace with current location
in userDidEnterInformationdelegate method i am getting all values from 2nd view controller
import UIKit
import CoreLocation
import MapKit
class ProfileAddressViewController: UIViewController, CLLocationManagerDelegate, UISearchBarDelegate, DataEnteredDelegate {
var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D()
let locationManager = CLLocationManager()
var latitude: Double?
var logitude: Double?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}
func userDidEnterInformation(info: DataEnteredModelSave) {
print("map address viewcontroller data \(info)")
self.pincodeField.text = info.pinCode
self.cityField.text = info.cityField
self.latitude = info.zLatitude
self.self.logitude = info.zLongitude
print("new map address viewcontroller data info lat long \(self.latitude) \(self.logitude)")
}
#IBAction func submitButtonClicked(_ sender: UIButton) {
self.view.endEditing(true)
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "NewZoomAddressViewController") as! NewZoomAddressViewController;
self.navigationController?.pushViewController(viewController, animated: true);
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let _: CLLocationCoordinate2D = manager.location?.coordinate else { return }
let userLocation :CLLocation = locations.last! as CLLocation
latitude = userLocation.coordinate.latitude
logitude = userLocation.coordinate.longitude
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(userLocation) { (placemarks, error) in
if (error != nil){
print("error in reverseGeocode")
}
let placemark = placemarks! as [CLPlacemark]
if placemark.count>0{
let placemark = placemarks![0]
let placemarkDictonary: NSDictionary=placemark.addressDictionary as! NSDictionary
self.pincodeField.text=placemarkDictonary["ZIP"] as? String
self.cityField.text=placemarkDictonary["City"] as? String
}
}
let center = CLLocationCoordinate2D(latitude: latitude!, longitude: logitude!)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
mapView.setRegion(region, animated: true)
let myAnnotation: MKPointAnnotation = MKPointAnnotation()
myAnnotation.coordinate = CLLocationCoordinate2DMake(userLocation.coordinate.latitude, userLocation.coordinate.longitude);
myAnnotation.title = "Current location"
mapView.addAnnotation(myAnnotation)
}
}
please help me to add delegate method latitude and longitude in locationManager didUpdateLocations
Replace userDidEnterInformation with below code:
func userDidEnterInformation(info: DataEnteredModelSave) {
print("map address viewcontroller data \(info)")
self.pincodeField.text = info.pinCode
self.streetField.text = info.streetField
self.cityField.text = info.cityField
self.latitude = info.zLatitude
self.logitude = info.zLongitude
print("map address viewcontroller data info lat long \(self.latitude) \(self.logitude)")
locationManager.stopUpdatingLocation() //stop updating location when you got data from delegate
let userLocation = CLLocation.init(latitude: latitude!, longitude: logitude!)
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(userLocation) { (placemarks, error) in
if (error != nil){
print("error in reverseGeocode")
}
let placemark = placemarks! as [CLPlacemark]
if placemark.count>0{
let placemark = placemarks![0]
print(placemark.locality!)
print(placemark.administrativeArea!)
print(placemark.country!)
let placemarkDictonary: NSDictionary=placemark.addressDictionary as! NSDictionary
self.pincodeField.text=placemarkDictonary["ZIP"] as? String
self.cityField.text=placemarkDictonary["City"] as? String
self.plotField.text=placemarkDictonary["Name"] as? String
self.streetField.text=placemarkDictonary["Street"] as? String
self.appormentNoField.text=placemarkDictonary["SubThoroughfare"] as? String
self.colonyField.text=placemarkDictonary["SubLocality"] as? String
self.landmarkField.text=placemarkDictonary["SubThoroughfare"] as? String
}
}
let center = CLLocationCoordinate2D(latitude: latitude!, longitude: logitude!)
//Assign data to map again with new location
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
mapView.setRegion(region, animated: true)
let myAnnotation: MKPointAnnotation = MKPointAnnotation()
myAnnotation.coordinate = CLLocationCoordinate2DMake(latitude!, logitude!)
myAnnotation.title = "Current location"
mapView.addAnnotation(myAnnotation)
}
I have added comments please check them.
EDIT: As per your second request if you want to show new coordinates on NewZoomAddressViewController first you need to pass coordinates to NewZoomAddressViewController in submitButtonClicked method like:
viewController.latestLocation = CLLocation.init(latitude: self.latitude!, longitude: self.logitude!)
then in NewZoomAddressViewController declare new var
var latestLocation: CLLocation?
and remove other code which is related to user's current location and final code will look like:
import UIKit
import MapKit
import CoreLocation
//import SwiftKeychainWrapper
protocol DataEnteredDelegate: class {
func userDidEnterInformation(info: DataEnteredModelSave)
}
class NewZoomAddressViewController: UIViewController {
#IBOutlet weak var oneBtnContainerView: UIView!
var latitudeZoom: Double?
var logitudeZoom: Double?
weak var delegate: DataEnteredDelegate? = nil
var zipName: String?
var localityName: String?
var sublocalityName: String?
var streetNumber: String?
var streetName: String?
let searchCont = UISearchController(searchResultsController: nil)
let annotation = MKPointAnnotation()
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var addressLabel: UILabel!
let regionInMeters: Double = 10000
var previousLocation: CLLocation?
var latestLocation: CLLocation?
override func viewDidLoad() {
super.viewDidLoad()
print("in Zoom map VC")
mapView.delegate = self
addressLabel.text = "\(self.sublocalityName!) \(localityName!) \(self.zipName!)"
centerViewOnUserLocation()
}
#IBAction func backBtn(_ sender: Any) {
self.navigationController?.popViewController(animated: true)
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.isHidden=true
}
var viewController: UIViewController?
#IBAction func confirmBtn(_ sender: Any) {
guard
let zipName = zipName,
let sublocalityName = sublocalityName,
let localityName = localityName,
let lnatZ = latitudeZoom,
let longZ = logitudeZoom
else { return }
let enteredData = DataEnteredModelSave(pinCode: zipName, streetField: sublocalityName, cityField: localityName, zLatitude: lnatZ, zLongitude: longZ)
delegate?.userDidEnterInformation(info: enteredData)
self.navigationController?.popViewController(animated: true)
}
func centerViewOnUserLocation() {
if let location = latestLocation {
let region = MKCoordinateRegion.init(center: location.coordinate, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
mapView.setRegion(region, animated: true)
}
}
func getCenterLocation(for mapView: MKMapView) -> CLLocation {
latitudeZoom = mapView.centerCoordinate.latitude
logitudeZoom = mapView.centerCoordinate.longitude
print("coordinates from zoom in func \(latitudeZoom), \(logitudeZoom)")
return CLLocation(latitude: latitudeZoom!, longitude: logitudeZoom!)
//print(CLLocation.self)
}
}
extension NewZoomAddressViewController: CLLocationManagerDelegate, UISearchBarDelegate {
// MARK:- Search Address
#IBAction func searchLocationButton(_ sender: Any) {
// let searchCont = UISearchController(searchResultsController: nil)
searchCont.searchBar.delegate = self
searchCont.searchBar.backgroundColor = .blue
present(searchCont, animated:true, completion:nil)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
dismiss(animated: true, completion: nil)
//create the search request
let searchReq = MKLocalSearch.Request()
searchReq.naturalLanguageQuery = searchBar.text
let activeSearch = MKLocalSearch(request: searchReq)
activeSearch.start { (response, error) in
UIApplication.shared.endIgnoringInteractionEvents()
if response == nil{
print("error")
}
else{
//remove annotation
//let annotations = self.mapView.annotations
// self.mapView.removeAnnotation(annotations as! MKAnnotation)
//getting data
let lat = response?.boundingRegion.center.latitude
let long = response?.boundingRegion.center.longitude
//create annotation
//let annotation = MKPointAnnotation()
self.annotation.title = searchBar.text
self.annotation.coordinate = CLLocationCoordinate2DMake(lat!, long!)
self.mapView.addAnnotation(self.annotation)
//zooming annotation
let coordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat!, long!)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: coordinate, span: span)
self.mapView.setRegion(region, animated: true)
// Add below code to get search address
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat!, longitude: long!)
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
placemarks, error -> Void in
// Place details
guard let placeMark = placemarks?.first else { return }
// Location name
self.zipName = placeMark.postalCode
self.localityName = placeMark.locality
self.sublocalityName = placeMark.subLocality
self.streetNumber = placeMark.subThoroughfare
self.streetName = placeMark.thoroughfare
})
}
}
}
}
extension NewZoomAddressViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let center = getCenterLocation(for: mapView)
let geoCoder = CLGeocoder()
guard let previousLocation = self.latestLocation else { return }
guard center.distance(from: previousLocation) > 50 else { return }
self.previousLocation = center
let userLocation :CLLocation = center as CLLocation
latitudeZoom = userLocation.coordinate.latitude
logitudeZoom = userLocation.coordinate.longitude
print("snajxhdwuidhwiuqhdxiqwjmdio \(latitudeZoom), \(logitudeZoom)")
geoCoder.reverseGeocodeLocation(center) { [weak self] (placemarks, error) in
guard let self = self else { return }
if let _ = error {
//TODO: Show alert informing the user
return
}
guard let placemark = placemarks?.first else {
//TODO: Show alert informing the user
return
}
self.streetNumber = placemark.subThoroughfare ?? ""
self.streetName = placemark.thoroughfare ?? ""
print("street number of zoom map \(self.streetName)")
self.localityName = placemark.locality ?? ""//locality
self.sublocalityName = placemark.subLocality ?? ""//locality
self.zipName = placemark.postalCode ?? ""//locality
DispatchQueue.main.async {
self.addressLabel.text = "\(self.streetNumber ?? "") \(self.streetName ?? "") \(self.sublocalityName ?? "") \(self.zipName ?? "") \(self.localityName ?? "")"
print("zzooom map location label \(self.addressLabel.text)")
}
}
}
}
I have a question, I created an annotation class to store id to further edit the waypoint. How to get the annotation id when didSelect MKMapView is called ?
This is my code:
#objc func longTap(sender: UIGestureRecognizer){
if sender.state == .began {
let locationInView = sender.location(in: mapView)
let locationOnMap = mapView.convert(locationInView, toCoordinateFrom: mapView)
addAnnotation(location: locationOnMap, name: "Test point", id: 123456)
}
}
...
func addAnnotation(location: CLLocationCoordinate2D, name: String, id: Int16) {
let annotation = WaypointsAnnotation()
annotation.coordinate = location
annotation.title = name
annotation.id = id
let CoordinateToDms = coordinateToDMS(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude)
annotation.subtitle = "\(CoordinateToDms.latitude) \(CoordinateToDms.longitude)"
self.mapView.addAnnotation(annotation)
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let annotationCoordinates = view.annotation?.coordinate
{
annotation.id ?
pindetaillatitude = annotationCoordinates.latitude
pindetaillongitude = annotationCoordinates.longitude
}
}
class WaypointsAnnotation : MKPointAnnotation {
var id : Int16?
}
Thanks for all the answers.
You need
let ann = view.annotation as! WaypointsAnnotation
print(ann.id)
I'm trying to present a view controller with an object within annotation didSelect function. But it's returning nil when I try to print the post.id within the newly presented viewcontroller. If I print post.id within the addAnnotation function it returns fine.
func addAnnotations(post: Post, title: String?, locationName: String?, coords: [CLLocation]) {
for coord in coords {
let CLLCoordType = CLLocationCoordinate2D(latitude: coord.coordinate.latitude,
longitude: coord.coordinate.longitude);
let anno = MKPointAnnotation()
anno.coordinate = CLLCoordType
if title == "" {
anno.title = locationName
} else {
anno.title = title
}
mapView.addAnnotation(anno)
}
}
let activityPreview = ActivityPreviewLauncher()
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
//Returns an error
guard let post = view.annotation?.post else { return }
activityPreview.showActivityPreview()
activityPreview.homeController = self
activityPreview.post = post
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation{
return nil
} else{
let pinIdent = "Pin"
var pinView: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: pinIdent) as? MKPinAnnotationView {
dequeuedView.annotation = annotation
pinView = dequeuedView
} else {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: pinIdent)
}
return pinView
}
}
Value of type 'MKAnnotation' has no member 'post'. You have to subclass MKPointAnnotation
class MyAnno: MKPointAnnotation {
var post: Post? = nil
}
in func addAnnotations override your code to
let CLLCoordType = CLLocationCoordinate2D(latitude: coord.coordinate.latitude,
longitude: coord.coordinate.longitude);
let anno = MyAnno()
anno.coordinate = CLLCoordType
anno.post = post
if title == "" {
anno.title = locationName
} else {
anno.title = title
}
mapView.addAnnotation(anno)
then in didSelect check type of your annotation
guard
let anno = view.annotation as? MyAnno,
let post = anno.post
else { return }
smth like this
So I have multiple locations stored in my database, using Geofire. I want to centre the map on a specific one.
I want to know if it is possible to access the firebase database to only retrieve the coordinates saved by GeoFire as a variable so that I can create a CLLocation and centre the map on this one location. Here is my code.
I call getJobLocation in my viewDidLoad. This is where I want to grab the job coordinates from Firebase and then call the other methods i.e. showJobsOnMap using these coordinates
func getJobLocation(jobID: String) {
...
}
func centreMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, 2000, 2000)
mapView.setRegion(coordinateRegion, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annoIdentifier = "job"
var annotationView: MKAnnotationView?
if annotation.isKind(of: MKUserLocation.self) {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "User")
annotationView?.image = UIImage(named:"currentLocationPin")
} else if let deqAnno = mapView.dequeueReusableAnnotationView(withIdentifier: "job") {
annotationView = deqAnno
annotationView?.annotation = annotation
} else {
let MKAV = MKAnnotationView(annotation: annotation, reuseIdentifier: annoIdentifier)
MKAV.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationView = MKAV
}
if let annotationView = annotationView, let _ = annotation as? JobAnnotation {
let postsRef = self.dataBaseRef.child("jobs")
postsRef.observe(.value, with: { (posts) in
for _ in posts.children {
annotationView.canShowCallout = true
annotationView.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationView.image = UIImage(named: "jobPin")
}
})
}
return annotationView
}
func showJobsOnMap(location: CLLocation) {
let circleQuery = geoFire!.query(at: location, withRadius: 2.5)
_ = circleQuery?.observe(GFEventType.keyEntered, with: { (key, location) in
if let key = key, let location = location {
if key == self.job.postID {
let postsRef = self.dataBaseRef.child("jobs").child(key)
postsRef.observe(.value, with: { (posts) in
for _ in posts.children {
let post = Post(snapshot: posts )
let jobDate = post.postDateTime
let price = post.price
let anno = JobAnnotation(coordinate: location.coordinate, jobID: key, jobDate: jobDate, title: "£\(price) - \(jobDate)")
self.mapView.addAnnotation(anno)
}
})
}
}
})
}
I have a latitude and longitude location of marker in google maps that I want to convert to the location name String in Swift. What is the best way to do this?
i want to show markers' location address and i don't know how to do it .
here is my code that i used to add marker and get latitude and longitude:
func mapView(mapView: GMSMapView, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
if counterMarker < 2
{
counterMarker += 1
let marker = GMSMarker(position: coordinate)
marker.appearAnimation = kGMSMarkerAnimationPop
marker.map = mapView
marker.position.latitude = coordinate.latitude
marker.position.longitude = coordinate.longitude
print(marker.position.latitude)
print(marker.position.longitude)
}
}
func mapView(mapView: GMSMapView, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
if counterMarker < 2
{
counterMarker += 1
let marker = GMSMarker(position: coordinate)
marker.appearAnimation = kGMSMarkerAnimationPop
marker.map = mapView
marker.position.latitude = coordinate.latitude
marker.position.longitude = coordinate.longitude
self.getAddressForLatLng(String(format: "%#",marker.position.latitude), longitude:String(format: "%#",marker.position.longitude)
}
}
func getAddressForLatLng(latitude: String, longitude: String) {
let url = NSURL(string: "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(latitude),\(longitude)&key=YOUR-APIKEY")
let data = NSData(contentsOfURL: url!)
let json = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
if let result = json["results"] as? NSArray {
if let address = result[0]["address_components"] as? NSArray {
let number = address[0]["short_name"] as! String
let street = address[1]["short_name"] as! String
let city = address[2]["short_name"] as! String
let state = address[4]["short_name"] as! String
let zip = address[6]["short_name"] as! String
print("\n\(number) \(street), \(city), \(state) \(zip) \(address)")
}
}
}