既に表示されているコールアウト内で 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
}
ありがとうございました。