Как я могу создать несколько пользовательских аннотаций в виде карты?

#swift #xcode #mkmapview #mkannotation #mkannotationview

#swift #xcode #mkmapview #mkannotation #mkannotationview

Вопрос:

Идея проста. У меня есть массив StopData(), который я создал в пользовательской структуре для отображения разных местоположений в MapView, выполняя цикл для каждого. Мой код выглядит примерно так:

 var route = [StopData]()

struct StopData {
    var addr: String?
    var coord: CLLocationCoordinate2D?
    var number: Int?
    var completed = false
}

func addStopsToMap() {
    mapView.removeAnnotations(mapView.annotations)
    for stop in route {
        let annotation = MKPointAnnotation()
        annotation.coordinate = stop.coord!
        annotation.title = "(stop.number!)"
        annotation.subtitle = stop.addr
        mapView.addAnnotation(annotation)
    }
}

func attemptLocationAccess() {
    // For use in foreground
    self.locationManager.requestWhenInUseAuthorization()
    
    if CLLocationManager.locationServicesEnabled() {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startUpdatingLocation()
    }
}

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    return NonClusteringAnnotation(annotation: annotation, reuseIdentifier: "NonClusteringAnnotation")
}

// MARK: - Location manager functions
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    return
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    locationManager.requestWhenInUseAuthorization()
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    guard status == .authorizedWhenInUse else {
        return
    }
    manager.requestLocation()
}
  

У меня также есть пользовательский класс, подобный следующему:

 class NonClusteringAnnotation: MKMarkerAnnotationView {
    override var annotation: MKAnnotation? {
        willSet {
            displayPriority = .required
        }
    }
}
  

У меня есть три основные вещи, которые я хотел бы выполнить.

  • Показывать каждый вывод аннотации и не кластер
  • Показывать пользовательские аннотации, если переменная completed имеет значение false
  • Показать другую пользовательскую аннотацию, если значение «завершено» равно true

С помощью этого кода каждый вывод отображается на карте и не группируется. Однако это также включает синюю точку текущего местоположения, которая отображается в виде красной булавки, как и остальные все аннотации. Итак, мне было интересно, как я могу создать несколько пользовательских представлений аннотаций и назначить им только определенные аннотации, сохраняя при этом синюю точку, указывающую текущее местоположение пользователей?

Что я пробовал до сих пор, так это добавление логической переменной типа willUseCustomAnnotation, которая вызывала бы другое возвращаемое значение, подобное этому:

 func addStopsToMap() {
    mapView.removeAnnotations(mapView.annotations)
    willUseCustomAnnotation = true
    for stop in route {
        let annotation = MKPointAnnotation()
        annotation.coordinate = stop.coord!
        annotation.title = "(stop.number!)"
        annotation.subtitle = stop.addr
        mapView.addAnnotation(annotation)
    }
    willUseCustomAnnotation = false
}

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if willUseCustomAnnotation {
        return NonClusteringAnnotation(annotation: annotation, reuseIdentifier: "NonClusteringAnnotation")
    } else {
        return nil
    }
}
  

Это не работает, потому что я предполагаю, что сначала он добавляет все аннотации в mapview, а затем создает представление для них всех сразу.

Я читал на форумах, что для изменения вида аннотации вы должны создать свой собственный вид в функции viewForAnnotation, однако это только в том случае, если вам нужен один пользовательский вид, а не несколько пользовательских представлений, как я хочу. Я новичок в MapKit, поэтому помощь будет действительно оценена.

Ответ №1:

Прошло много времени с тех пор, как я использовал MKMapView и пользовательские аннотации (это было в Objective-C.)

Кажется, я помню, что в вашей mapView(_:viewFor:) функции вам нужно проверить, является ли передаваемая вам аннотация MKUserLocation. Если это так, верните nil:

 func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
   guard !annotation is MKUserLocation else { 
       //This is the user location. Return nil so the system uses the blue dot.
       return nil  
   }
   //Your code to create an return custom annotations)
}
  

Комментарии:

1. если annotation === MapView.userLocation { возвращает ноль } else { возвращает некластерную аннотацию (аннотация: annotation, reuseIdentifier: «Некластерная аннотация») } Я добавил это в свой viewForAnnotation, и моя синяя точка снова отображается нормально! Есть ли в любом случае, что я могу проверить, если завершено = true, тогда я отображаю другой маркер?

2. Ваш код тоже работает. Что касается проверки того, completed == true ли это, это должно быть легко. Однако я не совсем понимаю, как создается / изменяется ваша структура. Структуры — это объекты значений, поэтому при любой попытке передать их вы получите новую копию, а не оригинал. Вам придется подробнее объяснить свой код и почему вы используете структуру в этой ситуации.

3. В принципе, у меня есть файл с именем GlobalVariables.swift, который содержит эту структуру, чтобы другие контроллеры представления могли ее читать и изменять. Всякий раз, когда структура изменяется, я вызываю функцию, которая обновляет экран addStopsToMap() , которая включает удаление всех аннотаций на карте и чтение их с обновленными данными. Итак, я не передаю структуру, а скорее читаю ее с помощью цикла for. В viewForAnnotation я не вижу никакого способа проверить, был ли stopData для этой аннотации отмечен как true Дайте мне знать, если вам нужна дополнительная информация