0

既に表示されているコールアウト内で KVO の更新を取得するのに苦労しています。

私の使用例: オープン コールアウトに、ユーザーの位置とマップに追加した注釈との間のリアルタイムの距離を表示したいと考えています。注釈はその位置を変更しません。

  • 定義したカスタム アノテーションを使用して、mapView にアノテーションを追加します。ここでは問題ありません。
  • 選択した注釈ごとに、コールアウトにカスタム注釈で定義されたすべての情報が表示されます
  • ただし、注釈の選択を解除して再度選択した場合にのみ、吹き出しで距離が更新されます

距離プロパティは @objc dynamic として宣言されているため、観察できます。ユーザーの位置が変わるたびに距離を計算します。この部分も機能します。

コールアウトを閉じて再度開かないと、コールアウトを更新するために何が欠けているのかわかりません。

私が使用しているコードは、Rob によってここで説明されているものです: Swift -How to Update Data in Custom MKAnnotation Callout?

だから私の質問: notificationView callout で値 (観察された) をリアルタイムで変更することは可能ですか? はいの場合、KVO が最善のアプローチですか? 以下のリンクでは、mapView viewFor メソッドをどのように実装しますか?

どの例も非常に役立ちます。

これは私の最初の投稿です。間違っていた場合はお知らせください。より多くの情報と詳細を提供します。しかし、私の状況は些細なことです。標準のコールアウトは、タイトルとサブタイトルに対して Key-Value Observation (KVO) を実行します。(そして、注釈ビューは座標の変化を観察します。) しかし、現在開いている吹き出しで値の変更を表示する方法は? それは私が得ていない考えです。

CustomAnnotation クラス:

class CustomAnnotation: NSObject, MKAnnotation {
    @objc dynamic var title: String?
    @objc dynamic var subtitle: String?
    @objc dynamic var coordinate: CLLocationCoordinate2D
    
    @objc dynamic var distance: CLLocationDistance
    var poiColor: String?
    var poiPhone: String?    
    
    init(title: String, subtitle: String, coordinate: CLLocationCoordinate2D, poiColor: String, poiPhone: String, distance: CLLocationDistance) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
        self.poiColor = poiColor
        self.poiPhone = poiPhone
        self.distance = distance
        super.init()
    }
}

CustomAnnotationView クラス:

    class CustomAnnotationView: MKMarkerAnnotationView {
    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        displayPriority = .required
        canShowCallout = true
        detailCalloutAccessoryView = createCallOutWithDataFrom(customAnnotation: annotation as? CustomAnnotation)
    }

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

    deinit {
        removeAnyObservers()
    }

    override var annotation: MKAnnotation? {
        didSet {
            removeAnyObservers()
            if let customAnnotation = annotation as? CustomAnnotation {
                updateAndAddObservers(for: customAnnotation)
            }
        }
    }

    private var subtitleObserver: NSKeyValueObservation?
    private var distanceObserver: NSKeyValueObservation?

    private let subtitleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    private let distanceLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
}

private extension CustomAnnotationView {
    func updateAndAddObservers(for customAnnotation: CustomAnnotation) {
        
        subtitleLabel.text = customAnnotation.subtitle
        subtitleObserver = customAnnotation.observe(\.subtitle) { [weak self] customAnnotation, _ in
            self?.subtitleLabel.text = customAnnotation.subtitle
        }
        
        let locationManager = CLLocationManager()
        let theLatitude:CLLocationDegrees = (locationManager.location?.coordinate.latitude)!
        let theLongitude:CLLocationDegrees = (locationManager.location?.coordinate.longitude)!
        // Get pin location
        let pointLocation = CLLocation(latitude: customAnnotation.coordinate.latitude, longitude: customAnnotation.coordinate.longitude)
        //Get user location
        let userLocation = CLLocation(latitude: theLatitude, longitude: theLongitude)
        // Return distance en meters
        let distanceFromUser = pointLocation.distance(from: userLocation)
        customAnnotation.distance = distanceFromUser*100
        distanceLabel.text = String(format: "%.03f", customAnnotation.distance)+" cm"
        distanceObserver = customAnnotation.observe(\.distance) { [weak self] customAnnotation, _ in
            self?.distanceLabel.text = "\(customAnnotation.distance) cm"
        }
    }

    func removeAnyObservers() {
        subtitleObserver = nil
        distanceObserver = nil
    }

    func createCallOutWithDataFrom(customAnnotation: CustomAnnotation?) -> UIView {
        
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = true
        view.addSubview(subtitleLabel)
        view.addSubview(distanceLabel)
        
        NSLayoutConstraint.activate([
            subtitleLabel.topAnchor.constraint(equalTo: view.topAnchor),
            subtitleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            subtitleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            subtitleLabel.bottomAnchor.constraint(equalTo: distanceLabel.topAnchor),
            distanceLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            distanceLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            distanceLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])

        if let customAnnotation = customAnnotation {
            updateAndAddObservers(for: customAnnotation)
        }
return view
    }
}

最後に:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation { return nil }
    let annotation = annotation as? CustomAnnotation
    
    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "CustomAnnotation") as? CustomAnnotationView
    
    if annotationView == nil {
        annotationView = CustomAnnotationView(annotation: annotation, reuseIdentifier: "CustomAnnotation")
        annotationView?.canShowCallout = true
    } else {
        annotationView?.annotation = annotation
    }
    return annotationView
}

ありがとうございました。

4

1 に答える 1