16

当我尝试放置图钉时,我无法在地图视图中加载自定义注释。

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

}
}

添加信息

我很肯定按钮功能完美。使用上面转储的当前代码,默认的红色引脚注释出现在它应该出现的位置。当我点击图钉时,我指定的描述也会毫无问题地出现。我对这段代码的唯一问题是我无法让我的图像代替无聊的默认红色别针

4

5 回答 5

59

我建议子类化`MKPointAnnotation。

神奇宝贝别针

我只包含了显示自定义地图图钉所需的代码。把它想象成一个模板

大纲

  • 我们将创建一个点注释对象并为CustomPointAnnotation该类分配一个自定义图像名称。

  • 我们将子类化MKPointAnnotation以设置图像并将其分配给委托协议方法viewForAnnotation

  • 在设置点注解的坐标后,我们将在地图上添加一个注解视图,并带有标题和副标题。

  • 我们将实现该viewForAnnotation方法,它是一种MKMapViewDelegate协议方法,它被调用以在地图上显示图钉。viewForAnnotation协议方法是自定义 pin 视图并为其分配自定义图像的最佳位置。

  • 我们将为给定的标识符出列并返回一个可重用的注解,并将注解转换为我们的自定义CustomPointAnnotation类,以便访问引脚的图像名称。

  • 我们将创建一个新的图像集Assets.xcassets并相应地放置 image@3x.png 和 image@2x.png。

  • 不要忘记plist。

NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

在此处输入图像描述

一如既往地在真实设备上进行测试。

调酒

//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
}
}
于 2016-07-17T08:55:27.587 回答
15

您需要处理一些问题。

MKMapView 和注解

首先,有必要了解如何MKMapView从注解中显示注解视图。有

  1. MKMapView - 显示地图并管理注释。
  2. MKMapViewDelegate - 您将数据从特定函数返回到 MKMapView。
  3. MKAnnotation - 包含有关地图上某个位置的数据。
  4. MKAnnotationView - 显示注释。

AnMKAnnotation保存地图上某个位置的数据。您创建此数据并将其交给MKMapView. 在未来的某个时候,当地图视图准备好显示注释时,它会回调委托并要求它创建一个MKAnnotationViewfor an MKAnnotation. 委托创建并返回视图,地图视图显示它。您在情节提要中或在代码中指定委托,例如mapView.delegate = self.

地点

跟踪用户位置的复杂性在于:

  1. 在启用位置跟踪之前,需要用户的许可。
  2. 用户允许跟踪后会有一段延迟,直到用户的位置可用。
  3. 甚至可能未启用位置服务。

CLLocationManager.authorizationStatus您的代码需要通过检查和实现CLLocationManagerDelegate方法来处理授权。

请注意,使用requestWhenInUseAuthorization需要输入NSLocationWhenInUseUsageDescriptioninInfo.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

    }
}
于 2016-07-14T20:21:20.973 回答
6

检查项目包中的 image.png 或 Assets.xcassets

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

    guard !annotation.isKind(of: MKUserLocation.self) else {
        return nil
    }

    let annotationIdentifier = "AnnotationIdentifier"

    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: 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
}
于 2016-07-14T11:21:30.483 回答
5

执行以下操作可能对您有用。

1) 为 Annotation 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)在您收到自定义引脚图像的地方执行以下代码

   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)
于 2016-07-18T05:31:20.360 回答
2

根据代码和 MapKit 指南,您的代码看起来是正确的。我在想可能是这条线annotationView.image = UIImage(named: "image.png")

编译时是否有image.png可能是错误的图像名称或未添加到项目中?也仅供参考,如果您使用的是.xcassets,则不必添加.png.

作为annotationView.image一个可选的,当图像UIImage(named: "image.png")为 nil 时,它不会崩溃,而只会渲染默认的 pin 图像。

如果这不是问题,请提供有关您已采取的调试步骤的更多信息,以便我们其他人可以更好地理解并帮助您。干杯 =)

于 2016-07-13T05:50:05.700 回答