如何更新MKPinAnnotationView上的信息? [英] How to update information on MKPinAnnotationView?

查看:83
本文介绍了如何更新MKPinAnnotationView上的信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我曾经有一些使用MKMapViewMKPointAnnotation的经验,我曾经在地图上放置一些图钉. 这次,我试图更进一步,并使用MKPinAnnotationView来写一些标签以及一些引脚.

I've had some past experience using MKMapView and MKPointAnnotation, which I used to put some pin on a map. This time I am trying to go one step further and use MKPinAnnotationView, to write a label along with some of the pins.

不幸的是,这并不能像我期望的那样全部起作用.

Unfortunately, it doesn't all work as I expect.

这就是我想要做的:

我有一个地图(一个MKMapView对象),当我触摸它时,我将一个销钉放在接触点上,然后执行一些计算,这使我在地图上获得了第二个点.我在地图上放置了第二个图钉(位于第二个点),我要在最后一个图钉上放置一个标签,例如"Hello Second!",但是当图钉更改位置时,该标签需要更新.

I have a map (an MKMapView object) and when I touch it, I put a pin at the touch point, then some computation is performed and this gives me a second point on the map. I put a second pin on the map (located at the second point), on this last pin I want to put a label, say "Hello Second!", but this label needs to be updated when the pin changes place.

以下是相关代码:

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类:

Here is the class 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()
    }
}

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

The lines with a comment marked //*, show where I need some help.

  • 第一个问题,我想更新secondPoint上的标签,但是我不知道要使用什么代码.行:

  • First issue, I want to update the label on the secondPoint, but I don't know what code to use. Line:

//*我也想更新此引脚的标签(附加到secondPoint).

//* I want to update the label for this pin (attached to the secondPoint) too.

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

Now the label appears as first set, but I don't know how to update it.

  • 第二个问题,必须有一种更好的方法来测试我要处理的那个引脚.行:

  • Second issue, there must be a better way to test which pin I am dealing with. Line:

//*我需要更好的测试来检查它是否不是touchPoint!

//* I need a better test to check that this not touchPoint!

推荐答案

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

If you want the annotation view to show some text that is updated as the annotation changes, use KVO on the annotation. So, first, create a model object, the annotation, which includes the new property to be observed:

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观察这些更改.

I've called this new property information, but you can probably come up with a better name that captures the functional intent of this property. But hopefully it illustrates the idea. The key takeaway here is that if this property may change at a later point, we'll want to make it dynamic so we can use KVO to observe those changes.

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更有意义的类名,也许使用一些可以更好地捕获这两个类的功能意图的名称.

I've changed the name of the label to informationLabel to make it a little more explicit that it is a view, not to be confused with the model property, information, of our new MyAnnotation class. Also, I'd suggest more meaningful class names than MyAnnotation and MyPinAnnotationView, perhaps using some name that better captures the functional intent of these two classes.

无论如何,如您所见,为该批注视图设置annotation时,它将更新标签text.但是它还会通过KVO观察注解的新information属性,因此,如果以后更改此属性,则视图将相应更新.

Regardless, as you can see, when you set the annotation for this annotation view, it updates the label text. But it also observes the annotation's new information property via KVO, so if this property changes later, the view will update accordingly.

这篇关于如何更新MKPinAnnotationView上的信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆