Hi I'm mostly new to coding and this is my first project that I've worked on. I'm making an app that displays pools which are hiring around your address and wanted to make it so that pressing on the callouts will bring you to a unique ViewController depending on which one you pressed.
From what I've seen so far online it looks like it needs to be done in an extension of the ViewController but was stuck on how to differentiate between callouts (as of right now I have it so that pressing it will show the directions, but I'd rather show more information that just that, which to my limited knowledge would mean displaying another view controller unless anyone else has any other ideas)
extension MapViewController : MKMapViewDelegate
{
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if let annotation = annotation as? Pools {
let identifier = "pin"
var view: MKPinAnnotationView
if let dequeuedView =
mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView{
dequeuedView.annotation = annotation
view = dequeuedView
}
else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure) as UIView
}
return view
}
return nil
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let location = view.annotation as! Pools
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
location.mapItem().openInMaps(launchOptions: launchOptions)
}
}
Any help would be greatly appreciated!
Related
I'm having problems with my custom MKAnnotationView.
I download the coordinate where to place it from my REST api and I place the pin on map with this code:
private func refreshMapView(andCenterMap: Bool){
DispatchQueue.main.async { [weak self] in
guard let self = self else {
return
}
self.mapView.addAnnotations(self.spotsArray)
if andCenterMap {
self.centerMap(at: self.mapView.userLocation.coordinate)
}
}
}
Ones the pin is placed I zoom automatically the map.
Here the code for the custom annotation creation:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// Do not touch the annotation of the user location
if annotation.isKind(of: MKUserLocation.self){
return nil
}
let annoIdentifier = "SPOT"
var annotationView: MKAnnotationView?
if let dequeued = mapView.dequeueReusableAnnotationView(withIdentifier: annoIdentifier) {
annotationView = dequeued
}else{
let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annoIdentifier)
annotationView = av
}
// Changing the image of the pin
annotationView!.annotation = annotation
if let image = UIImage(named: "map_pin") {
annotationView!.image = image
let deltaY = image.size.height/2
annotationView!.centerOffset = CGPoint(x: 0.0, y: -deltaY)
}else{
annotationView!.image = nil
}
return annotationView
}
As you can notice, my custom pin is using this image (#1x, #2x, #3x)
Ones tapped I want to show the "detail view" and I use the annotation as a sender in order to have all the information I need on the next view.
Here the code:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
guard let ann = view.annotation else {
return
}
if ann.isKind(of: MKUserLocation.self){
return
}
self.performSegue(withIdentifier: "showDetailSegue", sender: ann)
}
So I present all the data I need to and I can go back to the "map view".
The problem is:
In the map view, if I want to select the same annotation again, this is not tappable anymore.
I can see it (in the right place) but I can select it again only if I zoom a little bit and I tap "around" the annotation.
Any suggestione how to solve this issue?
Thanks in advance!
Add this end of didSelect
mapView.deselectAnnotation(ann,animated:false)
Hello guys I am working with MKMap and populating some pins into a map everything is good with that in the pin I can show name and last name + when I click the pin shows an URL but the idea is when I tap the URL to open the web browser and redirect to the URL and for some reason is not working.
Here is a screenshot of my method that I use to open my url:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
if let toOpen = view.annotation?.subtitle! {
if let url = URL(string: toOpen) {
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:],
completionHandler: {
(success) in
print("Open \(url): \(success)")
})
} else {
_ = UIApplication.shared.openURL(url)
}
}
}
}
}
this is my method where I define the pin properties, a weird thing is that I am giving my pin a color blue but still show it in red.
private func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.pinTintColor = UIColor.blue
pinView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
} else {
pinView!.annotation = annotation
}
return pinView
}
here is my Github project. I would like to know what I am doing wrong because I can tap my pin shows the information but it doesn't open the URL.
Thanks for your time guys!
Maybe your viewForAnnotation method is not called. Replace
private func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
with
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
I solved it.
I realized that my mapView functions weren't working at all. I comment the code and move stuff and those two functions weren't doing anything.
So after awhile watching videos and reading, I found that I need it to use the mapView delegate to the controller itself, so I could use my mapView functions and just adding this line of code:
override func viewDidLoad() {
super.viewDidLoad()
//MIRACLE HAPPENS HERE
mapView.delegate = self
}
Just with that line of code in my viewDidLoad function, all my code inside the mapView function started working.
I'm using the same function call to display a pin & annotation on my map. When I use this on a current location inside of a reverse geocode call, the pin centers on the base of the pin (obscuring the top of the callout). When I call the same code in any other circumstance (such as when using coordinates passed into the view controller), the map centers on the top of the pin (which is what I want). Code below, image just after this. placesData is an object of a custom class PlacesData, that conforms to both: NSObject, MKAnnotation. Thanks in advance!
func updateMap() {
centerMap(mapLocation: (placeData?.coordinate)!, regionRadius: regionRadius)
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotation(self.placeData!)
mapView.selectAnnotation(self.placeData!, animated: true)
}
Also: if significant, here is the code for my function: mapView(_:viewFor:)
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifer = "Marker"
var view: MKPinAnnotationView
if let dequedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifer) as? MKPinAnnotationView {
dequedView.annotation = annotation
view = dequedView
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifer)
view.canShowCallout = true
view.rightCalloutAccessoryView = UIButton(type: .custom)
}
return view
}
I have a problem with my app. In fact, when I am running my code in a separate app it is working. xCode is not showing me any errors and everything works fine but I can't see a detail button in my Annotations on MapKit. Is there a problem deeper in xCode?
That is my code:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "Education"
if annotation is Education {
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
let btn = UIButton(type: .detailDisclosure)
annotationView!.rightCalloutAccessoryView = btn
} else {
annotationView!.annotation = annotation
}
return annotationView
}
return nil
}
It looks like this on my app - no detail button on the right side of annotation.
you have to set the delegate for your mapView. I usually do it in the viewDidLoad of the ViewController the mapView is in.
mapView.delgate = self
is the code you need to add.
I'm using MapKit and I'm currently trying to set a custom pin annotation image on my pins. However, I'm having a hard time figuring out why it doesn't work. All of the other code is working perfectly, and when I try printing the frame of the image after setting it, it does show the correct dimensions for my "pinImage", so it seems to be able to set the image on the property.
Also, the delegate is set correctly, this is verified by setting a custom color on the default pin.
I've also tried using "pinImage.png", without luck. And since MKPinAnnotationView is a subclass of MKAnnotationView, I see no problem with why that should be the issue, and to be sure, I tried to use the MKAnnotationView also, without luck.
Here's my code:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? Pin {
let identifier = LocalConstants.pinIdentifier
var view: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
let detailButton = UIButton(type: .detailDisclosure) as UIView
view.rightCalloutAccessoryView = detailButton
//view.pinTintColor = Util.Colors.pluppPurple
}
view.image = UIImage(named: "pinImage")
return view
}
Thanks in advance!
The answer was indeed to use MKAnnotationView and not MKPinAnnotationView. I do not know what I messed up when trying it out yesterday. Final working copy below, for future reference:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? Pin {
let identifier = LocalConstants.pinIdentifier
var view: MKAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.tintColor = Util.Colors.pluppGrey
let detailButton = UIButton(type: .detailDisclosure) as UIView
view.rightCalloutAccessoryView = detailButton
}
view.image = UIImage(named: LocalConstants.pluppPin)
return view
}
return nil
}