#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
Дайте мне знать, если вам нужна дополнительная информация