I am having an issue with my calloutAccessoryControllerTapped. At the minute I have two buttons within my callout - each which will segue to a modal pop up on my map view. At the minute my segue works but both buttons segue to the same popup. I need to be able to differentiate between buttons and their segue.
Is this possible? I have googled this question and many answers seem to suggest using this line of code below
if (control == view.leftCalloutAccessoryView) {
However, this is coming up with an error "Value of type 'UIView' has no member 'leftCalloutAccessoryView'. I would really appreciate if somebody could help me with this issue and apologise if I have not clearly explained the issue, I have done so to my best extent.
Below is my code:
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
func mapView(_ mapView: MGLMapView, annotation: MGLAnnotation, calloutAccessoryControlTapped control: UIControl) {
self.performSegue(withIdentifier: "Show", sender: view)
}
func mapView(_ mapView: MGLMapView, rightCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? {
guard let skateAnnotation = annotation as? SkateAnnotation else { return nil }
if skateAnnotation.canEdit {
return UIButton(type: .detailDisclosure)
}
return nil
}
func mapView(_ mapView: MGLMapView, leftCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? {
return UIButton(type: .contactAdd)
}
func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? {
return nil
}
}
Something simple (change code for your own requirements as necessary) like this works to distinguish between the left and right callout accessory controls.
func mapView(_ mapView: MGLMapView, leftCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? {
let button = UIButton(type: .detailDisclosure)
button.tag = 100
return button
}
func mapView(_ mapView: MGLMapView, rightCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? {
let button = UIButton(type: .detailDisclosure)
button.tag = 101
return button
}
func mapView(_ mapView: MGLMapView, annotation: MGLAnnotation, calloutAccessoryControlTapped control: UIControl) {
// Hide the callout view.
mapView.deselectAnnotation(annotation, animated: false)
if control.tag == 100 {
print("left")
} else if control.tag == 101 {
print("right")
}
}
Related
I would like to trigger a NavigationLink through a tap on a Annotation in Mapkit. I am able to set a bool, that a certain annotation was tapped, but i never was able to call a SwiftUI View through it.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else {
return nil
}
let identifier = "Annotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
} else {
annotationView?.annotation = annotation
}
return annotationView
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
let selectedAssistance = self.parent.assistances.first {
$0.location.location?.coordinate == view.annotation?.coordinate
}
guard selectedAssistance != nil else {
return
}
self.parent.selectedAssistance = selectedAssistance?.serverId ?? ""
self.parent.presentSheet = true
}
I made it, by calling my own MapView in a ZStack, and placed a NavLink behind it, which is active on a Binding
I want to show the callout of the annotationview always show, I mean when the mapview is loaded, all the annotations‘ callout is shown.
How can I do this?
At anytime, there can be only one callout on the map. Framework reuses the previous callout when a new is to be presented, and here is showing a single callout view when annotation is added, like so
let annotation = MKPointAnnotation()
annotation.title = "Title for Callout"
mapView.addAnnotation(annotation)
This causes the delegate method viewForAnnotation to be fired:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let view = MKAnnotationView(annotation: annotation, reuseIdentifier: "AnnotId")
view.canShowCallout = true
return view
}
Framework will add the above returned view and the didAddViews delegate is fired, now show the callout view by selecting the annnotation, like so
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
if let annotation = views.first(where: { $0.reuseIdentifier == "AnnotId" })?.annotation {
mapView.selectAnnotation(annotation, animated: true)
}
}
Add annotation on map: mapView.addAnnotation(myAnnotation)
Select annotation mapView.selectAnnotation(myAnnotation, animated: false)
Add private function private func bringMyAnnotationToFront() with code if let myAnnotation = mapView.annotations.first(where: { $0 is MKPointAnnotation }) { mapview.selectAnnotation(myAnnotation, animated: false) }
Set MKMapViewDelegate and implement two methods with bringMyAnnotationToFront:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView), func mapView(MKMapView, didDeselect: MKAnnotationView)
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 would like to know how can I go to another view when I tap title on
MKPointAnnotation
func addPin(lat:Double, lng:Double) {
let testPin = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let dropPin = MKPointAnnotation()
dropPin.coordinate = testPin
dropPin.title = "123456"
mapView.addAnnotation(dropPin)
}
I need to segue with identifier "More"
Please add this delegate method in your code and check it
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView){
performSegue(withIdentifier: "PlaceDetail", sender: nil)
}
You need to override this method from MKMapViewDelegate:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
performSegue(withIdentifier: "PlaceDetail", sender: nil)
}
I implemented map view and created simple data model for annotations.
The pins are shown on the map, but I am still unable to get the details by tapping any pin.
My Code:
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var topView: MapDataView!
var dummyModel: DummyModel?
override func viewDidLoad() {
super.viewDidLoad()
dummyModel = DummyModel()
mapView.delegate = self
mapView.showsUserLocation = true
let region = MKCoordinateRegionMakeWithDistance(mapView.userLocation.coordinate, 1000, 1000)
mapView.setRegion(region, animated: true)
let range = 0..<Int((dummyModel?.objectsArray.count)!)
Array is valid and has no nil:
for i in range {
mapView.addAnnotation((dummyModel?.objectsArray[i])!)
}
The way i add annotation to the map:
mapView.selectAnnotation(mapView.annotations[0], animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
print("viewForAnnotation")
let identifier = "PubMapObject"
if annotation is PubMapObject {
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
}
This method never called and i dont know why. i guess the problem is here, but i am unable to find it ):
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
print("annotationView")
let pub = view.annotation as! PubMapObject
}
}
Try to add set frame of annotation view before returning annotation view
//my annotation class and provide width and height to annotation view before returning the annotation view and give frame to
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if (annotation.isKind(of: MKUserLocation.self)) {
return nil
}
let reuseId = "PubMapObject"
if (annotation.isKind(of: PubMapObject.self)) {
let anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView.isEnabled = true
anView.isUserInteractionEnabled = true
let btn = UIButton(type: .detailDisclosure)
btn.frame = CGRect(x: 0, y: 0, width: 50, height: 70)
anView!.rightCalloutAccessoryView = btn
anView.frame = CGRect(x: 0, y: 0, width: 50, height: 70)
return anView
}
return nil
}
Try using didSelect function instead of calloutAccessoryControlTapped.
func mapView(_ mapView: MKMapView, didSelect annotationView: MKAnnotationView) { ...