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
}
Related
I am using MapKit. It draws the route between the two entered locations. But the go button does not appear. So he draws the route but doesn't describe how to go on the route. You can see in the photo. It puts the pins, but the Go to route button does not appear. How can I activate the go button?
class customPin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(pinTitle:String, pinSubTitle:String, location:CLLocationCoordinate2D) {
self.title = pinTitle
self.subtitle = pinSubTitle
self.coordinate = location
}
}
class mapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let sourceLocation = CLLocationCoordinate2D(latitude:39.173209 , longitude: -94.593933)
let destinationLocation = CLLocationCoordinate2D(latitude:38.643172 , longitude: -90.177429)
let sourcePin = customPin(pinTitle: "Kansas City", pinSubTitle: "aa", location: sourceLocation)
let destinationPin = customPin(pinTitle: "St. Louis", pinSubTitle: "ddd", location: destinationLocation)
self.mapView.addAnnotation(sourcePin)
self.mapView.addAnnotation(destinationPin)
let sourcePlaceMark = MKPlacemark(coordinate: sourceLocation)
let destinationPlaceMark = MKPlacemark(coordinate: destinationLocation)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: sourcePlaceMark)
directionRequest.destination = MKMapItem(placemark: destinationPlaceMark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { (response, error) in
guard let directionResonse = response else {
if let error = error {
print("we have error getting directions==\(error.localizedDescription)")
}
return
}
let route = directionResonse.routes[0]
self.mapView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
self.mapView.setRegion(MKCoordinateRegion(rect), animated: true)
}
self.mapView.delegate = self
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.blue
renderer.lineWidth = 4.0
return renderer
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
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 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 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 {
I am trying to make a simple app that has a map and some fixed annotations. I want to click those annotations, their button, and get a menu with a picture and some additional text like how the Apple Maps points work.
So far here is my code, I can get all the way to the DetailDisclosure Button, but I cannot get it to work that way when I click it. Can someone help me? Thanks in advance.
(there is also a class called Shops, but I haven't included in this post)
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UIPopoverPresentationControllerDelegate{
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
var mapItemData:MKMapItem!
override func viewDidLoad() {
super.viewDidLoad()
// Initiate GPS
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
//Pin coordinates
mapView.delegate = self
let J = Shops(title: "Jingle", coordinate: CLLocationCoordinate2D(latitude: 44.631076, longitude: 22.946770), info: "H", address:"Π", subtitle:"κ")
let K = Shops(title: "R", coordinate: CLLocationCoordinate2D(latitude: 43.65, longitude: 6.43), info: "F", address:"Π", subtitle:"κ")
let L = Shops(title: "P", coordinate: CLLocationCoordinate2D(latitude: 58.89, longitude: 2.3508), info: "O", address:"Π", subtitle:"κ")
let B = Shops(title: "R", coordinate: CLLocationCoordinate2D(latitude: 26, longitude: 17), info: "H", address:"Π", subtitle:"κ")
let W = Shops(title: "W", coordinate: CLLocationCoordinate2D(latitude: 88.43111, longitude: -37.035663), info: "N", address:"Π", subtitle:"κ")
mapView.addAnnotations([J, K, L, B, W])
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Locate through GPS
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: 1, longitudeDelta: 1))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "Shops"
if annotation.isKindOfClass(Shops.self) {
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
let btn = UIButton(type: .InfoLight)
annotationView!.rightCalloutAccessoryView = btn
}else{
annotationView!.annotation = annotation
}
return annotationView
}
return nil
}
//Zoom out to enclose all annotations
func fitMapViewToAnnotaionList(annotations: [MKPointAnnotation]) -> Void {
let mapEdgePadding = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
var zoomRect:MKMapRect = MKMapRectNull
for index in 0..<annotations.count {
let annotation = annotations[index]
let aPoint:MKMapPoint = MKMapPointForCoordinate(annotation.coordinate)
let rect:MKMapRect = MKMapRectMake(aPoint.x, aPoint.y, 0.1, 0.1)
if MKMapRectIsNull(zoomRect) {
zoomRect = rect
} else {
zoomRect = MKMapRectUnion(zoomRect, rect)
}
}
mapView.setVisibleMapRect(zoomRect, edgePadding: mapEdgePadding, animated: true)
}
}