J'ai du mal à obtenir une annotation personnalisée à charger à l'intérieur de ma vue de carte lorsque j'essaie de placer une épingle.
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate{
@IBAction func ReportBtn(sender: AnyObject) {
//MARK: Report Date And Time Details
let ReportTime = NSDate()
let TimeStamp = NSDateFormatter()
TimeStamp.timeStyle = NSDateFormatterStyle.ShortStyle
TimeStamp.dateStyle = NSDateFormatterStyle.ShortStyle
TimeStamp.stringFromDate(ReportTime)
//MARK: Default Point Annotation Begins
let ReportAnnotation = MKPointAnnotation()
ReportAnnotation.title = "Annotation Created"
ReportAnnotation.subtitle = ReportTime.description
ReportAnnotation.coordinate = locationManager.location!.coordinate
mapView(MainMap, viewForAnnotation: ReportAnnotation)
MainMap.addAnnotation(ReportAnnotation)
}
@IBOutlet weak var MainMap: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.startUpdatingLocation()
self.MainMap.showsUserLocation = true
}
//MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02 ))
self.MainMap.setRegion(region, animated: true)
//self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError){
print(error.localizedDescription)
}
//MARK:Custom Annotation Begins Here
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKindOfClass(MKUserLocation) else {
return nil
}
/*if annotation.isKindOfClass(MKUserLocation){
//emty return, guard wasn't cooperating
}else{
return nil
}*/
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier){
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else{
let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
av.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
annotationView = av
}
if let annotationView = annotationView {
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "image.png")
}
return annotationView
}
}
Je suis certain que la fonctionnalité des boutons fonctionne parfaitement. Avec le code actuel, vidé ci-dessus, l'annotation par défaut de la broche rouge apparaît exactement là où elle devrait. Lorsque je tape sur l'épingle, la description que j'ai spécifiée apparaît également sans problème. Le seul problème que j'ai avec ce code est que je n'arrive pas à faire en sorte que mon image remplace l'ennuyeux pin rouge par défaut
Je recommande de sous-classer `MKPointAnnotation.
J'ai inclus uniquement le code nécessaire pour afficher une épingle de carte personnalisée. Considérez-le comme un modèle.
Aperçu
Nous allons créer un objet d'annotation ponctuelle et attribuer un nom d'image personnalisé à la classe CustomPointAnnotation
.
Nous allons sous-classer le MKPointAnnotation
pour définir l'image et l'assigner sur la méthode du protocole délégué viewForAnnotation
.
Nous ajouterons une vue d'annotation à la carte après avoir défini les coordonnées de l'annotation de point avec un titre et un sous-titre.
Nous allons implémenter la méthode viewForAnnotation
qui est une méthode de protocole MKMapViewDelegate
qui est appelée pour que les broches s'affichent sur la carte. viewForAnnotation
la méthode du protocole est le meilleur endroit pour personnaliser la vue des broches et lui affecter une image personnalisée.
Nous allons retirer la file d'attente et retourner une annotation réutilisable pour l'identifiant donné et convertir l'annotation dans notre classe CustomPointAnnotation
personnalisée afin d'accéder au nom d'image de la broche.
Nous allons créer un nouvel ensemble d'images dans Assets.xcassets
et placez [email protected] et [email protected] en conséquence.
N'oubliez pas plist.
NSLocationAlwaysUsageDescription
et NSLocationWhenInUseUsageDescription
Comme toujours tester sur un vrai appareil.
Le swizzle ????
//1
CustomPointAnnotation.Swift
import UIKit
import MapKit
class CustomPointAnnotation: MKPointAnnotation {
var pinCustomImageName:String!
}
// 2
ViewController.Swift
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
@IBOutlet weak var pokemonMap: MKMapView!
let locationManager = CLLocationManager()
var pointAnnotation:CustomPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
override func viewDidLoad() {
super.viewDidLoad()
//Mark: - Authorization
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
pokemonMap.delegate = self
pokemonMap.mapType = MKMapType.Standard
pokemonMap.showsUserLocation = true
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = CLLocationCoordinate2D(latitude: 35.689949, longitude: 139.697576)
let center = location
let region = MKCoordinateRegionMake(center, MKCoordinateSpan(latitudeDelta: 0.025, longitudeDelta: 0.025))
pokemonMap.setRegion(region, animated: true)
pointAnnotation = CustomPointAnnotation()
pointAnnotation.pinCustomImageName = "Pokemon Pin"
pointAnnotation.coordinate = location
pointAnnotation.title = "POKéSTOP"
pointAnnotation.subtitle = "Pick up some Poké Balls"
pinAnnotationView = MKPinAnnotationView(annotation: pointAnnotation, reuseIdentifier: "pin")
pokemonMap.addAnnotation(pinAnnotationView.annotation!)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error.localizedDescription)
}
//MARK: - Custom Annotation
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let reuseIdentifier = "pin"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
let customPointAnnotation = annotation as! CustomPointAnnotation
annotationView?.image = UIImage(named: customPointAnnotation.pinCustomImageName)
return annotationView
}
}
Il y a quelques problèmes auxquels vous devez faire face.
Tout d'abord, il est nécessaire de comprendre comment MKMapView
affiche une vue d'annotation à partir d'une annotation. Il y a
Un MKAnnotation
contient les données d'un emplacement sur la carte. Vous créez ces données et les remettez à MKMapView
. À un certain moment dans le futur, lorsque la vue de carte sera prête à afficher l'annotation, elle rappellera au délégué et lui demandera de créer un MKAnnotationView
pour un MKAnnotation
. Le délégué crée et renvoie la vue et la vue de la carte l'affiche. Vous spécifiez le délégué dans le storyboard, ou dans le code par exemple mapView.delegate = self
.
Le suivi de l'emplacement des utilisateurs est compliqué par:
Votre code doit gérer l'autorisation en vérifiant CLLocationManager.authorizationStatus
, et implémentant les méthodes CLLocationManagerDelegate
.
Notez que pour utiliser requestWhenInUseAuthorization
nécessite une entrée pour NSLocationWhenInUseUsageDescription
dans Info.plist
Exemple de projet sur GitHub .
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
// Instance of location manager.
// This is is created in viewDidLoad() if location services are available.
var locationManager: CLLocationManager?
// Last location made available CoreLocation.
var currentLocation: MKUserLocation? {
didSet {
// Hide the button if no location is available.
button.hidden = (currentLocation == nil)
}
}
// Date formatter for formatting dates in annotations.
// We use a lazy instance so that it is only created when needed.
lazy var formatter: NSDateFormatter = {
let formatter = NSDateFormatter()
formatter.timeStyle = NSDateFormatterStyle.ShortStyle
formatter.dateStyle = NSDateFormatterStyle.ShortStyle
return formatter
}()
@IBOutlet var button: UIButton!
@IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
// Track the user's location if location services are enabled.
if CLLocationManager.locationServicesEnabled() {
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
switch CLLocationManager.authorizationStatus() {
case .AuthorizedAlways, .AuthorizedWhenInUse:
// Location services authorised.
// Start tracking the user.
locationManager?.startUpdatingLocation()
mapView.showsUserLocation = true
default:
// Request access for location services.
// This will call didChangeAuthorizationStatus on completion.
locationManager?.requestWhenInUseAuthorization()
}
}
}
//
// CLLocationManagerDelegate method
// Called by CLLocationManager when access to authorisation changes.
//
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .AuthorizedAlways, .AuthorizedWhenInUse:
// Location services are authorised, track the user.
locationManager?.startUpdatingLocation()
mapView.showsUserLocation = true
case .Denied, .Restricted:
// Location services not authorised, stop tracking the user.
locationManager?.stopUpdatingLocation()
mapView.showsUserLocation = false
currentLocation = nil
default:
// Location services pending authorisation.
// Alert requesting access is visible at this point.
currentLocation = nil
}
}
//
// MKMapViewDelegate method
// Called when MKMapView updates the user's location.
//
func mapView(mapView: MKMapView, didUpdateUserLocation userLocation: MKUserLocation) {
currentLocation = userLocation
}
@IBAction func addButtonTapped(sender: AnyObject) {
guard let coordinate = currentLocation?.coordinate else {
return
}
let reportTime = NSDate()
let formattedTime = formatter.stringFromDate(reportTime)
let annotation = MKPointAnnotation()
annotation.title = "Annotation Created"
annotation.subtitle = formattedTime
annotation.coordinate = coordinate
mapView.addAnnotation(annotation)
}
//
// From Bhoomi's answer.
//
// MKMapViewDelegate method
// Called when the map view needs to display the annotation.
// E.g. If you drag the map so that the annotation goes offscreen, the annotation view will be recycled. When you drag the annotation back on screen this method will be called again to recreate the view for the annotation.
//
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKindOfClass(MKUserLocation) else {
return nil
}
let annotationIdentifier = "AnnotationIdentifier"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView!.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
annotationView!.canShowCallout = true
}
else {
annotationView!.annotation = annotation
}
annotationView!.image = UIImage(named: "smile")
return annotationView
}
}
vérifiez votre image.png dans votre bundle de projet ou Assets.xcassets
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKindOfClass(MKUserLocation) else {
return nil
}
let annotationIdentifier = "AnnotationIdentifier"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
annotationView!.canShowCallout = true
}
else {
annotationView!.annotation = annotation
}
annotationView!.image = UIImage(named: "image.png")
return annotationView
}
Faites comme suit peut être un travail pour vous.
1) Créez une classe personnalisée pour la broche d'annotation.
class CustomPointAnnotation: MKPointAnnotation {
var imageName: UIImage!
}
2) Définissez la variable comme ci-dessous.
var locationManager = CLLocationManager()
3) Appelez la méthode ci-dessous dans viewDidLoad()
func checkLocationAuthorizationStatus() {
if CLLocationManager.authorizationStatus() == .AuthorizedAlways {
map.showsUserLocation = false
} else {
locationManager.requestWhenInUseAuthorization()
}
}
4) Mettez le code ci-dessous dans viewWillAppear()
self.map.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.delegate = self
dispatch_async(dispatch_get_main_queue(),{
self.locationManager.startUpdatingLocation()
})
5) Mettre en œuvre la méthode la plus importante ci-dessous.
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if !(annotation is CustomPointAnnotation) {
return nil
}
let reuseId = "Location"
var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView!.canShowCallout = true
}
else {
anView!.annotation = annotation
}
let cpa = annotation as! CustomPointAnnotation
anView!.image = cpa.imageName
return anView
}
6) Exécutez le code ci-dessous où vous avez reçu une image de broche personnalisée
let strLat = "YOUR LATITUDE"
let strLon = "YOUR LONGITUDE"
let info = CustomPointAnnotation()
info.coordinate = CLLocationCoordinate2DMake(strLat.toDouble()!,strLon.toDouble()!)
info.imageName = resizedImage
info.title = dict!["locationName"]! as? String
self.map.addAnnotation(info)
D'après le code et selon le guide MapKit, votre code semble correct. Je pense que ça pourrait être cette ligne annotationView.image = UIImage(named: "image.png")
Y a-t-il une chance que image.png
Puisse être le mauvais nom d'image ou ne pas être ajouté au projet lors de la compilation? Juste pour info, si vous utilisez .xcassets
, Vous n'avez pas besoin d'ajouter un .png
.
Comme annotationView.image
Est facultatif, lorsque l'image UIImage(named: "image.png")
est nulle, elle ne se bloquera pas mais restituera simplement l'image de broche par défaut.
Si ce n'est pas le problème, veuillez fournir plus d'informations sur les étapes de débogage que vous avez prises afin que le reste d'entre nous puisse mieux comprendre et vous aider. Acclamations =)