只有一个(自定义)注释从其他注释数组中旋转

我几乎走向我的应用程序的最后阶段,它显示了公交车的实时地图。 所以,基本上,我有一个定时器,它可以定期从xml表中获取总线的经度和经度,该表提供了总线的实时位置。 我能够设置xml解析器,为总线的运动设置动画并为总线设置自定义(箭头)图像。

然而,问题是, 从多个总线arrays中,我只能得到一个总线来旋转 。 查看xml数据,它始终是xml工作表中第一个正在旋转的总线。 早些时候,我在旋转一辆公共汽车时遇到了麻烦,因此用户“Good Doug”帮助了我,我能够让它运转起来。 您可以在此处看到post: 自定义注释图像仅在程序开始时旋转(Swift-iOS) 。 我尝试通过为每个总线创建一个MKAnnotationView数组来使用相同的解决方案。 我不确定这是不是正确的做法。 如果有人可以帮我解决这个问题,我会很高兴:)

首先,这就是XML表格的样子(在这个例子中,有两辆车,所以我们只需要跟踪其中两辆):

    

这是我对一个单独的Bus类的实现(在Bus.swift文件中)。 这可以使用一些改进。

 class Bus : MKPointAnnotation, MKAnnotation { var oldCoord : CLLocationCoordinate2D! var addedToMap = false init(coord: CLLocationCoordinate2D) { self.oldCoord = coord } } 

这是我的ViewController.swift的代码 –

 var busArray: [Bus!] = [] //Array to hold custom defined "Bus" types (from Bus.swift file) var busViewArray : [MKAnnotationView?] = [nil, nil] //Array to hold MKAnnotationView of each bus. We're assuming 2 buses are active in this case. var vehicleCount = 0 // variable to hold the number of buses var vehicleIndex = 0 // variable to check which bus the xml parser is currently on. var trackingBusForTheVeryFirstTime = true // My xml parser function: func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: NSDictionary!) { if (elementName == "vehicle" ) { let latitude = attributeDict["lat"]?.doubleValue // Get latitude of current bus let longitude = attributeDict["lon"]?.doubleValue // Get longitude of current bus let dir = attributeDict["heading"]?.doubleValue // Get direction of current bus var currentCoord = CLLocationCoordinate2DMake(latitude!, longitude!) // Current coordinates of the bus // Checking the buses for the VERY FIRST TIME. This is usually the start of the program if (trackingBusForTheVeryFirstTime || vehicleCount == 0) { let bus = Bus(coord: currentCoord) self.busArray.append(bus) // Put current bus to the busArray self.vehicleCount++ } else { // UPDATE BUS Location. (Note: this is not the first time) // If index exceeded count, that means number of buses changed, so we need to start over if (self.vehicleIndex >= self.vehicleCount) { self.trackingBusForTheVeryFirstTime = true // Reset count and index for buses self.vehicleCount = 0 self.vehicleIndex = 0 return } let oldCoord = busArray[vehicleIndex].oldCoord if (oldCoord.latitude == latitude && oldCoord.longitude == longitude) { // if oldCoordinates and current coordinates are the same, the bus hasn't moved. So do nothing. return } else { // Move and Rotate the bus: UIView.animateWithDuration(0.5) { self.busArray[self.vehicleIndex].coordinate = CLLocationCoordinate2DMake(latitude!, longitude!) // if bus annotations have not been added to the map yet, add them: if (self.busArray[self.vehicleIndex].addedToMap == false) { self.map.addAnnotation(self.busArray[self.vehicleIndex]) self.busArray[self.vehicleIndex].addedToMap = true return } if let pv = self.busViewArray[self.vehicleIndex] { pv.transform = CGAffineTransformRotate(self.map.transform, CGFloat(self.degreesToRadians(dir!))) // Rotate bus } } if (vehicleIndex < vehicleCount - 1) self.vehicleIndex++ } else { self.vehicleIndex = 0 } return } } } 

这是我实现的viewForAnnotation

 func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! { let reuseId = "pin\(self.vehicleIndex)" busViewArray[self.vehicleIndex] = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) if busViewArray[self.vehicleIndex] == nil { self.busViewArray[self.vehicleIndex] = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId) busViewArray[vehicleIndex]!.image = imageWithImage(UIImage(named:"arrow.png")!, scaledToSize: CGSize(width: 21.0, height: 21.0)) self.view.addSubview(busViewArray[self.vehicleIndex]!) } else { busViewArray[self.vehicleIndex]!.annotation = annotation } return busViewArray[self.vehicleIndex] } 

我怀疑我的viewForAnnotation实现。 我也不确定它是否有一个MKAnnotationView数组。 也许,我对注释视图在iOS中如何工作的理解是错误的。 如果有人可以帮我解决这个问题,我会很高兴,因为我已经坚持了一段时间。 即使整体实施需要改变,我也很乐意尝试一下。 这是问题的截图。

截图

请再次注意,所有公共汽车都出现在正确的位置并顺利移动,但其中只有一辆实际上是旋转的。 提前致谢。

我不认为解析代码直接操作注释视图是合适的。 你不知道它们是否可见,它们是否已被实例化等等.mapview负责管理注释视图,而不是你。

如果需要维护总线和注释之间的交叉引用,请执行此操作,但不要维护对注释视图的引用。 您的应用与注释的互动应仅限于注释本身。 因此,创建一个具有angle属性的注释子类。

 class MyAnnotation : MKPointAnnotation { @objc dynamic var angle: CGFloat = 0.0 } 

然后,您可以让注释视图子类“观察”自定义注释子类,随着注释angle变化而旋转。 例如,在Swift 4中:

 class MyAnnotationView : MKAnnotationView { override init(annotation: MKAnnotation?, reuseIdentifier: String?) { super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) addAngleObserver() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) addAngleObserver() } // Remember, since annotation views can be reused, if the annotation changes, // remove the old annotation's observer, if any, and add new one's. override var annotation: MKAnnotation? { willSet { token = nil } didSet { addAngleObserver() } } // add observer var token: NSKeyValueObservation! private func addAngleObserver() { if let annotation = annotation as? MyAnnotation { transform = CGAffineTransform(rotationAngle: annotation.angle) token = annotation.observe(\.angle) { annotation, _ in UIView.animate(withDuration: 0.25) { self.transform = CGAffineTransform(rotationAngle: annotation.angle) } } } } } 

或者在Swift 3中:

 private var angleObserverContext = 0 class MyAnnotationView : MKAnnotationView { override init(annotation: MKAnnotation?, reuseIdentifier: String?) { super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) addAngleObserver() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) addAngleObserver() } // add observer private func addAngleObserver() { if let annotation = annotation as? MyAnnotation { transform = CGAffineTransform(rotationAngle: annotation.angle) annotation.addObserver(self, forKeyPath: #keyPath(MyAnnotation.angle), options: [.new, .old], context: &angleObserverContext) } } // remove observer private func removeAngleObserver() { if let annotation = annotation as? MyAnnotation { annotation.removeObserver(self, forKeyPath: #keyPath(MyAnnotation.angle)) } } // remember to remove observer when annotation view is deallocated deinit { removeAngleObserver() } // Remember, since annotation views can be reused, if the annotation changes, // remove the old annotation's observer, if any, and add new one's. override var annotation: MKAnnotation? { willSet { removeAngleObserver() } didSet { addAngleObserver() } } // Handle observation events for the annotation's `angle`, rotating as appropriate override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard context == &angleObserverContext else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } UIView.animate(withDuration: 0.5) { if let angleNew = change![.newKey] as? CGFloat { self.transform = CGAffineTransform(rotationAngle: angleNew) } } } } 

现在,您的应用程序可以维护对已添加到地图的注释的引用,并设置它们的angle ,这将在视图中以视觉方式表示。


请参阅Swift 2示例的此答案的上一版本 。