当用户缩小并且注释彼此太靠近时隐藏 MKAnnotations
Posted
技术标签:
【中文标题】当用户缩小并且注释彼此太靠近时隐藏 MKAnnotations【英文标题】:Hide MKAnnotations when user zooms out and annotations are too close to each other 【发布时间】:2013-09-13 06:19:33 【问题描述】:到目前为止,我已经在某些应用程序中看到了这一点,当用户缩小时,注释会彼此靠近,如果它们太靠近,则会被替换为例如一个“+5”别针或其他东西。
如何做到这一点?
我认为应该在regionDidChangeAnimated
中完成,并在mapview 上检查每个Pin 之间的距离(不是实际距离)。
这是正确的方法吗?如何在 mapview 上获取距离而不是其中的距离(例如,NY 和 SF 之间的距离将始终相同,但如果用户缩小,地图上图钉之间的距离会缩小)
【问题讨论】:
【参考方案1】:在 WWDC 2017 What's New in MapKit 他们向我们介绍了 ios 11 中的一个新的 annotation clustering API,这使得实现集群变得异常容易。简而言之,为您的注释视图设置一个clusteringIdentifier
,它会为您处理所有的集群逻辑。例如
override func viewDidLoad()
super.viewDidLoad()
mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
mapView.register(ClusterAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)
...
并且,在此过程中,不需要 MKMapViewDelegate
方法(尽管如果您想要进一步自定义,显然可以这样做,但如果您对基本 UX 没问题,则默认重用标识符消除了对它的需要。关键是,你必须实现你的注释视图,特别是为你的主注释视图设置clusteringIdentifier
,这样集群就会自动发生,例如
class CustomAnnotationView: MKMarkerAnnotationView
static let clusteringIdentifier = "ClusterAnnotationView"
let annotationWidth = 40
override init(annotation: MKAnnotation?, reuseIdentifier: String?)
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
clusteringIdentifier = CustomAnnotationView.clusteringIdentifier
collisionMode = .circle
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
override var annotation: MKAnnotation?
willSet
clusteringIdentifier = CustomAnnotationView.clusteringIdentifier
// you can do whatever other update to your `newValue` annotation needed here, if you'd like
和
class ClusterAnnotationView: MKAnnotationView
override init(annotation: MKAnnotation?, reuseIdentifier: String?)
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
displayPriority = .defaultHigh
collisionMode = .circle
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
override var annotation: MKAnnotation?
willSet
updateImage(for: newValue as? MKClusterAnnotation)
private func updateImage(for cluster: MKClusterAnnotation?)
guard let cluster = cluster else image = nil; return
let rect = CGRect(origin: .zero, size: CGSize(width: 40, height: 40))
let renderer = UIGraphicsImageRenderer(size: rect.size)
image = renderer.image _ in
// e.g. circle
#colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1).setFill()
#colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0).setStroke()
let path = UIBezierPath(arcCenter: rect.center, radius: rect.radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
path.lineWidth = 0.5
path.fill()
path.stroke()
// with count in the center
let text = "\(cluster.memberAnnotations.count)"
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.white,
.font: UIFont.boldSystemFont(ofSize: 20)]
let size = text.size(withAttributes: attributes)
let textRect = CGRect(origin: CGPoint(x: rect.midX - size.width / 2, y: rect.midY - size.height / 2), size: size)
text.draw(in: textRect, withAttributes: attributes)
不再需要我在下面的原始答案中考虑的所有复杂手动聚类。
在 WWDC 2011 Visualizing Information Geographically with MapKit 中,他们展示了一种精确实现此目的的方法(演示的内容大约在视频 18 分钟后开始)。他们采用的概念是将可见地图划分为网格的概念,如果特定网格中有多个注释,他们会删除它们并添加单个“集群”注释。它们说明了您甚至可以如何在视觉上动画化注释进出集群的移动,因此用户可以在放大和缩小时了解正在发生的事情。这是您深入研究的一个很好的起点。
【讨论】:
在 swift 中,我正在使用地图自定义图像,例如比普通图钉更大的圆形阴影作为用户位置。这在用户位置图像下隐藏/重叠了几个引脚,我如何将所有引脚从用户位置带到前面?我为其他引脚尝试了将subview tofront,它不起作用。例如:cutt.ly/ap2pLIv。你能帮帮我吗?以上是关于当用户缩小并且注释彼此太靠近时隐藏 MKAnnotations的主要内容,如果未能解决你的问题,请参考以下文章