Как мне сделать, чтобы MKAnnotations плавно перемещались по карте (корректировали их координаты)? - PullRequest
0 голосов
/ 30 августа 2018

Я начинающий разработчик Swift и создаю приложение, которое отслеживает местоположение городских автобусов на карте.

Проблема, с которой я столкнулся, заключается в том, что я хочу, чтобы MKAnnotations плавно перемещались между позициями GPS (от старого к тому, что находится в свежем JSON), вместо того, чтобы удалять и снова появляться.

Пока что мое приложение получает JSON, который декодируется в массив объектов, подчиняющихся протоколу MKAnnotation.

Затем я отображаю их все на карте следующим способом:

func updateUI(json: MyModelClass) {
    mapView.removeAnnotations(mapView.annotations)
    mapView.addAnnotations(json.busArray)
}

JSON загружается каждые 10 секунд и запускает метод updateUI, удаляя существующие примечания MKA и добавляя новые.

Буду очень признателен за любой совет.

В случае необходимости вот модель:

struct MyModelClass: Codable {
    let busArray: [Bus]

    enum CodingKeys: String, CodingKey {
        case busArray = "result"
    }

    init(busArray: [Bus]) {
        self.busArray = busArray
    }
}

class Bus: NSObject, Codable, MKAnnotation {
    let latitude, longitude: Double
    let time, title, brigade: String?
    var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 52.22977, longitude: 21.01178)

    enum CodingKeys: String, CodingKey {
        case latitude = "Lat"
        case longitude = "Lon"
        case time = "Time"
        case title = "Lines"
        case brigade = "Brigade"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        self.latitude = try container.decode(Double.self, forKey: .latitude)
        self.longitude = try container.decode(Double.self, forKey: .longitude)
        self.title = try container.decode(String.self, forKey: .title)
        self.time = try container.decode(String.self, forKey: .time)
        self.brigade = try container.decode(String.self, forKey: .brigade)
        self.coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(latitude), longitude: CLLocationDegrees(longitude))

Ответы [ 3 ]

0 голосов
/ 28 сентября 2018

Как то так?

enter image description here

MKAnnotationView наследуется от UIView.

Я сделал это с помощью , а не , добавив annotationView как аннотацию к MapView.

Вместо этого я сделал что-то вроде

mapView.addSubview(annotaionView)

После этого используйте один из способов iOS для анимации UIViews:

Самый простой способ - использовать UIView.animate{ }

В приведенном выше примере я использовал UIKit dynamics и SnapBehaviour, см. https://www.raywenderlich.com/2326-uikit-dynamics-tutorial-getting-started

Вам нужно только преобразовать координаты карты в UIView координаты:

 var snapTo = mapView.convert(cdPOI.coordinate, toPointTo: mapView)

после завершения анимации я удаляю аннотацию как подпредставление и делаю что-то вроде mapView.addAnnotation(annotation)

0 голосов
/ 18 ноября 2018

Вот фрагмент кода, который я написал на основе ответа OverD. Значение subtitle совпадает с busID.

DispatchQueue.global().async {

                for old in self.mapView.annotations {
                    for new in model.busArray {
                        if new.busID == old.subtitle {
                            if let annotation = old as? Bus {
                                DispatchQueue.main.async {                          
                                    annotation.coordinate = new.coordinate
                                }
                            }
                        }
                    }
                }

            }

РЕДАКТИРОВАТЬ - Рефакторинг и плавное перемещение представления аннотации из старой координаты в новую.

func matchIDs(mapView: MKMapView, annotations: [MKAnnotation], model: MyModel) {

        DispatchQueue.global().async {
            for annotation in annotations {
                if let filteredBus = model.busArray.filter({ $0.busID == annotation.subtitle }).first {
                    DispatchQueue.main.async {

                        UIView.animate(withDuration: 0.5, animations: {
                            let matchedBus = annotation
                            if let annotationForView = mapView.view(for: matchedBus)?.annotation as? Bus {
                                annotationForView.coordinate = filteredBus.coordinate
                            }
                        })

                    }
                } else {
                    // do nothing
                }
            }
        }
    }

Я также реализовал метод viewFor annotation в моем делегате MKMapView (View Controller), который создает пользовательский значок для каждой аннотации.

0 голосов
/ 30 августа 2018

Я бы добавил поле busID в класс Bus. Чтобы добавить шины на карту, я бы создал метод, который специально добавляет новые шины. И вы обновляете метод UI, вам следует использовать цикл for (или его эквивалент), чтобы соответствовать busID и изменить его новое местоположение.

Надеюсь, это направит вас в правильном направлении.

...