我有以下代码从用户获取gps坐标并在他当前所在的位置放置一个红色标记:
class ViewController: UIViewController, CLLocationManagerDelegate {
@IBOutlet var mapView: MKMapView!
var locationManager: CLLocationManager?
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager!.delegate = self
if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
locationManager!.startUpdatingLocation()
} else {
locationManager!.requestWhenInUseAuthorization()
}
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .NotDetermined:
print("NotDetermined")
case .Restricted:
print("Restricted")
case .Denied:
print("Denied")
case .AuthorizedAlways:
print("AuthorizedAlways")
case .AuthorizedWhenInUse:
print("AuthorizedWhenInUse")
locationManager!.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.first!
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, 500, 500)
mapView.setRegion(coordinateRegion, animated: true)
locationManager?.stopUpdatingLocation()
let annotation = MKPointAnnotation()
annotation.coordinate = location.coordinate
longitude = location.coordinate.longitude
latitude = location.coordinate.latitude
mapView.addAnnotation(annotation)
locationManager = nil
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Failed to initialize GPS: ", error.description)
}
}
这很有效,正如你所看到的,我正在使用这些行来获取用户的lat和long以便稍后处理它:
longitude = location.coordinate.longitude
latitude = location.coordinate.latitude
现在我想添加另一个功能 - 用户在地图上看到他当前的位置作为红色别针并且可以保留原样或者 - 新功能 - 他可以将红色小伙子拖到其他地方并获得新的经度和纬度。
我一直在寻找可拖动功能,我决定将此代码添加到现有代码中:
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKPointAnnotation {
let pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "myPin")
pinAnnotationView.pinColor = .Purple
pinAnnotationView.draggable = true
pinAnnotationView.canShowCallout = true
pinAnnotationView.animatesDrop = true
return pinAnnotationView
}
return nil
}
但它没有做到这一点,而且引脚仍然不能拖动。我怎样才能解决这个问题,并且每次用户抓住它并移动它时,(现在打印到控制台)引脚的新位置?
如果您看到的是红色标记而不是您在代码示例中指定的紫色标记,则表明您尚未注册注释视图的重用标识符和/或未调用mapView(_:viewFor:)
。
现在,为了帮助避免视图控制器膨胀,我们通常将注释视图的自定义放在它自己的子类中(本着“单一责任原则”的精神):
class CustomAnnotationView: MKPinAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
pinTintColor = .purple
isDraggable = true
canShowCallout = true
animatesDrop = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
然后,在iOS 11及更高版本中,您可能会完全删除mapView(_:viewFor:)
,而只是注册该类,您就完成了:
override func viewDidLoad() {
super.viewDidLoad()
mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
}
在11之前的iOS版本中(或者如果您有一些复杂的逻辑,您可能要添加多种类型的注释),您需要指定地图视图的delegate
并实现mapView(_:viewFor:)
。
可以通过从IB中的“Connections Inspector”中的delegate
插座进行控制拖动,或者通过编程方式,例如,通过控制拖动IB中的代表。在viewDidLoad
:
mapView.delegate = self
然后我添加一个常量来指定我喜欢的自定义注释视图的重用标识符:
class CustomAnnotationView: MKPinAnnotationView {
static let reuseIdentifier = Bundle.main.bundleIdentifier! + ".customAnnotationView"
// these two are unchanged from as shown above
override init(annotation: MKAnnotation?, reuseIdentifier: String?) { ... }
required init?(coder aDecoder: NSCoder) { ... }
}
然后,您将实现mapView(_:viewFor:)
,如果可能的话,它将尝试将先前的注释视图出列并更新其annotation
,或者实例化新的注释视图,如果不是:
extension ViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation { return nil }
if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: CustomAnnotationView.reuseIdentifier) {
annotationView.annotation = annotation
return annotationView
}
return CustomAnnotationView(annotation: annotation, reuseIdentifier: CustomAnnotationView.reuseIdentifier)
}
}
有关较旧的Swift版本,请参阅previous iteration of this answer。
提示:您可以在选中时拖动注释,只有在显示标注时才能选择注释。当它有标题时,它可以显示标注。因此,除非你有一个标题,否则它将无效。