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")
}
Related
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
}
}
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
}
The annotation is displayed in my map but I can't add a callout. I am planing to use the callout to change a label.text to the title of the annotation in the same ViewController.
I tried this for example but what am I missing to make it work.
I hope somebody can help me out since this problem I could solve everything with stackoverflow or youtube but I am trying for hours now :(
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var map: MKMapView!
override func viewDidLoad() {
map.delegate = self
let cor : CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 50, longitude: 10)
let region = MKCoordinateRegionMakeWithDistance(cor, 5000, 5000)
self.map.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate.latitude = 50
annotation.title = "test"
annotation.subtitle = "hdhsadsa"
annotation.coordinate.longitude = 10
map.addAnnotation(annotation)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation { return nil }
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "identifier") as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "identifier")
annotationView?.canShowCallout = true
annotationView?.rightCalloutAccessoryView = UIButton(type: .infoLight)
} else {
annotationView?.annotation = annotation
}
return annotationView
}
}
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
}
}
I'm using a custom annotation in my mapkit project (in swift 3) to show multiple annotations on the map. It's showing and I can click on annotationn but only the first time. For openning the annotation again I need to click everywhere on the map and click again the annotation. Could anybody help me ? Thank you in advance.
Here are the functions I'm using:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation
{
return nil
}
var annotationView = self.map.dequeueReusableAnnotationView(withIdentifier: "Pin")
if annotationView == nil{
annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "Pin")
annotationView?.canShowCallout = false
}else{
annotationView?.annotation = annotation
}
if (indexPin > 0) {
indexPin = indexPin - 1
let pin : PinAnnotation = pinAnotationList[indexPin]
annotationView?.image = UIImage(named: pin.imageName)
}
return annotationView
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView)
{
if view.annotation is MKUserLocation
{
return
}
let pin = view.annotation as! PinAnnotation
if pin.userType == "O" {
if (currentLatitude == 0 || currentLatitude2 == 0) {
self.showAlert(self, message: "It's necessary to set origin and destiny addresses")
return
}
AppVars.DriverId = pin.userId
AppVars.VehicleId = pin.vehicleId
AppVars.LatitudeDriver = pin.coordinate.latitude
AppVars.LongitudeDriver = pin.coordinate.longitude
performSegue(withIdentifier: "callDriverPopupSegue", sender: self)
}
else {
let customView = (Bundle.main.loadNibNamed("AnnotationView", owner: self, options: nil))?[0] as! CustomCalloutView
var calloutViewFrame = customView.frame;
let point = CGPoint(x: calloutViewFrame.size.width/2 + 15,y :calloutViewFrame.size.height - 10)
calloutViewFrame.origin = point
customView.frame = calloutViewFrame;
customView.titleLabel.text = pin.title
view.addSubview(customView)
}
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
if (view.isKind(of: PinAnnotation.self))
{
for subview in view.subviews
{
subview.removeFromSuperview()
}
}
if (view.isKind(of: AnnotationView.self))
{
for subview in view.subviews
{
subview.removeFromSuperview()
}
}
}
Class PinAnnotation
import MapKit
class PinAnnotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var userId: Int!
var vehicleId:Int!
var userType: String!
var imageName: String!
var title: String!
init(coordinate: CLLocationCoordinate2D) {
self.coordinate = coordinate
}
}
Class AnnotationView
import MapKit
class AnnotationView: MKAnnotationView
{
}
I've found a solution ! The situation occurred when called performSegue(withIdentifier: "callDriverPopupSegue", sender: self) in didSelect because the annotation that was clicked keeped selected. So I add the code bellow in mapview controller to deselect the annotation and after that I was able to click for the second time.
override func viewWillAppear(_ animated: Bool) {
DispatchQueue.main.async {
for item in self.map.selectedAnnotations {
self.map.deselectAnnotation(item, animated: false)
}
}
}