Confusión viewForAnnotation y personalización del pinColor iterativamente
El objetivo es personalizar los colores del pin según algunos valores almacenados en una matriz de estructura.
Por alguna ayuda aquí implementé el siguiente método delegado viewForAnnotation y eso funciona muy bien llamando a este método delegado iterativamente en un bucle basado en el tamaño de mi matriz de datos de estructura. Por lo tanto, funciona si quiero establecer todos los pines en un color, púrpura, por ejemplo (que es la línea comentada en el código a continuación).
El problema es que cuando pongo un interruptor para establecer el color en función de un valor en mi matriz, pasa por este código pero no respeta ninguno de los valores de mayúsculas y minúsculas para establecerlo en un color alternativo y todo va a un pin rojo (aparentemente el valor por defecto). Imprimí el estado y lo depuré para saber que está entrando en el interruptor y configurando los colores de pin en consecuencia, pero parece que no se pegan.
func mapView(aMapView: MKMapView!,
viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
let theindex = mystructindex // grab the index from a global to be used below
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
// Preventive if to keep this from being called beyond my arrays index value as the delegate getting called beyond the for loop for some unknown reason
if (theindex < MySupplierData.count) {
// Set the pin color based on the status value in MySupplierData structure array
switch MySupplierData[mystructindex].status {
case 0,1:
println("Case 0 or 1 - setting to Red")
pinView!.pinColor = .Red // Needs help, show red pin
case 2:
println("Case 2 - Setting to Green")
pinView!.pinColor = .Green // Looking Good
case 3:
println("Case 3 - Setting to Purple")
pinView!.pinColor = .Purple // Could use a follow-up
default:
println("Case default - Should Never Happen")
break;
} // end switch
} // end if
// pinView!.pinColor = .Purple // This works fine without the switch and respects any color I set it to.
}
else {
pinView!.annotation = annotation
}
return pinView
}
Dentro de mi bucle for dentro del ViewController, lo llamo de la siguiente manera, pero no hago nada con la devolución.
// previous to this I setup some Titles and Subtitle which work fine
self.theMapView.addAnnotation(myAnnotation)
// Call to my mapview
mapView(theMapView, viewForAnnotation: myAnnotation)
No hago nada con el Pinview de retorno: no pensé que fuera necesario, pero todos los pines se dibujan en rojo en este punto cuando uso el código del interruptor. Básicamente, me falta algo aquí.
7-8-14 Actualizaciones para resolver problemas con código revisado según la gran ayuda / tutoría de Anna. TKS!
Casi funciona, todos los pines dentro del mapa tienen los colores correctos, pero los que están fuera de la pantalla inmediata a veces son incorrectos. Publicar todo el código involucrado aquí, ya que puede ayudar a otros, ya que esta parece ser una pregunta muy común sobre cómo hacer un trabajo personalizado dentro de Maps.
Una clase personalizada como se sugiere para contener otra variable en una anotación personalizada, en este caso el valor de estado proveniente de mi estructura de datos, MySupplierData.
class CustomMapPinAnnotation : NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String
var subtitle: String
var status: Int
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, status: Int) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.status = status
}
}
MapView revisado: ahora utiliza la nueva CustomMapPinAnnotation que se le pasa:
func mapView(aMapView: MKMapView!,
viewForAnnotation annotation: CustomMapPinAnnotation!) -> MKAnnotationView! {
let reuseId = "pin"
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
// Code to catch my custom CustomMapPinAnnotation so we can check the status and set the color
if annotation.isKindOfClass(CustomMapPinAnnotation)
{
println("FOUND OUR CustomMapPinAnnotation CLASS IN mapView")
println(" Custom Title = \(annotation.title)")
println(" Custom status passed = \(annotation.status)")
switch annotation.status {
case 0,1:
println("Case 0 or 1 - Setting to Red")
pinView!.pinColor = .Red
case 2:
println("Case 2 - Setting to Green")
pinView!.pinColor = .Green
case 3:
println("Case 3 - Setting to Purple")
pinView!.pinColor = .Purple
default:
println("Case default - Should Never Happen")
break;
} // switch
} // if
}
else {
pinView!.annotation = annotation
}
return pinView
} //func mapView
En viewDidLoad la configuración y el bucle For para configurar las anotaciones
override func viewDidLoad() {
super.viewDidLoad()
// setup the region and Span
var theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
// Set the region to the the first element of the structure array.
var theRegion:MKCoordinateRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(MySupplierData[0].latitude, MySupplierData[0].longitude), theSpan)
// This set the Map Type (Standard, Satellite, Hybrid)
self.theMapView.mapType = MKMapType.Standard
// Now loop through the structure data from 1 top the end of the structure to map the data
var mytitle: String = ""
var mysubtitle: String = ""
var myCustomPinAnnotation: CustomMapPinAnnotation
for mystructindex = 0; mystructindex < MySupplierData.count; ++mystructindex {
println("INSIDE SUPPLIER LOOP INDEX = \(mystructindex)" )
switch MySupplierData[mystructindex].status {
case 0:
mytitle = "(Red) " + MySupplierData[mystructindex].company
case 1:
mytitle = "(Red) " + MySupplierData[mystructindex].company
case 2:
mytitle = "(Geeen) " + MySupplierData[mystructindex].company
case 3:
mytitle = "(Purple) " + MySupplierData[mystructindex].company
default:
mytitle = "? " + MySupplierData[mystructindex].company
}
mysubtitle = MySupplierData[mystructindex].subtitle
// Create the Custom Annotations with my added status code
myCustomPinAnnotation = CustomMapPinAnnotation(
coordinate: CLLocationCoordinate2DMake(MySupplierData[mystructindex].latitude,MySupplierData[mystructindex].longitude),
title: mytitle, // custom title
subtitle: mysubtitle, // custom subtitle
status: MySupplierData[mystructindex].status) // status that will drive pin color
// put this annotation in the view.
self.theMapView.addAnnotation(myCustomPinAnnotation)
} // For
// This line brings up the display with the specific region in mind, otherwise it seems to default to a US Map.
self.theMapView.setRegion(theRegion, animated: true)
} // viewDidLoad
La salida de depuración muestra que el bucle For se ejecuta hasta su finalización como se esperaba para crear myCustomPinAnnotation antes de que la vista personalizada ForAnnotation en mapView se ejecute internamente. A medida que muevo el mapa a áreas fuera de la vista inmediata, noto que se llama a viewForAnnotation en mapView según sea necesario y veo que mi interruptor se ejecuta en consecuencia, pero los colores del pin no siempre son correctos. Todos los pines dentro del mapa de visualización inicial son correctos cada vez, por lo que son estos en la región exterior en los que estoy atrapado actualmente por qué están apagados.