如何更新MKPinAnnotationView上的信息?
我已经有一些过去使用MKMapView
和MKPointAnnotation
的经验,我曾经在地图上放置了一些别针。 这次我想更进一步,使用MKPinAnnotationView
来写一个标签和一些引脚。如何更新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上的标签,但我不知道要使用什么代码。行:
// *我想要更新此引脚(附加到secondPoint)的标签。
现在标签显示为第一组,但我不知道如何更新它。
-
第二个问题,必须有一个更好的方法来测试我正在处理的针脚。行:
// *我需要一个更好的测试来检查这个不是touchPoint!
如果您希望注记视图显示一些随着注记更改而更新的文本,请在注记上使用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
,使之成为多一点明确的,它是一个视图,而不是与模型属性,information
,我们的新MyAnnotation
类的混淆。此外,我建议比MyAnnotation
和MyPinAnnotationView
更有意义的类名称,或许使用更好的名称来捕获这两个类的功能意图。
无论如何,如您所见,当您为此批注视图设置annotation
时,它会更新标签text
。但它也通过KVO观察注释的新information
属性,因此如果此属性稍后更改,则视图将相应更新。
不,我不想看到标题,因为你提到的原因。但我会记住你的观察者的想法,看看我能否用它做点什么。我想更新信息UILabel(请参阅我的文章)。 – Michel
我当然需要工作,从你的想法开始。我不得不说,只是通过阅读你的代码,在这一点上我不太了解。最终我想更新信息的内容(UILabel),当用户触摸显示屏并且secondPoint改变位置时。一旦我看到它的工作原理,我希望你的建议能使我做到这一点。 – Michel
@Michel - 是的,这就是为什么我们使用观察者模式,以便您可以稍后更新一些注释属性,并且注释视图将相应地更新。只要观察一下除“title”之外的其他属性。看到我上面的扩展答案。 – Rob
如果你不介意,你会分享你的演示吗?我可以理解你的问题,并发布它的答案 –
好,但让我知道你需要知道,这是不是在我的文章。我已经在这篇文章中分享了所有我能想到的主题。 – Michel
检查此答案我认为这将帮助你http://*.com/questions/24467408/swift-add-mkannotationview-to-mkmapview –