confusão de viewForAnnotation e personalização do pinColor iterativamente
O objetivo é personalizar as cores dos pinos de acordo com alguns valores armazenados em uma matriz de estrutura.
Por alguma ajuda aqui, implementei o seguinte método delegado viewForAnnotation e que funciona muito bem chamando esse método delegado iterativamente em um loop com base no tamanho da minha matriz de dados de estrutura. Portanto, funciona se eu quiser definir todos os pinos para uma cor, roxa, por exemplo (que é a linha comentada no código abaixo).
O problema é que, quando eu coloco uma opção para definir a cor com base em um valor da minha matriz, ele passa por esse código, mas não respeita nenhum dos valores de maiúsculas e minúsculas para defini-lo para uma cor alternativa e tudo passa para um alfinete vermelho (aparentemente o padrão). Eu imprimi o status e depurei para saber que ele está entrando no comutador e configurando o pinColor de acordo, mas eles não parecem grudar.
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 do meu loop for no ViewController, chamo isso da seguinte maneira, mas não faço nada com o retorno.
// previous to this I setup some Titles and Subtitle which work fine
self.theMapView.addAnnotation(myAnnotation)
// Call to my mapview
mapView(theMapView, viewForAnnotation: myAnnotation)
Eu não faço nada com o Pinview de retorno - acho que não precisava, mas todos os pinos ficam vermelhos nesse momento ao usar o código do switch. Fundamentalmente, devo estar faltando alguma coisa aqui.
7-8-14 Atualizações para resolver problemas com o código revisado pela grande ajuda / tutoria de Anna. TKS!
Quase funciona. Todos os pinos no mapa têm as cores certas, mas as que estão fora da exibição imediata às vezes estão erradas. A publicação de todo o código envolvido aqui, pois isso pode ajudar outras pessoas, pois essa parece ser uma pergunta muito comum sobre como fazer um trabalho personalizado no Maps.
Uma classe personalizada, conforme sugerido, para manter outra variável em uma anotação personalizada - nesse caso, o valor do status proveniente da minha estrutura de dados, 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
}
}
O mapView revisado - agora utilizando o novo CustomMapPinAnnotation que está sendo passado para ele:
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
No viewDidCarregue a configuração e o loop For para configurar as anotações
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
A saída de depuração mostra que o loop For é executado até o final conforme o esperado para criar os myCustomPinAnnotation antes que o viewForAnnotation personalizado no mapView seja executado internamente por conta própria. À medida que movo o mapa para áreas fora da visualização imediata, noto que a viewForAnnotation no mapView é chamada conforme necessário e vejo meu switch sendo executado adequadamente, mas as cores dos pinos nem sempre estão corretas. Todos os pinos no mapa de exibição inicial estão corretos todas as vezes, então é sobre esses da região externa que eu estou preso no momento em que eles estão desligados.