viewForAnnotation混淆并迭代定制pinColor [英] viewForAnnotation confusion and customizing the pinColor iteratively

查看:91
本文介绍了viewForAnnotation混淆并迭代定制pinColor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标是根据结构数组中存储的每个值自定义引脚颜色。



在这里,我实现了以下viewForAnnotation委托方法,并且有效伟大的基于我的结构数据数组的大小在循环中迭代地调用这个委托方法。因此,如果我想将所有引脚设置为一种颜色,例如紫色(这是下面代码中的注释行),它就可以工作。



问题是,当我根据数组中的值设置颜色时,它会通过此代码,但不会考虑任何案例值将它设置为备用颜色,一切都变为红色引脚(看似默认)。我打印出状态并进行调试,知道它已进入开关并相应地设置了pinColor,但它们似乎没有坚持。

  func mapView(aMapView:MKMapView!,
viewForAnnotation批注:MKAnnotation!) - > MKAnnotationView! {

让theindex = mystructindex //从全局获取索引,如果注释是MKUserLocation,则使用

以下{
//返回nil所以map视图绘制标识用户位置的蓝点
返回nil
}

让reuseId =pin
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)为? MKPinAnnotationView

如果pinView == nil {
// println(Pinview为零)
pinView = MKPinAnnotationView(注释:annotation,reuseIdentifier:reuseId)
pinView !.canShowCallout = true
pinView!.animatesDrop = true

//预防性如果不让我的数组被调用超出我的数组索引值,因为代理被调用超出了for循环的一些未知原因

if(theindex< MySupplierData.count){

//根据MySupplierData结构数组中的状态值设置引脚颜色
切换MySupplierData [mystructindex ] .status {

case 0,1:
println(Case 0 or 1 - setting to Red)
pinView!.pinColor = .Red //需要帮助, show red pin
case 2:
println(Case 2 - Setting to Green)
pinView!.pinColor = .Green //好看
案例3:
println(案例3 - 设置为紫色)
pinView!.pinColor = .Purple //可以使用关注-up
默认值:
println(案例默认值 - 应该永远不会发生)
break;

} //结束开关
} //结束如果

// pinView!.pinColor = .Purple //没有开关就可以正常工作并尊重任何颜色我把它设置为。
}
else {
pinView!.annotation = annotation
}

return pinView
}

在ViewController中我的for循环中我按如下方式调用它,但是我没有对返回做任何事情。

  //在此之前,我设置了一些标题和副标题,其工作正常
self.theMapView.addAnnotation(myAnnotation)
//调用我的mapview
mapView(theMapView,viewForAnnotation:myAnnotation)

我不做任何返回Pinview的东西 - 我认为我不需要,但是当使用开关代码时,所有的引脚都会被拉红。从根本上说,我必须在这里遗漏一些东西。






7-8-14更新以解决修改后的代码问题每个Anna的帮助很大/辅导。 TKS!



它几乎可以正常工作,地图中的所有引脚都有正确的颜色,但
立即显示之外的引脚有时是错误的。发布此处涉及的所有代码,因为它可以帮助其他人
,因为这似乎是关于如何在地图中进行自定义工作的一个非常常见的问题。



建议在自定义注释中保存其他变量的自定义类 - 在这种情况下,状态值来自我的数据结构MySupplierData。

  class CustomMapPinAnnotation:NSObject,MKAnnotation {
var坐标:CLLocationCoordinate2D
var title:String
var subtitle:String
var status:Int

init(坐标:CLLocationCoordinate2D,title:String,subtitle:String,status:Int){
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.status = status

}
}

修改后的mapView - 现在使用传递给它的新CustomMapPinAnnotation:

  func mapView(aMapView:MKMapView!,
viewForAnnotation批注:CustomMapPinAnnotation!) - > MKAnnotationView! {

让reuseId =pin
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)为? MKPinAnnotationView

如果pinView == nil {
// println(Pinview为零)
pinView = MKPinAnnotationView(注释:annotation,reuseIdentifier:reuseId)
pinView !.canShowCallout = true
pinView!.animatesDrop = true

//捕获我的自定义CustomMapPinAnnotation的代码,以便我们可以检查状态并设置颜色
if annotation.isKindOfClass( CustomMapPinAnnotation)
{
println(在mapView中找到我们的CustomMapPinAnnotation CLASS)
println(自定义标题= \(annotation.title))
println(自定义状态传递= \(annotation.status))
切换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
默认值:
println(Case default - Should Never Happen)
break;
} //切换
} //如果
}
else {
pinView!.annotation = annotation
}
return pinView
} // func mapView

在viewDidLoad中设置和For循环来设置注释

 覆盖func viewDidLoad(){
super.viewDidLoad()

//设置区域和Span
var theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta,longDelta)

//将区域设置为结构数组的第一个元素。
var theRegion:MKCoordinateRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(MySupplierData [0] .latitude,MySupplierData [0] .longitude),theSpan)

//这设置了地图类型(标准,卫星,混合)
self.theMapView.mapType = MKMapType.Standard

//现在循环结构数据从结构末端的1顶部开始映射数据

var mytitle:String =
var mysubtitle:String =
var myCustomPinAnnotation:CustomMapPinAnnotation

for mystructindex = 0; mystructindex< MySupplierData.count; ++ mystructindex {
println(INSIDE SUPPLIER LOOP INDEX = \(mystructindex))

切换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
默认值:
mytitle =?+ MySupplierData [mystructindex] .company

}
mysubtitle = MySupplierData [mystructindex] .subtitle

//使用我添加的状态创建自定义注释code
myCustomPinAnnotation = CustomMapPinAnnotation(
坐标:CLLocationCoordinate2DMake(MySupplierData [mystructindex] .latitude,MySupplierData [mystructindex] .longitude),
标题:mytitle,//自定义标题
副标题:mysubtitle,//自定义字幕
状态:MySupplierData [mystructindex] .status)//将驱动的状态pin颜色

//将此注释放在视图中。
self.theMapView.addAnnotation(myCustomPinAnnotation)
} //对于

//此行显示特定区域的显示,否则它似乎默认为美国地图。
self.theMapView.setRegion(theRegion,animated:true)

} // viewDidLoad

调试输出显示For循环执行完成按预期创建myCustomPinAnnotation,然后mapView中的自定义viewForAnnotation在内部执行
。当我将地图移动到直接视图之外的区域时,我注意到mapView中的viewForAnnotation会根据需要调用
并且我看到我的开关相应地执行但是引脚颜色并不总是正确的。初始显示图中的所有引脚每次都是正确的,所以
就是这些外部区域我目前所关注的是为什么它们关闭了。

解决方案

首先,代码应 调用 viewForAnnotation 显式本身。

addAnnotation 行之后删除对 viewForAnnotation 的显式调用。 / p>

viewForAnnotation 是一种委托方法,地图视图会在需要时自动调用显示注释。如果没有自动调用,请确保设置了地图视图的委托属性(例如, self )。 / p>



第二(以及真正的问题),是代码假定 viewForAnnotation 委托方法只会在添加每个注释后立即调用一次。



情况并非如此,不能保证。只要需要显示注释,地图视图就会调用 viewForAnnotation ,并且可以多次为相同的注释调用,或者在实际添加注释后很长时间(例如,在用户平底锅之后)或缩放地图,注释进入视图)。



参见 MKAnnotationView是否缓冲其输入队列?以获取一些其他详细信息以及其他答案的相关链接,包括示例代码。



基本上,您必须使用注释对象本身存储影响注释视图的属性,并从传递到 viewForAnnotation 注释参数中检索这些属性c $ c>。





我建议您使用的是:



我假设您使用的是内置注释类 MKPointAnnotation 。而不是使用 MKPointAnnotation ,它不允许您将自定义 status 属性与注释对象本身一起存储,或者:




  • 创建一个实现 MKAnnotation 协议的自定义类,但也包含 status property。在创建注释时设置此属性,并从传递到 viewForAnnotation 注释参数中提取其值,并设置<$ c因此,$ c> pinColor 。请参阅链接答案中的示例代码。


  • MySupplierData 中创建对象本身实现 MKAnnotation 协议的对象。因此,如果 MySupplierData 中的对象是某个类的实例,例如 Supplier ,请设为 Supplier class符合 MKAnnotation 协议,然后您可以添加 MySupplierData 对象本身调用 addAnnotation 时到地图视图。



The goal is to customize the pin colors per some values stored in an structure array.

Per some help here I implemented the the following viewForAnnotation delegate method and that works great calling this delegate method iteratively in a loop based on the size of my structure data array. So it works if I want to set all the pins to one color, purple for example (which is the commented line in the code below).

The problem is when I put in a switch to set the color based on a value in my array it goes through this code but does not respect any of the case values to set it to an alternate color and everything goes to a red pin (seemingly the default). I've printed out the status and debugged to know it is getting inside the switch and setting pinColor's accordingly but they don't seem to stick.

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
}

Inside my for loop within the ViewController I call this as follows, but I don't do anything with the return.

        // previous to this I setup some Titles and Subtitle which work fine
        self.theMapView.addAnnotation(myAnnotation)
        // Call to my mapview   
        mapView(theMapView, viewForAnnotation: myAnnotation)

I don't do anything with the return Pinview - didn't think I needed to but all the pins get drawn red at this point when using the switch code. Fundamentally I must be missing something here.


7-8-14 Updates to address problems with revised code per Anna's great help/tutoring. TKS!

It almost works, All pins within the Map have the right colors but ones outside of the immediate display are sometimes wrong. Posting all the code involved here since it may help others as this seems to be a very common question on how to do custom work within Maps.

A custom class as suggested to hold other variable in a custom annotation - in this case the status value coming from my data structure, 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

  }
}

The revised mapView - now utilizing the new CustomMapPinAnnotation being passed to it:

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

Within viewDidLoad the setup and For loop to setup the annotations

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

Debug output shows the For loop executes to completion as expected to create the myCustomPinAnnotation's before the custom viewForAnnotation in mapView gets executed on its own internally. As I move the map to areas outside the immediate view I do note the viewForAnnotation in mapView gets called as needed and I see my switch executing accordingly but the pin colors are not always correct. All the pins within the initial display map are correct every time so it's these outer region ones I am stuck on currently as to why they are off.

解决方案

First, the code should not be calling viewForAnnotation explicitly itself.
Remove the explicit call to viewForAnnotation after the addAnnotation line.

viewForAnnotation is a delegate method and the map view will call it automatically when it needs to display an annotation. If it's not getting called automatically, make sure the map view's delegate property is set (to self for example).


Second (and the real issue), is that the code assumes that the viewForAnnotation delegate method will get called only once and immediately after adding each annotation.

This is not the case and is not guaranteed. The map view will call viewForAnnotation whenever it needs to display the annotation and could be called multiple times for the same annotation or long after the annotation is actually added (eg. after user pans or zooms the map and the annotation comes into view).

See does MKAnnotationView buffer its input queue? for some additional details and relevant links to other answers including sample code.

Basically, you must store the properties that affect an annotation's view with the annotation object itself and retrieve these properties from the annotation parameter that is passed into viewForAnnotation.


What I suggest for your case is this:

I assume you are using the built-in annotation class MKPointAnnotation. Instead of using MKPointAnnotation which does not let you store your custom status property alongwith the annotation object itself, either:

  • Create a custom class that implements the MKAnnotation protocol but also with a status property. Set this property when creating the annotation and extract its value from the annotation parameter passed into viewForAnnotation and set the pinColor accordingly. See sample code in linked answer(s).

  • Make the objects in the MySupplierData themselves objects that implement the MKAnnotation protocol. So if the objects in MySupplierData are instances of some class named, say, Supplier, make the Supplier class conform to the MKAnnotation protocol and then you can add the MySupplierData objects themselves to the map view when calling addAnnotation.

这篇关于viewForAnnotation混淆并迭代定制pinColor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆