自定义annotationView标签重叠(导致MKMapView内存泄漏)

时间:2015-04-30 17:42:27

标签: swift mkmapview mkannotation mkannotationview

我正在使用mkmapview构建应用。我正在使用自定义注释视图来显示头像和相应的标签。一切正常:每个头像和相应的标签都正确显示。我可以在地图中导航。但是当我最大限度地缩小时,让我们说在旧金山显示4个标签,一旦我恢复到原始比例,标签会重叠。 最大缩小时,标签位于彼此之上。这个是正常的。但是一旦我恢复正常变焦:

   let span = MKCoordinateSpanMake(0.001, 0.001)

每个标签看起来都被其他标签盖章: PING map annotationview label overlaping

上面的标签应该说" sanchez"但它与其他标签文本融为一体。

以下是自定义注释视图的代码:

   func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
    if !(annotation is MKPointAnnotation) {
        return nil
    }
    var seleccion:Bool

    let reuseId = "test"
    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.image
    if cpa.toBeTriggered == true {
        anView.selected = true
    }
    var nameLbl: UILabel! = UILabel(frame: CGRectMake(-24, 40, 100, 30))
    nameLbl.text = cpa.nickName
    nameLbl.textColor = UIColor.blackColor()
    nameLbl.font = UIFont(name: "Atari Classic Extrasmooth", size: 10)
    nameLbl.textAlignment = NSTextAlignment.Center
    anView.addSubview(nameLbl)

    return anView
}

这就是它变得奇怪的地方:如果我为nameLbl设置了背景颜色,标签不会重叠/融化。这让我想起了Apple的一个错误......

修改

正如@Anna所提到的,CustomPointAnnotation是一个数据模型类:

import UIKit
import MapKit

class CustomPointAnnotation: MKPointAnnotation {
    var image: UIImage!
    var toBeTriggered: Bool = false
    var selected: Bool = false
    var nickName: String!
}

2 个答案:

答案 0 :(得分:3)

导致标签重叠的问题有两个:

  1. 正如评论中所述,每次调用 UILabel时,viewForAnnotation都会添加到注释视图,包括回收视图时( mapView.dequeueReusableAnnotationViewWithIdentifier返回一个视图)。循环播放的视图已经设置了UILabel,其中包含文字。当您在其上添加另一个标签时,会出现重叠文本。

    不是每次都添加标签,而是仅在实际创建MKAnnotationView时添加标签(当dequeue返回nil时)。然后设置标签text,获取对视图上已有标签的引用(在其上设置tag是一种简单的方法。)

    另一种方法是创建自定义注释 view 类(MKAnnotationView的子类)并在其中实现prepareForReuse并清除标签的文本。此自定义视图类与CustomPointAnnotation模型类是分开的。

  2. 即使在问题1中进行了修复之后,当远距离缩放并且有多个注释彼此靠近时,仍会出现重叠标签。他们的图像和标签会重叠。这不是一个错误。就是那样子。要避免此问题(如果这对您来说是个问题),一种解决方案是实现注释聚类,您可以根据缩放级别合并或分离注释。解释如何做到这一点超出了这个问题的范围。如果感兴趣,您可以搜索注释聚类库或实现细节。
  3. 要以最快的方式解决问题1,您可以执行以下操作:

    func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
        if !(annotation is CustomPointAnnotation) {
            //Check for CustomPointAnnotation (not MKPointAnnotation)
            //because the code below assumes CustomPointAnnotation.
            return nil
        }
        var seleccion:Bool
    
        let reuseId = "test"
        var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
        if anView == nil {
            anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
            anView.canShowCallout = true
    
            //Create and add UILabel only when actually creating MKAnnotationView...
            var nameLbl: UILabel! = UILabel(frame: CGRectMake(-24, 40, 100, 30))
            nameLbl.tag = 42    //set tag on it so we can easily find it later
            nameLbl.textColor = UIColor.blackColor()
            nameLbl.font = UIFont(name: "Atari Classic Extrasmooth", size: 10)
            nameLbl.textAlignment = NSTextAlignment.Center
            anView.addSubview(nameLbl)
        }
        else {
            anView.annotation = annotation
        }
    
        let cpa = annotation as! CustomPointAnnotation
        anView.image = cpa.image
    
        //NOTE: Setting selected property directly on MKAnnotationView 
        //      is not recommended.
        //      See documentation for the property.
        //      Instead, call MKMapView.selectAnnotation method 
        //      in the didAddAnnotationViews delegate method.
        if cpa.toBeTriggered == true {
            anView.selected = true
        }
    
        //Get a reference to the UILabel already on the view
        //and set its text...
        if let nameLbl = anView.viewWithTag(42) as? UILabel {
            nameLbl.text = cpa.nickName
        }
    
        return anView
    }
    

答案 1 :(得分:1)

每次调用

时使用不同的重用标识符

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?

取一个计数器变量并将其作为字符串传递给annotationIdentifier

mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier)