ios - viewForAnnotation 混淆和迭代自定义 pinColor

标签 ios swift mkannotationview

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

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

问题是当我放入一个开关以根据数组中的值设置颜色时,它会通过此代码但不考虑任何大小写值以将其设置为替代颜色并且一切都变为红色pin(似乎是默认值)。我已经打印出状态并进行调试以了解它正在进入开关并相应地设置 pinColor,但它们似乎没有粘住。

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
}

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

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

我没有对返回的 Pinview 做任何事情——我认为我不需要这样做,但是此时使用开关代码时所有的引脚都被绘制成红色。从根本上说,我一定在这里遗漏了一些东西。


7-8-14 根据 Anna 的大力帮助/辅导,更新以解决修订后代码的问题。 TKS!

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

建议在自定义注释中保存其他变量的自定义类 - 在本例中,状态值来 self 的数据结构 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 - 现在使用传递给它的新 CustomMapPinAnnotation:

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

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

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

调试输出显示 For 循环按预期执行到完成,以在 mapView 中的自定义 viewForAnnotation 获取之前创建 myCustomPinAnnotation 内部自行执行。当我将 map 移动到即时 View 之外的区域时,我确实注意到 mapView 中的 viewForAnnotation 根据需要被调用 我看到我的开关相应地执行,但引脚颜色并不总是正确的。初始显示 map 中的所有引脚每次都是正确的 正是这些外部区域的问题,我目前一直在研究它们为何关闭。

最佳答案

首先,代码应该调用viewForAnnotation明确地自己。
删除对 viewForAnnotation 的显式调用在addAnnotation之后行。

viewForAnnotation是一个委托(delegate)方法, map View 会在需要显示注释时自动调用它。如果它没有被自动调用,请确保 map View 的 delegate属性已设置(例如 self)。


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

事实并非如此,也无法保证。 map View 将调用 viewForAnnotation每当它需要显示注释并且可以针对同一注释多次调用或在实际添加注释很久之后调用(例如,在用户平移或缩放 map 并且注释进入 View 之后)。

参见 does MKAnnotationView buffer its input queue?有关其他详细信息和其他答案的相关链接,包括示例代码。

基本上,您必须将影响注释 View 的属性与注释对象本身一起存储,并从 annotation 中检索这些属性。传递给 viewForAnnotation 的参数.


我对你的情况的建议是:

我假设您使用的是内置注释类 MKPointAnnotation .而不是使用 MKPointAnnotation这不允许您存储自定义 status属性连同注释对象本身,要么:

  • 创建一个实现 MKAnnotation 的自定义类协议(protocol),但也有 status属性(property)。创建注释时设置此属性并从 annotation 中提取其值传递给 viewForAnnotation 的参数并设置 pinColor因此。请参阅链接答案中的示例代码。

  • 制作MySupplierData中的对象他们自己 实现 MKAnnotation 的对象协议(protocol)。所以如果 MySupplierData 中的对象是某个类的实例,例如,Supplier , 使 Supplier类符合 MKAnnotation协议(protocol),然后您可以添加 MySupplierData调用 addAnnotation 时将对象本身添加到 map View 中.

关于ios - viewForAnnotation 混淆和迭代自定义 pinColor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24613511/

相关文章:

ios - PromiseKit 可选链 Swift

ios - 实现委托(delegate)和协议(protocol)时解开 UILabel 错误

Swift:为什么这个 Swift Challenge 的答案是 -3?

ios - Swift 中如何判断 MKPointAnnotation 是否被按下?

ios - 在 MKMapView 中渲染 map 线我的 map 被卡住

iphone - 如何在 Twitter Rest API v1.1 中从 FHSTwitterEngine 完全注销?

ios - 如何去除 UIButton 中的左右边框?

ios - MapKit iOS 9 detailCalloutAccessoryView 用法

iOS "frame layout"

ios - 为什么我的约束没有发挥应有的作用?