Reputation: 365
This is my code and i want to add a custom pin (.png file) instead of the red pin. I tried to use MKPinAnnotationView
and MKAnnotationView
but i couldn't add coordinates, subtitles and title. I'm new to iOS development.
override func viewDidLoad() {
super.viewDidLoad()
// Handle the text field’s user input through delegate callbacks.
commentTextField.delegate = self
coreLocationManager.delegate = self
//desired accuracy is the best accuracy, very accurate data for the location
coreLocationManager.desiredAccuracy = kCLLocationAccuracyBest
//request authorization from the user when user using my app
coreLocationManager.requestWhenInUseAuthorization()
coreLocationManager.startUpdatingLocation()
dbRef = FIRDatabase.database().reference()
struct Location {
let title: String
let latitude: Double
let longitude: Double
let subtitle: String
}
// Locations array
let locations = [
Location(title: "Dio Con Dio", latitude: 40.590130, longitude: 23.036610,subtitle: "cafe"),
Location(title: "Paradosiako - Panorama", latitude: 40.590102, longitude: 23.036180,subtitle: "cafe"),
Location(title: "Veranda", latitude: 40.607740, longitude: 23.103044,subtitle: "cafe")
]
for location in locations {
let annotation = MKPointAnnotation()
annotation.title = location.title
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
annotation.subtitle = location.subtitle
map.addAnnotation(annotation)
}
}
I am using Swift 3.
Upvotes: 13
Views: 12300
Reputation: 437372
FWIW, nowadays I would generally not implement mapView(_:viewFor:)
at all. I would just register my annotation view in viewDidLoad
:
mapView.register(DogAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
And I would have an annotation view subclass, which configures the annotation view as appropriate:
class DogAnnotationView: MKAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
configure(for: annotation)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure(for: annotation)
}
override var annotation: MKAnnotation? { didSet { configure(for: annotation) } }
private func configure(for annotation: MKAnnotation?) {
image = UIImage(systemName: "dog.fill")
…
}
}
Yielding:
Or we might use MKMarkerAnnotationView
:
class DogAnnotationView: MKMarkerAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
configure(for: annotation)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure(for: annotation)
}
override var annotation: MKAnnotation? { didSet { configure(for: annotation) } }
private func configure(for annotation: MKAnnotation?) {
glyphImage = UIImage(systemName: "dog.fill")
…
}
}
Yielding:
Either way, you can do whatever configuration of the annotation view you want (e.g., I generally use clustering by setting clusteringIdentifier
and register another annotation view class for MKMapViewDefaultClusterAnnotationViewReuseIdentifier
), but that is not relevant here. The idea is to just register the annotation view class and put its configuration in that annotation view class rather than contributing to view controller bloat with MKMapViewDelegate
method mapView(_:viewFor:)
.
For posterity’s sake, my original answer with mapView(_:viewFor:)
is below.
You need to specify your view controller as the delegate for the map view (either in IB or programmatically in viewDidLoad
and then (a) specify that you're conforming to the MKMapViewDelegate
protocol; and (b) implement mapView(_:viewFor:)
:
extension ViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MyPin"
if annotation is MKUserLocation {
return nil
}
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
annotationView?.image = UIImage(named: "custom_pin.png")
// if you want a disclosure button, you'd might do something like:
//
// let detailButton = UIButton(type: .detailDisclosure)
// annotationView?.rightCalloutAccessoryView = detailButton
} else {
annotationView?.annotation = annotation
}
return annotationView
}
}
For more information, see the Location and Maps Programming Guide: Creating Annotation Views from Your Delegate Object. The code snippets are in Objective-C, but it describes the basic process.
Upvotes: 20
Reputation: 169
use this method:
optional func mapView(_ mapView: MKMapView,
didAdd views: [MKAnnotationView])
works fine for me. (My environment: Xcode 9.4.1 and iOS 11.4.1)
Example:
func mapView(_ mapView: MKMapView,
didAdd views: [MKAnnotationView])
{
//views[0] = just added MKAnnotationView
let pic = UIImage(named: "abc.jpg")
views[0].image = pic
views[0].layer.cornerRadius = (views[0].frame.size.width) / 2
views[0].clipsToBounds = true
print("fafafjejowfjpeawijoefaw")
}
Upvotes: -1
Reputation: 1
I added it in this way:
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
let sourceView = views.first
sourceView?.image = UIImage(named: "Bus")
let destinationView = views.last
destinationView?.image = UIImage(named: "Home")
}
Upvotes: -1
Reputation: 41
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MyPin"
if annotation.isKindOfClass(MKUserLocation) {
return nil
}
let detailButton: UIButton = UIButton(type: UIButtonType.DetailDisclosure)
if let annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "pin")
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "custom_pin.png")
annotationView.rightCalloutAccessoryView = detailButton
}
else {
annotationView.annotation = annotation
}
return annotationView
}
Upvotes: -1
Reputation: 159
SWIFT 5
let pointAnnotation = MKPointAnnotation()
override func viewDidLoad()
{
mapVw.delegate = self
pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: yourLatitude, longitude:yourLongitude)
mapVw.addAnnotation(pointAnnotation)
}
// MARK:- MapView Delegate
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if annotation is MKUserLocation
{
return nil;
}else{
let pinIdent = "Pin";
var pinView: MKAnnotationView?
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: pinIdent)
{
dequeuedView.annotation = annotation;
pinView = dequeuedView;
}
else
{
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: pinIdent);
pinView?.image = UIImage(named: "yourImage")
}
return pinView;
}
}
Upvotes: 0
Reputation: 365
Finally i did it this way, on my own!
ViewController.swift
//
// ViewController.swift
//
// Created by Alexandros Andreadis on 19/04/2017.
// Copyright © 2017 Alexandros Andreadis. All rights reserved.
//
import UIKit
import MapKit
import CoreLocation
import FirebaseDatabase
class RateViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, CLLocationManagerDelegate, MKMapViewDelegate{
let pin = UIImage(named: "pin")
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if let annotation = annotation as? Locations{
if let view = mapView.dequeueReusableAnnotationView(withIdentifier: annotation.identifier){
return view
}else{
let view = MKAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
view.image = pin
view.isEnabled = true
view.canShowCallout = true
//view.leftCalloutAccessoryView = UIImageView(image: pin)
return view
}
}
return nil
}
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
mapView.addAnnotations(locations)
}
}
Locations.swift
//
// Locations.swift
//
// Created by Alexandros Andreadis on 10/05/2017.
// Copyright © 2017 Alexandros Andreadis. All rights reserved.
//
import UIKit
import MapKit
class Locations: NSObject, MKAnnotation {
// required coordinate, title, and the reuse identifier for this annotation
var identifier = "locations"
var title: String?
var coordinate: CLLocationCoordinate2D
//initializer taking a name, a latitude and longitude to populate the title and coordinate for each instance of this object
init(name:String,lat:CLLocationDegrees,long:CLLocationDegrees){
title = name
coordinate = CLLocationCoordinate2DMake(lat, long)
}
}
// Creating the list of the places that will be pinned in map
class LocationList: NSObject {
var Location = [Locations]()
override init(){
Location += [Locations(name: "Dio Con Dio", lat: 40.590130, long: 23.036610)]
Location += [Locations(name: "Paradosiako - Panorama", lat: 40.590102, long:23.036180)]
Location += [Locations(name: "Veranda", lat: 40.607740, long: 23.103044)]
Location += [Locations(name: "Markiz", lat: 40.634252, long: 22.936276)]
Location += [Locations(name: "Moi Lounge Bar", lat: 40.653481, long: 22.994131)]
Location += [Locations(name: "Boulevard Lounge Bar", lat: 40.658462, long: 22.983198)]
Location += [Locations(name: "Ernést Hébrard", lat: 40.631829, long: 22.941014)]
Location += [Locations(name: "Tribeca - All Day & Night Bar", lat: 40.631029, long: 22.942396)]
}
}
Upvotes: 1