缩小时注释被隐藏

时间:2019-08-23 17:06:02

标签: swift mapkit

这是我的问题:

enter image description here

当缩小并且属性showUserUser设置为true并且注释位于用户位置的中心时,缩小时群集将消失。我不希望这样,它们应该始终可见。 displayPriority的默认值设置为required,所以我不确定如何解决此问题。 每个注释和群集都应该始终可见。当我将showsUserLocation属性设置为false时,或确保注释/群集不在当前位置附近时,此方法将起作用。

有两种方法可以重现我的问题:

  1. 克隆并运行https://github.com/Jasperav/AnnotationsGlitch
  2. 复制粘贴并运行下面的代码

代码

import UIKit
import MapKit

class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
    let mapView = MKMapView(frame: .zero)

    private let locationManager = CLLocationManager()

    override func viewDidLoad() {
        view.addSubview(mapView)

        mapView.translatesAutoresizingMaskIntoConstraints = false
        mapView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
        mapView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
        mapView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        mapView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        mapView.delegate = self

        mapView.showsUserLocation = true
    }

    override func viewDidAppear(_ animated: Bool) {
        let authorizationStatus = CLLocationManager.authorizationStatus()

        switch authorizationStatus {
        case .authorizedWhenInUse, .authorizedAlways:
            break
        case .notDetermined, .restricted, .denied:
            locationManager.requestWhenInUseAuthorization()
        @unknown default:
            fatalError()
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
            for _ in 0...20 {
                let currentLocation = self.mapView.userLocation.coordinate
                let newLocation = currentLocation.shiftRandomPosition(meters: 30000, randomMeters: true)

                self.mapView.addAnnotation(Annotation(coordinate: newLocation))
            }

            self.mapView.setRegion(MKCoordinateRegion(center: self.mapView.userLocation.coordinate, span: MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 0)), animated: false)
        }
    }

    func mapView(_ mapView: MKMapView, clusterAnnotationForMemberAnnotations memberAnnotations: [MKAnnotation]) -> MKClusterAnnotation {
        MKClusterAnnotation(memberAnnotations: memberAnnotations)
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        guard let annotation = annotation as? Annotation else { return nil }

        let identifier = "marker"
        let view: MKMarkerAnnotationView

        if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView {
            dequeuedView.annotation = annotation
            view = dequeuedView
        } else {
            view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        }

        view.clusteringIdentifier = "identifier"


        return view
    }
}

class Annotation: NSObject, MKAnnotation {
    let coordinate: CLLocationCoordinate2D

    init(coordinate: CLLocationCoordinate2D) {
        self.coordinate = coordinate

        super.init()
    }
}

// https://stackoverflow.com/a/55459722/7715250
extension CLLocationCoordinate2D {
    /// Get coordinate moved from current to `distanceMeters` meters with azimuth `azimuth` [0, Double.pi)
    ///
    /// - Parameters:
    ///   - distanceMeters: the distance in meters
    ///   - azimuth: the azimuth (bearing)
    /// - Returns: new coordinate
    private func shift(byDistance distanceMeters: Double, azimuth: Double) -> CLLocationCoordinate2D {
        let bearing = azimuth
        let origin = self
        let distRadians = distanceMeters / (6372797.6) // earth radius in meters

        let lat1 = origin.latitude * Double.pi / 180
        let lon1 = origin.longitude * Double.pi / 180

        let lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearing))
        let lon2 = lon1 + atan2(sin(bearing) * sin(distRadians) * cos(lat1), cos(distRadians) - sin(lat1) * sin(lat2))
        return CLLocationCoordinate2D(latitude: lat2 * 180 / Double.pi, longitude: lon2 * 180 / Double.pi)
    }

    func shiftRandomPosition(meters: Double, randomMeters: Bool) -> CLLocationCoordinate2D {
        let finalMeters: Double

        if randomMeters {
            finalMeters = Double.random(in: -meters..<meters)
        } else {
            finalMeters = meters
        }

        let randomAzimuth = Double.random(in: -Double.pi..<Double.pi)

        return shift(byDistance: finalMeters, azimuth: randomAzimuth)
    }
}

2 个答案:

答案 0 :(得分:2)

YMMV,但是我可以通过将displayPriority显式设置为.required来解决此问题。文档 say 表示这是默认值,但我在调试时注意到,实际上 注释的优先级较低,这将导致它们被用户位置遮挡注释。

更新: 这可以工作一小会儿,但是每当视图通过出队群集和/或重用时,它就会再次停止工作。我尝试在AnnotationView的init(),prepareForDisplay()等中设置displayPriority。问题仍然出现。在所有情况下,对我有用的是在每次创建或退出displayPriority时重置一次。如果将view.displayPriority = .required添加到设置clusteringIdentifier的上方或下方的代码中,则在返回视图之前,它应该可以工作。为我工作!您可能还必须为MKClusterAnnotationViews主动/明确地重置它。

答案 1 :(得分:0)

当前用户的注释没有群集标识符。如果您为当前用户的注释提供群集标识符,则该标识符有效。