Как создать собственный MKAnnotationView с XIB

Я хочу иметь собственный MKAnnotationView. Я создал файл xib в IB и установил для него класс MyAnnotationView.

    class MyAnnotationView: MKAnnotationView {

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @IBOutlet weak var textLabel: UILabel!
    @IBOutlet weak var busIcon: UIImageView!

}

Вот как выглядит xib - у него есть связанные textLabel и busIcon:

Как создать собственный MKAnnotationView с XIB

Я использую метод делегата viewFor annotation для создания представлений для всех аннотаций:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {     

        // Don't want to show a custom image if the annotation is the user's location.
        if (annotation is MKUserLocation) {
            return nil
        } else {

            let annotationIdentifier = "AnnotationIdentifier"
            var annotationView: MyAnnotationView?                           


            if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "AnnotationIdentifier") as? MyAnnotationView {
                annotationView = dequeuedAnnotationView
                annotationView?.annotation = annotation
            } else {

                // if no views to dequeue, create an Annotation View
                let av = MyAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
                av.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
                annotationView = av     
            }


            if let annotationView = annotationView {
                annotationView.canShowCallout = true                        // callout bubble
                annotationView.image = UIImage(named: "Delivery")
                annotationView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
            }

            return annotationView

        }

    }

annotationView.image = UIImage(named: "Delivery")

&

AnnotationView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)

существуют только для того, чтобы проверить, работает ли код, и отобразить образец представления на карте, поскольку они используют стандартные свойства, унаследованные от MKAnnotationView.

Я не знаю, как заставить метод viewFor annotation использовать созданный мной XIB. Может ли кто-нибудь помочь мне с этим? Я искал решение, но нашел что-то подходящее только в Obj C.

Спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
2 276
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

1- Создайте подкласс представления UIView с помощью xib, скажем, CallView

2- Внутри viewforAnnotation

let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "id") 
let customView = Bundle.main.loadNibNamed("CallView", owner: self, options: nil).first! as! CallView
// here configure label and imageView
annotationView.addSubview(customView)

у вас возникают проблемы с размером просмотра таким образом

Vyachaslav Gerchicov 11.12.2019 12:17

ОБНОВЛЕННЫЙ КОД НА ОСНОВЕ Ответ Ш-хана

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

                //  Don't want to show a custom image if the annotation is the user's location.
                if (annotation is MKUserLocation) {
                    return nil
                } else {

                    let annotationIdentifier = "AnnotationIdentifier"
                    let nibName = "MyAnnotationView"
                    let viewFromNib = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?.first as! MyAnnotationView
                    var annotationView: MyAnnotationView?

                    // if there is a view to be dequeued, use it for the annotation
                    if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) as? MyAnnotationView {

                        if dequeuedAnnotationView.subviews.isEmpty {
                            dequeuedAnnotationView.addSubview(viewFromNib)
                        }
                        annotationView = dequeuedAnnotationView
                        annotationView?.annotation = annotation
                    } else {

                        // if no views to dequeue, create an Annotation View
                        let av = MyAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
                        av.addSubview(viewFromNib)
                        annotationView = av     // extend scope to be able to return at the end of the func
                    }

                    // after we manage to create or dequeue the av, configure it
                    if let annotationView = annotationView {
                        annotationView.canShowCallout = true                                    // callout bubble
                        annotationView.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
                        annotationView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)

                        let customView = annotationView.subviews.first as! MyAnnotationView
                        customView.frame = annotationView.frame
                        customView.textLabel.text = (annotationView.annotation?.title)!
                    }
                    return annotationView
                }
}
**Create Custom MKPointAnnotation Class**

import UIKit
import MapKit

    class CustomPointAnnotation: MKPointAnnotation {
       var id : Int
       var url : String

      init(id : Int , url : String ) {
      self.id = id
       self.url = url

}
    }

Создайте Xib для класса MarkerView для просмотра аннотаций

class MarkerView: MKAnnotationView {
    @IBOutlet weak var imgVwUser: UIImageView!



     init(annotation: CustomPointAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let hitView = super.hitTest(point, with: event)
        if (hitView != nil)
        {
            self.superview?.bringSubviewToFront(self)
        }
        return hitView
    }
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let rect = self.bounds
        var isInside: Bool = rect.contains(point)
        if (!isInside)
        {
            for view in self.subviews
            {
                isInside = view.frame.contains(point)
                if isInside
                {
                    break
                }
            }
        }
        return isInside
    }
}

Добавьте делегатов MKMapView в свой ViewController

extension YourViewController : MKMapViewDelegate {

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

        //  Don't want to show a custom image if the annotation is the user's location.
        if (annotation is MKUserLocation) {
            return nil
        } else {

            let annotationIdentifier = "AnnotationIdentifier"
            let nibName = "MarkerView"
            let viewFromNib = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?.first as! MarkerView
            var annotationView: MarkerView?

            // if there is a view to be dequeued, use it for the annotation
            if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) as? MarkerView {

                if dequeuedAnnotationView.subviews.isEmpty {
                    dequeuedAnnotationView.addSubview(viewFromNib)
                }
                annotationView = dequeuedAnnotationView
                annotationView?.annotation = annotation
            } else {

                // if no views to dequeue, create an Annotation View
                let av = MarkerView(annotation: annotation as? CustomPointAnnotation, reuseIdentifier: annotationIdentifier)
                av.addSubview(viewFromNib)
                annotationView = av     // extend scope to be able to return at the end of the func
            }

            // after we manage to create or dequeue the av, configure it
            if let annotationView = annotationView {
                annotationView.canShowCallout = false                                    // callout bubble


                if let annotation =  annotation as? CustomPointAnnotation {


                    annotationView.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
                    annotationView.frame = CGRect(x: 0, y: 0, width: 66, height: 75)

                    let customView = annotationView.subviews.first as? MarkerView
                    customView?.frame = annotationView.frame
                    let image = annotation.url

                    let imageUrl = URL(string: image)


                    customView?.imgVwUser.sd_setImage(with: imageUrl, placeholderImage:  UIImage(named:"defaults"), options: [.refreshCached], completed: nil)


                }
            }

            return annotationView
        }
    }




     }

ДОБАВИТЬ аннотацию к просмотру карты

extension YourViewController  {

    func addAnnotation(){

        let annotationsToRemove = mapView.annotations.filter { $0 !== mapView.userLocation }
        mapView.removeAnnotations( annotationsToRemove )

        var annotations: [CustomPointAnnotation] = []

        for  i in 0..<self.arrayData.count {


            let customPoints = CustomPointAnnotation.init(id: arrayData[i].id  ?? 0, url:  arrayData[i].url)


            let location = CLLocationCoordinate2DMake(self.arrayData[i].lat ?? 0, self.arrayData[i].lng ?? 0)
            customPoints.coordinate = location

            annotations.append(customPoints)
        }

        mapView.addAnnotations(annotations)

    }


}

1) рамка вида аннотации становится нулевой, и вы должны установить ее вручную, что уже означает ошибку; 2) аннотации начали немного прыгать при выделении. Проголосовано против

Vyachaslav Gerchicov 11.12.2019 12:41

Другие вопросы по теме