Swift map annotations - ios

I am trying to get an annotation on the user location but I can't get a (sort of) speech bubble for my annotation's details. Is there any option to create something like this?
//AnnotationSettings
let newPin = MKPointAnnotation()
//set region on the map
maphome.setRegion(region, animated: true)
newPin.coordinate = location.coordinate
newPin.title = "aksldfjaskldfjaklsdfa"
newPin.subtitle = "sounds awesome!"
maphome.addAnnotation(newPin)
This is my code for the annotation.

You should set canShowCallout = true.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKMarkerAnnotationView
if pinView == nil {
pinView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.canShowCallout = true
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}
return pinView
}

yes, you can try this
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
// Always allow callouts to popup when annotations are tapped.
return true
}

Related

Swift Mapview Custom Call Out View with default map view pins

I believe this is going to be a really easy answer but I've been trying to figure out how I add a custom callout view with map views default pins. With my current code it seems I can only add an image as the MKPointAnnotation instead of the default pins. This first "viewFor annotation" is how I set up the default pins, while everything underneath is for the custom call out view... What I am trying to do is have my custom call out view with the default pins. Do I have to add a custom image pin if I want a custom call out view?
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation { return nil }
if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "") {
annotationView.annotation = annotation
return annotationView
} else {
let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:"")
annotationView.isEnabled = true
annotationView.canShowCallout = true
let btn = UIButton(type: .detailDisclosure)
annotationView.rightCalloutAccessoryView = btn
return annotationView
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation { return nil }
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: "Pin")
if annotationView == nil{
annotationView = CustomBusinessCallOutAnnotatiion(annotation: annotation, reuseIdentifier: "Pin")
annotationView?.canShowCallout = false
}else{
annotationView?.annotation = annotation
}
annotationView?.image = UIImage(named: "car")
return annotationView
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if view.annotation is MKUserLocation { return }
let customAnnotation = view.annotation as! CustomBusinessPoint
let views = Bundle.main.loadNibNamed("CustomBusinessCallOut", owner: nil, options: nil)
let calloutView = views?[0] as! CustomBusinessCallOut
calloutView.businessName.text = customAnnotation.businessName
calloutView.businessStreet.text = customAnnotation.businessStreet
calloutView.businessState.text = customAnnotation.businessState
calloutView.businessDistance.text = customAnnotation.businessDistance
calloutView.center = CGPoint(x: view.bounds.size.width / 2, y: -calloutView.bounds.size.height * -0.0001)
view.addSubview(calloutView)
mapView.setCenter((view.annotation?.coordinate)!, animated: true)
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
if view.isKind(of: CustomBusinessCallOutAnnotatiion.self) {
for subview in view.subviews {
subview.removeFromSuperview()
}
}
}
You need not addSubView calloutView. You can use MKAnnotationView as Custom Callout.
e.g. You should arrange the source code
Implement subclass of MKAnnotation and MKAnnotationView.
class PinAnnotation : NSObject, MKAnnotation {
var coordinate : CLLocationCoordinate2D
var title: String?
var calloutAnnotation: CustomBusinessCallOut?
init(location coord:CLLocationCoordinate2D) {
self.coordinate = coord
super.init()
}
}
class CustomBusinessCallOut : NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
init(location coord:CLLocationCoordinate2D) {
self.coordinate = coord
super.init()
}
}
class CalloutAnnotationView : MKAnnotationView {
}
Implement mapView delegate methods.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
if annotation is PinAnnotation {
let reuseId = "Pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
}
else {
pinView?.annotation = annotation
}
return pinView
} else if annotation is CustomBusinessCallOut {
let reuseId = "Callout"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pinView == nil {
pinView = CalloutAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.addSubview(UIImageView(image: UIImage(named: "car")))
}
else {
pinView?.annotation = annotation
}
return pinView
} else {
return nil
}
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
guard view.annotation is PinAnnotation else { return }
if let pinAnnotation = view.annotation as? PinAnnotation {
let calloutAnnotation = CustomBusinessCallOut(location: pinAnnotation.coordinate)
calloutAnnotation.title = pinAnnotation.title
pinAnnotation.calloutAnnotation = calloutAnnotation
mapView.addAnnotation(calloutAnnotation)
}
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
guard view.annotation is PinAnnotation else { return }
if let pinAnnotation = view.annotation as? PinAnnotation,
let calloutAnnotation = pinAnnotation.calloutAnnotation {
mapView.removeAnnotation(calloutAnnotation)
pinAnnotation.calloutAnnotation = nil
}
}

Stop mapkit custom MKAnnotationView disappearing on tap

I currently have a custom MKAnnotationView set in a map callout, and it's working well. I however want to add a button to the callout view, but when i tap the button it closes the annotation view before it gets called. How can i get around this?
Here are pertinent bits of my code:
In my view for annotations:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "mapReuseId"
var mapView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if mapView == nil {
mapView = MKAnnotationView(annotation: annotation as! Annotation, reuseIdentifier: reuseId)
mapView!.canShowCallout = false
} else {
mapView!.annotation = annotation as! Annotation
}
mapDottView!.image = customImage
return mapDottView
}
In my didSelect delegate:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
let callOut = customCallOutView(with: data)
view.addSubview(callOut)
// some layout here
}
The customCallOutView is longish, but the important part is that it has a UIButton which never gets called on tap. Any ideas?
You can try to put a delay when your button is tapped.
You can use Grand Central Dispatch or Perform Selector After Delay.
// Do what you need to do when your button was tapped.
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// Dismiss your annotation.
}
Try the following code:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "mapReuseId"
var mapView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if mapView == nil {
mapView = MKAnnotationView(annotation: annotation as! Annotation, reuseIdentifier: reuseId)
mapView!.canShowCallout = true
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
} else {
mapView!.annotation = annotation as! Annotation
}
mapDottView!.image = customImage
return mapDottView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
print(#function)
// this method will be called when the button is tapped.
// annotation view doesn't disappear
}

How to change selected pin image in Map Kit in Swift 3?

I have a map and on this map I have custom annotation pins. All pins have same custom image. When i click on a pin, i need to change this annotation's image. I was using Google Maps before:
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
if marker.userData as? Int != nil {
let marker_tag = marker.userData as! Int
Datas.selectedMarkerIndex = marker_tag
if let selectedMarker = mapView.selectedMarker {
selectedMarker.icon = UIImage(named: "marker_gray")
}
mapView.selectedMarker = marker
marker.icon = UIImage(named: "marker_red")
}
return true
}
This was working fine. But I dont know how to do it with MapKit. I want to change just selected marker(pin) image. How can I do this?
Also I tried this but not working
How to change non selected annotation pin images on mapkit with Swift
And this is my code:
class CustomPointAnnotation: MKPointAnnotation {
var pinImageName:String!
var userData:Int!
}
extension MyView: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let reuseIdentifier = "my_pin"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
} else {
annotationView?.annotation = annotation
}
let customPointAnnotation = annotation as! CustomPointAnnotation
annotationView?.isDraggable = false
annotationView?.canShowCallout = false
annotationView?.layer.anchorPoint = CGPoint(x: 0.5, y: 1)
annotationView?.image = UIImage(named: customPointAnnotation.pinImageName)
return annotationView
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let anno = view.annotation as? CustomPointAnnotation {
let marker_tag = anno.userData!
print(marker_tag)
}
}
func addMarkersOnMap(){
if Datas.myArray.count != 0 {
Datas.selectedMarkerIndex = 0
for i in 0..<Datas.myArray.count{
let lat = Datas.myArray[i].lat
let lng = Datas.myArray[i].lng
myArray.append(CustomPointAnnotation())
if lat != nil {
let location = CLLocationCoordinate2D(latitude: lat!, longitude: lng!)
myArray[i].pinImageName = "marker_gray"
myArray[i].coordinate = location
myArray[i].userData = i
pinAnnotationView = MKPinAnnotationView(annotation: myArray[i], reuseIdentifier: "my_pin")
mapView.addAnnotation(pinAnnotationView.annotation!)
}
}
"selected" means "tapped"? If so, Try the following code:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
view.image = UIImage(named: "marker_gray")
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
view.image = UIImage(named: "marker_red")
}

How did select annotation title?

How tap or clickable annotation title in Map. For example I have code:
#IBOutlet var Map: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
Map.delegate = self
let location = CLLocationCoordinate2DMake(lat!, lon!)
let span = MKCoordinateSpanMake(0.1, 0.1)
let region = MKCoordinateRegion(center: location, span: span)
Map.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "Title"
Map.addAnnotation(annotation)
}
I try use UITapGestureRecognizer and mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) but it doesn't work. Maybe someone have any ideas
Implement the delegate methods.
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
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
print(#function)
if control == view.rightCalloutAccessoryView {
// Do something
}
}

Show Annotation Title and SubTitle in Custom MKPinAnnotationView

I am using MKPinAnnotationView inside my App.
I am setting MapView object as delegate, and using this code for customising my AnnotationView
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
// pinView!.canShowCallout = true
pinView!.image = UIImage(named:"store.jpg")
pinView!.animatesDrop = true
pinView!.pinTintColor = UIColor.darkGrayColor()
}
else {
pinView!.annotation = annotation
}
return pinView
}
I am getting custom AnnotationView as I required.However, I am missing the features of title and subtitle of MKPointAnnotation.
I wish to see title and subtitle for the grey dots.
I was overriding one func
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
mapView.deselectAnnotation(view.annotation, animated: true)
}
I commented this function out and got the titles and subtitles.
Updated Code
/*
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
mapView.deselectAnnotation(view.annotation, animated: true)
}
*/
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView.canShowCallout = true
pinView.animatesDrop = true
pinView.pinTintColor = UIColor.darkGrayColor()
pinView.draggable = true
pinView.accessibilityLabel = "hello"
let btn = UIButton(type: .DetailDisclosure)
pinView.rightCalloutAccessoryView = btn
return pinView
}

Resources