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)
Related
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
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)
}
}
I was using MapKit and have shown five points of location and the pins are coming too. Now, I want to get a callout when I press on the pin annotation. How can I get that?
Here is the code:
class MultipleAnnotationController: UIViewController {
let sec22 = Capital(title: "Sector 22", coordinate: CLLocationCoordinate2D(latitude: 30.7339583, longitude: 76.77261969999995), info: "Sector 22 Aroma")
let sec34 = Capital(title: "Sector 34", coordinate: CLLocationCoordinate2D(latitude: 30.7195549, longitude: 76.76394989999994), info: "Aakash Institute")
let mohali = Capital(title: "Mohali Office", coordinate: CLLocationCoordinate2D(latitude: 30.707318902730268, longitude: 76.70382329676794), info: "Office Location")
let rmalerkotla = Capital(title: "Malerkotla Home", coordinate: CLLocationCoordinate2D(latitude: 30.5232076, longitude: 75.88825079999992), info: "Home")
let delhi = Capital(title: "New Delhi", coordinate: CLLocationCoordinate2D(latitude: 28.7040592, longitude: 77.10249019999992), info: "Capital of India")
#IBOutlet weak var mapV: MKMapView!
override func viewDidLoad() {
mapV.addAnnotations([sec22, sec34, mohali, rmalerkotla, delhi])
super.viewDidLoad()
}
class Capital: NSObject, MKAnnotation {
var title: String?
var coordinate: CLLocationCoordinate2D
var info: String
init(title: String, coordinate: CLLocationCoordinate2D, info: String) {
self.title = title
self.coordinate = coordinate
self.info = info
}
}
}
You need to implement the following method,
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "Pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.canShowCallout = true
}
else {
pinView?.annotation = annotation
}
return pinView
}
Don't forget to set mapV.delegate.
override func viewDidLoad() {
super.viewDidLoad()
mapV.addAnnotations([sec22, sec34, mohali, rmalerkotla, delhi])
mapV.delegate = self
}
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 am trying to convert a saved PFGeopoint objects in Parse server into an annotation but i can't seem to figure it out and i don't know what's wrong.
I tried to apply the code from this question : Converting Parse GeoPoint into a CLLocation in Swift but i still couldn't figure it out.
Here is my Code :
import UIKit
import MapKit
import CoreLocation
import Parse
class MapVC: UIViewController, MKMapViewDelegate {
fileprivate let locationManager = CLLocationManager()
fileprivate var startedLoadingPOIs = false
fileprivate var places = [Place]()
var descLocation: PFGeoPoint = PFGeoPoint()
var mapHasCenteredOnce = false
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.requestWhenInUseAuthorization()
mapView.userTrackingMode = MKUserTrackingMode.followWithHeading
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView: MKAnnotationView?
if annotation.isKind(of: MKUserLocation.self) {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "User")
annotationView?.image = UIImage(named: "loc.png")
}
return annotationView
}
}
extension MapVC: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//1
if locations.count > 0 {
let location = locations.last!
print("Accuracy: \(location.horizontalAccuracy)")
//2
if location.horizontalAccuracy < 100 {
//3
manager.stopUpdatingLocation()
let span = MKCoordinateSpan(latitudeDelta: 0.014, longitudeDelta: 0.014)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.region = region
if !startedLoadingPOIs {
startedLoadingPOIs = true
let loader = PlacesLoader()
loader.loadPOIS(location: location, radius: 1000) { placesDict, error in
if let dict = placesDict {
let query = PFQuery(className: "posts")
if let latitude = (PFUser.current()?["location"] as AnyObject).latitude {
if let longitude = (PFUser.current()?["location"] as AnyObject).longitude {
let geoPoint = PFGeoPoint(latitude: latitude, longitude: longitude)
query.whereKey("postLocation", nearGeoPoint: geoPoint, withinKilometers: 1)
}
}
query.findObjectsInBackground { (objects: [PFObject]?, error: Error?) in
if error == nil {
for object in objects! {
let pfObject = object as PFObject
let caption = pfObject["title"] as! String
self.descLocation = object["postLocation"] as! PFGeoPoint
let latitude: CLLocationDegrees = self.descLocation.latitude
let longitude: CLLocationDegrees = self.descLocation.longitude
let location = CLLocation(latitude: latitude, longitude: longitude)
let place = Place(location: location, name: caption )
self.places.append(place)
let annotation = PlaceAnnotation(location: place.location!.coordinate, title: place.placeName)
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
}
}
}
}
}
}
}
}
}
I just had two uanessacry lines that blocked the operation, removed them and it worked for me.
loader.loadPOIS(location: location, radius: 1000) { placesDict, error in
if let dict = placesDict {