Свифт с iOS MapKit с пользовательских аннотаций [закрыт]

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

import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate{
@IBAction func ReportBtn(sender: AnyObject) {
    //MARK: Report Date And Time Details
    let ReportTime = NSDate()
    let TimeStamp = NSDateFormatter()
    TimeStamp.timeStyle = NSDateFormatterStyle.ShortStyle
    TimeStamp.dateStyle = NSDateFormatterStyle.ShortStyle
    TimeStamp.stringFromDate(ReportTime)
    //MARK: Default Point Annotation Begins
    let ReportAnnotation = MKPointAnnotation()
    ReportAnnotation.title = "Annotation Created"
    ReportAnnotation.subtitle = ReportTime.description
    ReportAnnotation.coordinate = locationManager.location!.coordinate
    mapView(MainMap, viewForAnnotation: ReportAnnotation)
    MainMap.addAnnotation(ReportAnnotation)
}

@IBOutlet weak var MainMap: MKMapView!
let locationManager = CLLocationManager()

override func viewDidLoad() {
    super.viewDidLoad()
    self.locationManager.requestWhenInUseAuthorization()
    self.locationManager.delegate = self
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    self.locationManager.startUpdatingLocation()
    self.MainMap.showsUserLocation = true
}


//MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
 let location = locations.last
 let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
 let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02 ))
    self.MainMap.setRegion(region, animated: true)
    //self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError){
    print(error.localizedDescription)
}
//MARK:Custom Annotation Begins Here
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    guard !annotation.isKindOfClass(MKUserLocation) else {
        return nil
    }
    /*if annotation.isKindOfClass(MKUserLocation){
        //emty return, guard wasn't cooperating
    }else{
    return nil
    }*/
    let annotationIdentifier = "AnnotationIdentifier"

    var annotationView: MKAnnotationView?
    if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier){
        annotationView = dequeuedAnnotationView
        annotationView?.annotation = annotation
    }
    else{
        let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
        av.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
        annotationView = av
    }
    if let annotationView = annotationView {
        annotationView.canShowCallout = true
        annotationView.image = UIImage(named: "image.png")
    }
    return annotationView

}
}

Добавлена Информация

Я уверен, что функциональность кнопки, работает идеально. С текущим кодом, сброшенным выше, аннотация красного pin-кода по умолчанию появляется там, где она должна. Когда я нажимаю на pin-код, описание, которое я указал, также появляется без проблем. единственная проблема у меня с этим кодом заключается в том, что я не могу получить мой образ, чтобы занять место скучного, по умолчанию красный pin

5 ответов


я рекомендую подклассы ' MKPointAnnotation.

Покемон Pin

я включил только необходимый код для отображения пользовательского pin-кода карты. Думайте об этом как шаблон.

контур

  • мы создадим объект точечной аннотации и назначим пользовательское имя изображения с помощью CustomPointAnnotation класса.

  • мы подкласс MKPointAnnotation чтобы установить изображение и назначить его на метод протокола делегата viewForAnnotation.

  • мы добавим вид аннотации на карту после установки координаты точки аннотации с заголовком и подзаголовком.

  • мы будем использовать тег viewForAnnotation метод, который является MKMapViewDelegate метод протокола, который вызывается для pins для отображения на карте. viewForAnnotation способ протоколом лучшее место для настройки представления pin-кода и назначения пользовательского изображения он.

  • мы удалим и вернем многоразовую аннотацию для данного идентификатора и приведем аннотацию к нашему пользовательскому CustomPointAnnotation класс для доступа к имени изображения pin-кода.

  • мы создадим новый набор изображений в Assets.xcassets и место image@3x.png и image@2x.png соответственно.

  • не забывайте, что файл plist.

NSLocationAlwaysUsageDescription и NSLocationWhenInUseUsageDescription

enter image description here

как всегда тест на реальном устройстве.

мошенничество

//1

CustomPointAnnotation.swift

import UIKit
import MapKit

class CustomPointAnnotation: MKPointAnnotation {
var pinCustomImageName:String!
}

//2

ViewController.swift

import UIKit
import MapKit

class ViewController: UIViewController, MKMapViewDelegate,  CLLocationManagerDelegate {


@IBOutlet weak var pokemonMap: MKMapView!
let locationManager = CLLocationManager()
var pointAnnotation:CustomPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!

override func viewDidLoad() {
    super.viewDidLoad()

    //Mark: - Authorization
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
    locationManager.startUpdatingLocation()

    pokemonMap.delegate = self
    pokemonMap.mapType = MKMapType.Standard
    pokemonMap.showsUserLocation = true

}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location = CLLocationCoordinate2D(latitude: 35.689949, longitude: 139.697576)
    let center = location
    let region = MKCoordinateRegionMake(center, MKCoordinateSpan(latitudeDelta: 0.025, longitudeDelta: 0.025))
    pokemonMap.setRegion(region, animated: true)

    pointAnnotation = CustomPointAnnotation()
    pointAnnotation.pinCustomImageName = "Pokemon Pin"
    pointAnnotation.coordinate = location
    pointAnnotation.title = "POKéSTOP"
    pointAnnotation.subtitle = "Pick up some Poké Balls"

    pinAnnotationView = MKPinAnnotationView(annotation: pointAnnotation, reuseIdentifier: "pin")
    pokemonMap.addAnnotation(pinAnnotationView.annotation!)
}

func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
    print(error.localizedDescription)
}

//MARK: - Custom Annotation
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    let reuseIdentifier = "pin"
    var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseIdentifier)

    if annotationView == nil {
        annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
        annotationView?.canShowCallout = true
    } else {
        annotationView?.annotation = annotation
    }

    let customPointAnnotation = annotation as! CustomPointAnnotation
    annotationView?.image = UIImage(named: customPointAnnotation.pinCustomImageName)

    return annotationView
}
}

есть несколько вопросов,которые вам нужно решить.

MKMapView и аннотации

во-первых, надо понимать как MKMapView отображает вид аннотации из аннотации. Есть

  1. MKMapView-отображает карту и управляет аннотациями.
  2. MKMapViewDelegate-вы возвращаете данные из определенных функций в MKMapView.
  3. MKAnnotation - содержит данные о местоположении на карте.
  4. MKAnnotationView - отображает аннотацию.

An MKAnnotation содержит данные, расположение на карте. Вы создаете эти данные и передаете их MKMapView. В какой-то момент в будущем, когда представление карты будет готово к отображению аннотации, оно перезвонит делегату и попросит его создать MKAnnotationView на MKAnnotation. Делегат создает и возвращает представление, а представление карты отображает его. Вы указываете делегата в раскадровке или в коде, например mapView.delegate = self.

расположение

отслеживание местоположения пользователей осложняется:

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

ваш код должен иметь дело с авторизацией путем проверки CLLocationManager.authorizationStatus и осуществляет CLLocationManagerDelegate методы.

обратите внимание, что использовать requestWhenInUseAuthorization требуется запись для NSLocationWhenInUseUsageDescription на Info.plist

пример

пример проекта на GitHub.

import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

    // Instance of location manager. 
    // This is is created in viewDidLoad() if location services are available.
    var locationManager: CLLocationManager?

    // Last location made available CoreLocation.
    var currentLocation: MKUserLocation? {
        didSet {
            // Hide the button if no location is available.
            button.hidden = (currentLocation == nil)
        }
    }

    // Date formatter for formatting dates in annotations.
    // We use a lazy instance so that it is only created when needed.
    lazy var formatter: NSDateFormatter = {

        let formatter = NSDateFormatter()
        formatter.timeStyle = NSDateFormatterStyle.ShortStyle
        formatter.dateStyle = NSDateFormatterStyle.ShortStyle
        return formatter
    }()

    @IBOutlet var button: UIButton!
    @IBOutlet var mapView: MKMapView!

    override func viewDidLoad() {

        super.viewDidLoad()

        mapView.delegate = self

        // Track the user's location if location services are enabled.
        if CLLocationManager.locationServicesEnabled() {

            locationManager = CLLocationManager()
            locationManager?.delegate = self
            locationManager?.desiredAccuracy = kCLLocationAccuracyBest

            switch CLLocationManager.authorizationStatus() {

            case .AuthorizedAlways, .AuthorizedWhenInUse:
                // Location services authorised.
                // Start tracking the user.
                locationManager?.startUpdatingLocation()
                mapView.showsUserLocation = true

            default:
                // Request access for location services.
                // This will call didChangeAuthorizationStatus on completion. 
                locationManager?.requestWhenInUseAuthorization()
            }
        }
    }

    //
    // CLLocationManagerDelegate method
    // Called by CLLocationManager when access to authorisation changes.
    //
    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {

        switch status {

        case .AuthorizedAlways, .AuthorizedWhenInUse:
            // Location services are authorised, track the user.
            locationManager?.startUpdatingLocation()
            mapView.showsUserLocation = true

        case .Denied, .Restricted:
            // Location services not authorised, stop tracking the user.
            locationManager?.stopUpdatingLocation()
            mapView.showsUserLocation = false
            currentLocation = nil

        default:
            // Location services pending authorisation.
            // Alert requesting access is visible at this point.
            currentLocation = nil
        }
    }

    //
    // MKMapViewDelegate method
    // Called when MKMapView updates the user's location.
    //
    func mapView(mapView: MKMapView, didUpdateUserLocation userLocation: MKUserLocation) {

        currentLocation = userLocation
    }

    @IBAction func addButtonTapped(sender: AnyObject) {

        guard let coordinate = currentLocation?.coordinate else {
            return
        }

        let reportTime = NSDate()
        let formattedTime = formatter.stringFromDate(reportTime)

        let annotation = MKPointAnnotation()
        annotation.title = "Annotation Created"
        annotation.subtitle = formattedTime
        annotation.coordinate = coordinate

        mapView.addAnnotation(annotation)
    }

    //
    // From Bhoomi's answer. 
    //
    // MKMapViewDelegate method
    // Called when the map view needs to display the annotation.
    // E.g. If you drag the map so that the annotation goes offscreen, the annotation view will be recycled. When you drag the annotation back on screen this method will be called again to recreate the view for the annotation.
    //
    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

        guard !annotation.isKindOfClass(MKUserLocation) else {

            return nil
        }

        let annotationIdentifier = "AnnotationIdentifier"

        var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier)

        if annotationView == nil {
            annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
            annotationView!.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
            annotationView!.canShowCallout = true
        }
        else {
            annotationView!.annotation = annotation
        }

        annotationView!.image = UIImage(named: "smile")

        return annotationView

    }
}

проверьте изображение.png в вашем проекте или активах.xcassets

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

         guard !annotation.isKindOfClass(MKUserLocation) else {
                return nil
            }

            let annotationIdentifier = "AnnotationIdentifier"

            var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier)
            if annotationView == nil {
                annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
        annotationView.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
                annotationView!.canShowCallout = true
            }
            else {
                annotationView!.annotation = annotation
            }

            annotationView!.image = UIImage(named: "image.png")

            return annotationView

        }

делать, как следовать может быть работа для вас.

1) Создайте пользовательский класс для Pin-кода аннотации.

class CustomPointAnnotation: MKPointAnnotation {
    var imageName: UIImage!
}

2)определить переменную, как показано ниже.

var locationManager = CLLocationManager()

3) вызов метода ниже в viewDidLoad()

  func checkLocationAuthorizationStatus() {
        if CLLocationManager.authorizationStatus() == .AuthorizedAlways {
            map.showsUserLocation = false
        } else {
            locationManager.requestWhenInUseAuthorization()
        }
    }

4) Поставить ниже код в viewWillAppear()

    self.map.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
    locationManager.delegate = self
    dispatch_async(dispatch_get_main_queue(),{
        self.locationManager.startUpdatingLocation()
    })

5) наиболее важная реализация ниже метода.

 func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
        if !(annotation is CustomPointAnnotation) {
            return nil
        }

        let reuseId = "Location"

        var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
        if anView == nil {
            anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
            anView!.canShowCallout = true
        }
        else {
            anView!.annotation = annotation
        }
        let cpa = annotation as! CustomPointAnnotation
        anView!.image = cpa.imageName

        return anView
    } 

6) выполните код ниже, где вы получили пользовательский pin-код

   let strLat = "YOUR LATITUDE"
   let strLon = "YOUR LONGITUDE"
   let info = CustomPointAnnotation()
   info.coordinate = CLLocationCoordinate2DMake(strLat.toDouble()!,strLon.toDouble()!)
   info.imageName = resizedImage
   info.title = dict!["locationName"]! as? String
   self.map.addAnnotation(info)

из кода и в соответствии с руководством MapKit ваш код выглядит правильно. Я думаю, что это может быть эта строка annotationView.image = UIImage(named: "image.png")

есть ли шанс, что image.png может быть неправильное имя изображения или не добавлено в проект при компиляции? Также просто FYI, если вы используете .xcassets, вам не нужно добавлять .png.

As annotationView.image является необязательным, когда изображение UIImage(named: "image.png") равно нулю, он не будет сбой, но просто визуализировать изображение pin по умолчанию.

если это не проблема, пожалуйста, предоставьте больше информации о шагах отладки, которые Вы предприняли, чтобы остальные из нас могли лучше понять и помочь вам. Ура =)