【问题标题】:How to update information on MKPinAnnotationView?如何更新 MKPinAnnotationView 的信息?
【发布时间】:2017-05-09 17:49:36
【问题描述】:

我有一些使用MKMapViewMKPointAnnotation 的经验,我曾经在地图上放置一些图钉。 这次我想更进一步,使用MKPinAnnotationView,写一个标签和一些别针。

不幸的是,它并没有像我预期的那样工作。

这是我想做的:

我有一张地图(一个 MKMapView 对象),当我触摸它时,我在触摸点上放了一个大头针,然后执行一些计算,这给了我地图上的第二个点。我在地图上放了第二个图钉(位于第二个点),在最后一个图钉上我想放一个标签,说“Hello Second!”,但是当图钉改变位置时,这个标签需要更新。

以下是相关代码:

class ViewController: UIViewController, MKMapViewDelegate {
    var mapView:MKMapView!, touchPoint,secondPoint:MKPointAnnotation!

    override func viewDidLoad() {
        super.viewDidLoad()
        mapView = MKMapView()
        ...........
        let mapTap = UITapGestureRecognizer(target: self,
                                            action: #selector(ViewController.mapTouchHandler))
        mapView.addGestureRecognizer(mapTap)
    }


    func mapTouchHandler(gesture:UITapGestureRecognizer) {
        ...........
        // Compute map coordinates for the touch point (tapGeoPoint).

        if touchPoint == nil {
            touchPoint = MKPointAnnotation()
            mapView.addAnnotation(touchPoint);
        }

        touchPoint.coordinate = CLLocationCoordinate2D(latitude: tapGeoPoint.latitude,
                                                       longitude: tapGeoPoint.longitude)
        ...........
        computeSecondPoint(url: someComputedURL)
    }


    func computeSecondPoint(url searchURL:String) {
        let reqURL = NSURL(string: searchURL)!, session = URLSession.shared,
        task = session.dataTask(with: reqURL as URL) {
            (data: Data?, response: URLResponse?, error: Error?) in
            if error == nil {
                do {let allData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSArray
                    .................
                    // Compute map coordinates for the second point (secondPointCoord).

                    if self.secondPoint == nil {
                        self.secondPoint = MKPointAnnotation()
                        self.mapView.addAnnotation(self.secondPoint)
                    }

                    DispatchQueue.main.async {
                        () -> Void in
                        self.secondPoint.coordinate = CLLocationCoordinate2D(latitude: secondPointCoord.latitude,
                                                                             longitude: secondPointCoord.longitude)
                        self.secondPoint.title = "Hello Second -TITLE!"
                        //* I want to update the label for this pin (attached to the secondPoint) too.
                    }
                } catch let error as NSError {print(error.localizedDescription)}
            } else {
                print("Error inside \(#function):\n\(error)")
            }
        }

        task.resume()

    }


    func mapView(_ mapView: MKMapView,
                 viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        let identifier = "pin"
        var view: MyPinAnnotationView
        if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
            as? MyPinAnnotationView {
            dequeuedView.annotation = annotation
            view = dequeuedView
        } else {
            view = MyPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)

            if ((annotation.coordinate.latitude != touchPoint.coordinate.latitude) ||
                (annotation.coordinate.longitude != touchPoint.coordinate.longitude)) {//* I need a better test to check that this not touchPoint!
                view.pinTintColor = UIColor.blue
                view.canShowCallout = true
                view.calloutOffset = CGPoint(x: -7, y: 0)
                view.setInfo(title: "Hi Start Label!")
            } else {
                view.pinTintColor = UIColor.red
                view.canShowCallout = false
            }
        }
        return view
    }
}

这是 MyPinAnnotationView 类:

import UIKit
import MapKit

class MyPinAnnotationView: MKPinAnnotationView {
    let information:UILabel = UILabel(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 70.0, height: 30.0)))

    func setInfo(title : String)
    {
        information.text = title
        information.textAlignment = .center
        self.addSubview(information)
    }


    func hideInfo() {
        information.removeFromSuperview()
    }
}

带有注释标记//* 的行显示我需要帮助的地方。

  • 第一个问题,我想更新第二个点上的标签,但是不知道用什么代码。线路:

    //* 我也想更新此图钉的标签(附加到 secondPoint)。

现在标签显示为第一组,但我不知道如何更新它。

  • 第二个问题,必须有更好的方法来测试我正在处理的引脚。线路:

    //* 我需要更好的测试来检查这不是接触点!

【问题讨论】:

  • 如果您不介意,您会分享您的演示吗?我可以理解您的问题并发布答案
  • 很好,但是让我知道您需要知道的内容不在我的帖子中。我已经在帖子中分享了我能想到的关于这个主题的所有内容。
  • 检查这个答案我认为这会帮助你stackoverflow.com/questions/24467408/…
  • 嗯?但我可以添加一个 MKAnnotationView。我的问题是在需要时更新我添加的标签的内容。
  • 意味着如果您点击其他地方,那么您必须使用 ? 更新您的标签

标签: ios mkmapview mkpinannotationview mkmapviewdelegate mkpointannotation


【解决方案1】:

如果您希望注释视图显示一些随着注释更改而更新的文本,请在注释上使用 KVO。因此,首先,创建一个模型对象,即注解,其中包含要观察的新属性:

class MyAnnotation: NSObject, MKAnnotation {
    dynamic var title: String?
    dynamic var subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
    dynamic var information: String?

    init(title: String? = nil, subtitle: String? = nil, coordinate: CLLocationCoordinate2D, information: String? = nil) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
        self.information = information
    }
}

我已将此新属性称为information,但您可能会想出一个更好的名称来捕捉此属性的功能意图。但希望它能说明这个想法。这里的关键点是,如果此属性可能在以后发生更改,我们将希望将其设为 dynamic,以便我们可以使用 KVO 来观察这些更改。

class MyPinAnnotationView: MKPinAnnotationView {
    private let informationLabel = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 70.0, height: 30.0)))

    private var observerContext = 0

    override var annotation: MKAnnotation? {
        willSet {
            removeObserverIfAny()
        }
        didSet {
            if let annotation = annotation as? MyAnnotation {
                annotation.addObserver(self, forKeyPath: #keyPath(MyAnnotation.information), context: &observerContext)
                informationLabel.text = annotation.information
            }
        }
    }

    deinit {
        removeObserverIfAny()
    }

    private func removeObserverIfAny() {
        if let oldAnnotation = annotation as? MyAnnotation {
            oldAnnotation.removeObserver(self, forKeyPath: #keyPath(MyAnnotation.information))
        }
    }

    func showInformation() {
        addSubview(informationLabel)
    }

    func hideInformation() {
        informationLabel.removeFromSuperview()
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard context == &observerContext else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }

        if let annotation = annotation as? MyAnnotation, let information = annotation.information {
            informationLabel.text = information
        }
    }

}

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

        var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MyPinAnnotationView
        if annotationView == nil {
            annotationView = MyPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
            annotationView?.canShowCallout = true
        } else {
            annotationView?.annotation = annotation
        }
        annotationView?.showInformation()
        return annotationView
    }
}

我已将标签的名称更改为informationLabel,以便更明确地表明它是一个视图,不要与我们的新MyAnnotation 类的模型属性information 混淆。另外,我建议使用比MyAnnotationMyPinAnnotationView 更有意义的类名,也许使用更能捕捉这两个类的功能意图的名称。

无论如何,如您所见,当您为此注释视图设置annotation 时,它会更新标签text。但它也会通过 KVO 观察注解的新 information 属性,所以如果以后这个属性发生变化,视图也会相应更新。

【讨论】:

  • 不,我不想关注标题,因为你提到的原因。但我会记住你的观察者想法,看看我能不能用它做点什么。我想更新UILabel的信息(见我的帖子)。
  • 我当然需要工作,从你的想法开始。我不得不说,仅通过阅读您的代码,我目前还不太了解。最终我想更新信息(UILabel)的内容,当用户触摸显示器并且 secondPoint 改变位置时。我希望你的建议能让我做到这一点,一旦我看到它是如何工作的。
  • @Michel - 是的,这就是我们使用观察者模式的原因,这样您就可以稍后更新一些注释属性,并且注释视图会相应地更新。只需观察title 以外的一些属性。请参阅上面的扩展答案。
  • 工作量很大,但现在可以了。非常感谢。
  • 像魅力一样工作!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多