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)
}
Related
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 am making a Swift application that uses MKPointAnnotations, and I recently ran into an issue where I needed to store metadata in my annotations, so I created the custom class below:
class BRETTFAnnotation: MKPointAnnotation {
var tag: Int64
var name: String
init(lat : Double, lon:Double, t : Int64, n: String) {
self.tag = t
self.name = n
super.init()
self.coordinate = CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
}
My MKAnnotationView viewfor MKAnnotation method is shown below:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let newAnnotation = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "reuse")
newAnnotation.canShowCallout = true
let right = self.button(title: "Yes")
right?.addTarget(self, action: #selector(clickedToConfirmNewPoint), for: .touchUpInside)
newAnnotation.rightCalloutAccessoryView = right
let left = self.button(title: "No")
left?.addTarget(self, action: #selector(clickedToCancelNewPoint), for: .touchUpInside)
newAnnotation.leftCalloutAccessoryView = left
return newAnnotation
}
The problem I am running into is when ever I click on my custom BRETTFAnnotation (which I add to my MKMapView) nothing happens. When I was just using the MKPointAnnotation (instead of the BRETTFAnnotation) when I clicked on the map the two buttons on the MKAnnotationView would show. I am trying to get the MKPinAnnotationView to show on touch using my BRETTFAnnotation instead of the MKPointAnnotation.
How can I continue to use my custom annotation and show the callout when the user clicks on the annotation at the same time?
Edit 1: Since it is probably useful the code below is how I make the annotation and add it to the mapView.
let location = gestureRecognizer.location(in: mapView)
let coordinate = mapView.convert(location,toCoordinateFrom: mapView)
print("adding lat,long \(coordinate.latitude),\(coordinate.longitude)")
lastPoint = BRETTFAnnotation(lat: coordinate.latitude, lon: coordinate.longitude, t: 1, n: "")
let annotationView = MKPinAnnotationView(annotation: lastPoint, reuseIdentifier: "reuse")
mapView.addAnnotation(lastPoint)
I fix this problem by making my BRETTFAnnotation a subclass of NSObject and MKAnnotation instead of MKPointAnnotation. Doing this allowed my custom class to receive user interaction and show the callouts.
When you use your own MKAnnoation you can handle your actions in didSelect. Just implement the following code.
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let yourAnnotation = view.annotation as? BRETTFAnnotation {
//handle your meta data or/and show UIViews or whatever
}
}
with
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
//getting called when you tap on map or on another annotation (not the selected annotation before)
//hide UIViews or do whatever you want
}
That does work for me:
class ViewController: UIViewController, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
print("didSelect")
if let annoation = view.annotation as? MyAnnoation {
print("metatag \(annoation.metaTag)")
}
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
print("didDeselect")
}
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
let annotation = MyAnnoation(n: "name", m: "metaTag")
annotation.coordinate = CLLocationCoordinate2D(latitude: 50.0, longitude: 8.0)
mapView.addAnnotation(annotation)
}
}
class MyAnnoation: MKPointAnnotation {
var name: String?
var metaTag: String?
init(n: String, m: String) {
self.name = n
self.metaTag = m
}
}
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")
}
}
I am trying to perform a Segue between two UI Views I have correctly typed the identifier for the segue as can be seen Here
This is my function, with the same identifier "no" but when the button is clicked in the simulator it simply shows This (It looks like it is showing the stack in bottom left?)
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "no", sender:self)
}
}
I have attached my full code incase further analysis is needed. Thanks for your help.
View Controller:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate,CLLocationManagerDelegate {
#IBOutlet weak var MapView: MKMapView!
let manager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//let location = locations[0]
//let span:MKCoordinateSpan = MKCoordinateSpanMake(0.02, 0.02)
//let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
}
override func viewDidLoad() {
super.viewDidLoad()
// tracking user's location
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
// Setting up Map
let distanceSpan:CLLocationDegrees = 2000
MapView.setRegion(MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(-39.0556253, 174.0752278), distanceSpan, distanceSpan), animated: true)
MapView.showsUserLocation = true
MapView.delegate = self
// artwork on map
let windwandcoord: CLLocationCoordinate2D = CLLocationCoordinate2DMake(-39.055961,174.072288)
let artworkPin = Artwork(title:"Wind Wand",locationName:"Majestic",discipline:"Statue",
coordinate:windwandcoord)
MapView.addAnnotation(artworkPin)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation is MKUserLocation {return nil}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.calloutOffset = CGPoint(x: -5, y: 5)
let calloutButton = UIButton(type: .detailDisclosure)
pinView!.rightCalloutAccessoryView = calloutButton
pinView!.sizeToFit()
}
else {
pinView!.annotation = annotation
}
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "no", sender:self)
}
}
}
Any help appreciated.
See the solid blue bar in the gutter in your screen shot?
It is a breakpoint. When the path of execution reaches a breakpoint that is active (solid blue like this), we pause there. That is what a breakpoint is for.
If you don't want that to happen, drag the breakpoint out of the gutter.