【问题标题】:Clustering doesn't work properly in iOS 13集群在 iOS 13 中无法正常工作
【发布时间】:2019-11-01 09:19:47
【问题描述】:

我正在对注解进行聚类。

以下代码可以正常工作,并在 iOS 11 和 iOS 12 中正确地对点进行聚类。

这在 iOS 13 中无法对点进行聚类。

我没有使用任何测试版。

TTMapView 类是 MKMapView 的包装器。

class TTMapView: UIView {

    var mapView = MKMapView()
    private var mapObjects: Dictionary<TTShape, MKShape?> = [:]
    private var _isClusteringEnabled = true

    func addMarker(_ marker: TTPoint) -> TTPoint {
        removeMarker(marker)
        let coordinate = marker.coordinate
        let pointAnnotation = MKPointAnnotation()
        pointAnnotation.coordinate = convertTTCoordinateToCLLocationCoordinate2D(coordinate)
        pointAnnotation.title = marker.title
        pointAnnotation.subtitle = marker.subtitle
        mapObjects.updateValue(pointAnnotation, forKey: marker)
        mapView.addAnnotation(pointAnnotation)
        return marker
    }
}

extension TTMapView: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        if annotation is MKUserLocation {
            return nil
        }

        if _isClusteringEnabled {
            let point = mapObjects.filter ({ $0.value === annotation }).first?.key as? TTPoint
            print("point ", point)
            return TTClusterAnnotationView(annotation: annotation, reuseIdentifier: TTClusterAnnotationView.ReuseID, image: point?.image, color: point?.tintColor)
        } else {
            let reuseId = "simplePin"
            var pinAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
            if pinAnnotationView == nil {
                pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
                pinAnnotationView?.isDraggable = true
                pinAnnotationView?.canShowCallout = true
            }
            return pinAnnotationView
        }
    }
}

class TTClusterAnnotationView: MKMarkerAnnotationView {

    /// Use this Id for setting annotation
    static let ReuseID = "clusterAnnotation"

    init(annotation: MKAnnotation?, reuseIdentifier: String?, image: UIImage?, color: UIColor? = nil) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        // Enable clustering by just setting the clusteringIdentifier
        clusteringIdentifier = "clusteringIdentifier"
        glyphImage = image
        glyphTintColor = color
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func prepareForDisplay() {
        super.prepareForDisplay()
        displayPriority = .required
    }
}

【问题讨论】:

    标签: swift mkmapview mkannotation mkannotationview mkmapviewdelegate


    【解决方案1】:

    创建集群注释视图(这是集群的注释视图,不要与您现有的具有clusteringIdentifier 的注释视图混淆,我已将其重命名为CustomAnnotationView 以避免混淆)有一个@ .required的987654323@:

    class CustomClusterAnnotationView: MKMarkerAnnotationView {
        override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
            super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
            displayPriority = .required
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override var annotation: MKAnnotation? {
            didSet {
                displayPriority = .required
            }
        }
    }
    

    然后注册那个类:

    mapView.register(CustomClusterAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)
    

    然后使用它:

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        if annotation is MKUserLocation {
            return nil
        }
    
        if annotation is MKClusterAnnotation {
            return nil
        }
    
        ...
    }
    

    一些不相关的观察:

    1. 我建议将您的图像和颜色属性添加到自定义注释类型,而不是让viewFor 过滤mapObjects。所以:

      class CustomAnnotation: MKPointAnnotation {
          let image: UIImage
          let color: UIColor
      
          init(coordinate: CLLocationCoordinate2D, title: String?, image: UIImage, color: UIColor) {
              self.image = image
              self.color = color
              super.init()
              self.coordinate = coordinate
              self.title = title
          }
      }
      

      然后,如果您使用它而不是 MKPointAnnotation,您的自定义注释视图可以直接从注释中提取颜色和图像信息。

      class CustomAnnotationView: MKMarkerAnnotationView {
          static let reuseID = "CustomAnnotationView"
      
          override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
              super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
              updateForAnnotation()
          }
      
          required init?(coder aDecoder: NSCoder) {
              fatalError("init(coder:) has not been implemented")
          }
      
          override var annotation: MKAnnotation? {
              didSet {
                  updateForAnnotation()
              }
          }
      }
      
      private extension CustomAnnotationView {
          func updateForAnnotation() {
              clusteringIdentifier = "CustomAnnotationView"
              displayPriority = .required
              if let annotation = annotation as? CustomAnnotation {
                  glyphImage = annotation.image
                  glyphTintColor = annotation.color
              } else {
                  glyphImage = nil
                  glyphTintColor = nil
              }
          }
      }
      

      注意,上面我正在重置annotationdidSet 中的集群标识符、图像、字形等。这使得注释视图的重用成为可能。 (见下一点。)

    2. 您的引脚注释视图的重用逻辑不正确。如果启用集群,您根本不会进行重用。如果针对 iOS 11 及更高版本,我会使用 dequeueReusableAnnotationView(withIdentifier:for:),它会为您处理所有这些。所以,我可以注册这个重用id:

      mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: CustomAnnotationView.reuseID)
      

      如果您关闭集群,我会为您显示的“简单图钉”注释视图重复该过程。

      mapView.register(CustomSimplePinAnnotationView.self, forAnnotationViewWithReuseIdentifier: CustomSimplePinAnnotationView.reuseID)
      

      class CustomSimplePinAnnotationView: MKPinAnnotationView {
          static let reuseID = "CustomSimplePinAnnotationView"
      
          override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
              super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
              isDraggable = true
              canShowCallout = true
          }
      
          required init?(coder aDecoder: NSCoder) {
              fatalError("init(coder:) has not been implemented")
          }
      }
      

      然后您的viewFor 被简化:

      func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
          switch annotation {
          case is MKUserLocation:
              return nil
      
          case is MKClusterAnnotation:
              return nil
      
          default:
              if _isClusteringEnabled {
                  return mapView.dequeueReusableAnnotationView(withIdentifier: CustomAnnotationView.reuseID, for: annotation)
              } else {
                  return mapView.dequeueReusableAnnotationView(withIdentifier: CustomSimplePinAnnotationView.reuseID, for: annotation)
              }
          }
      }
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      • 2020-02-01
      • 2021-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多