How to add iOS 10 default annotation/pin? - ios

I have a MapView in my app. And user can add an annotaion/pin to that MapView. I works fine but I would like to know if it is possible to add new annotation design.
This is the new pin:
This is what my map shows:
This is my annotation code:
let annotaion = MKPointAnnotation()
this line adds my annotation to map:
self.myMap.addAnnotation(self.annotaion)
Thank you.

I believe #0ndre_ was looking for the default image, not to bring in his own custom image. The answer by #Franco_Meloni was incomplete. Here is how I got it to work.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let pin = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.canShowCallout = true
let button = UIButton(type: .detailDisclosure)
pin.rightCalloutAccessoryView = button
if annotation.isEqual(mapView.userLocation) {
return nil
}
return pin
}
The key is using MKMarkerAnnotationView to get the bigger marker. If you use MKPinAnnotationView you will see the smaller one appear.

You should implement
mapView(_ mapView: MKMapView,
viewFor annotation: MKAnnotation) -> MKAnnotationView?
from MKMapViewDelegate (https://developer.apple.com/reference/mapkit/mkmapviewdelegate/1452045-mapview)
Implementation example:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let view = MKAnnotationView()
view.image = UIImage(named: "pin")
return view
}

Related

How to get rid of the MKBalloonCalloutView in iOS 14

I have the following code which works for iOS 13 and lower.
func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
mapView.userLocation.title = "You are here"
mapView.userLocation.subtitle = // user's location
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isKind(of: MKUserLocation.self) {
return nil
}
}
It shows only the blue dot without a callout and above the blue dot is just the title and subtitle.
But on iOS 14 there is a default MKBalloonCalloutView that appears in place of the title and subtitle. It shows a gray profileImage. How can I get rid of the BalloonCallout so I can show just the title and subtitle?
By setting your own detail detailCalloutAccessoryView for the User Location annotation's MKAnnotationView the behaviour reverts to just showing title and subtitle.
You can set any UIView of your choice, like an UIImageView for example, or just an empty one.
For example in your MKMapViewDelegate
func mapViewDidFinishLoadingMap(_ mapView: MKMapView) {
mapView.view(for: mapView.userLocation)?.detailCalloutAccessoryView = .init()
}
For the user (the one from the question), if using iOS 14 and higher I use MKMarkerAnnotationView,. If using iOS 13 or lower I use MKPinAnnotationView. I have a separate custom pin for everyone else:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let reuseIdentifier = "MyIdentifier"
if annotation.isKind(of: MKUserLocation.self) {
if #available(iOS 14.0, *) {
if let pin = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier) as? MKMarkerAnnotationView {
return setMKMarkerAnnotationView(pin: pin)
}
} else {
let pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
pin.canShowCallout = true
return pin
}
return nil
} else {
// dequeue the custom pins for everyone else
}
}
func setMKMarkerAnnotationView(pin: MKMarkerAnnotationView) -> MKMarkerAnnotationView {
pin.animatesWhenAdded = true
pin.markerTintColor = UIColor.red
pin.titleVisibility = .visible
pin.subtitleVisibility = .visible
return pin
}

Invalid redeclaration of 'mapView(_:viewFor:)'

So I'm trying to create an app with custom annotations on the map, and I've been following a tutorial on how to do it. However when I put this code in, its giving me the error
Invalid redeclaration of 'mapView(_:viewFor:)'
Here's the tutorial - https://www.youtube.com/watch?v=w_aw72i8P_U
extension ViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let _annotation = annotation as? MyAnnotation else {return }
let identifier = "marker"
var view: MKMarkerAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
}
else
{
view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
return view
}
}
This normally happens when you already implemented that method elsewhere.
Check your ViewController to make sure you don't have func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {} implemented outside of that extension.

How to change markerTintColor in MapKit without changing default location pin in Swift?

I have MKMarkerAnnotationView to change color of pins on my map.
func mapView(_ MapView:MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{
let view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "pin")
view.markerTintColor = .blue
return view
}
But, when I start my app, marker of my defoult location changes to.
How can I change pin without changing this marker?
Code to view location is also simple
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
self.MapView.showsUserLocation = true
}
Thanks for answer! :)
You could check if the annotation is the user location like this:
func mapView(_ MapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "pin")
view.markerTintColor = .blue
return view
}
In your method, check to see if the annotation object is an instance of MKUserLocation. If it is, return nil to keep the standard user location annotation view.
(The Docs for mapView(_:viewFor:) explain this.)

Annotation title not appearing when adding viewForAnnotation

I have added this:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "id")
if let title = annotation.title{
if title! == "P"{
pinView.pinTintColor = UIColor.yellow
}
else{
pinView.pinTintColor = UIColor.gray
}
}
return pinView
}
But when I do this I can´t see my titles when I click on an annotation anymore, any ideas why?
You need to add the canShowCallout on your pinView. If the value of the canShowCallout property is true, a standard callout bubble is shown when the user taps a selected annotation view. The callout uses the title and subtitle text from the associated annotation object.
So just add the following row to your viewFor function and you´ll see the title.
pinView.canShowCallout = true

Swift MapKit custom current location marker

This is what my project currently looks like. My questions is, how do I change the blue ball (current location) to a custom image or icon?
I am sure you know that a user is used to seeing that blue-dot as the current user's location. You shouldn't change it unless you have a good reason.
Here is how to change it:
Set the delegate for the mapView, and then override the following function... something like this:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
let pin = mapView.view(for: annotation) as? MKPinAnnotationView ?? MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.pinTintColor = UIColor.purple
return pin
} else {
// handle other annotations
}
return nil
}
and to have an image displayed instead:
Just replace the code inside if statement with the following code:
let pin = mapView.view(for: annotation) as? MKPinAnnotationView ?? MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.image = UIImage(named: "user_location_pin")
return pin
I think this code sample should give you enough information to help you figure out what to do. (Note that mapView is created in a storyboard...)
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
let loc = CLLocationManager()
var angle = 0
var timer: NSTimer!
var userPinView: MKAnnotationView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
loc.requestWhenInUseAuthorization()
timer = NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: #selector(rotateMe), userInfo: nil, repeats: true)
}
func rotateMe() {
angle = angle + 10
userPinView?.transform = CGAffineTransformMakeRotation( CGFloat( (Double(angle) / 360.0) * M_PI ) )
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
let pin = mapView.viewForAnnotation(annotation) ?? MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.image = UIImage(named: "userPinImage")
userPinView = pin
return pin
} else {
// handle other annotations
}
return nil
}
}
You can customise the view using MKMapDelegate's method:
optional func mapView(_ mapView: MKMapView,
viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?
Parameters
mapView - The map view that requested the annotation view.
annotation - The object representing the annotation that is about to be displayed. In addition to your custom annotations, this object
could be an MKUserLocation object representing the user’s current
location.
See full the documentation here
Also please see the following SO question for updating the view when user location changes:
Custom Annotation view for userlocation not moving the mapview

Resources