我正在开发一个人项目,允许用户在地图上添加注释引脚,然后从Flickr下载所选位置的照片。引脚/注释是可点击的,以便触发某些功能(例如,删除或触发到详细视图的segue)。我目前无意中使callout action
工作。以下是我写的代码:
class ViewController: UIViewController {
@IBOutlet weak var mapView: MKMapView!
let reusedPinId = "pin"
var selectedLocation: TouringLocationAnnotation!
let initLocation = CLLocation(latitude: 21.282788, longitude: -157.829444)
let regionRadius: CLLocationDistance = 1000
var myPin: MKPinAnnotationView?
var editModeOn = false
override func viewDidLoad() {
super.viewDidLoad()
let longPressRecognizer = UILongPressGestureRecognizer()
longPressRecognizer.addTarget(self, action: "addMapAnnotation:")
mapView.addGestureRecognizer(longPressRecognizer)
mapView.delegate = self
centerMapOnLocation(initLocation)
let touringSpot = TouringSpot(title: "Picture at this touring site", coordinate: CLLocationCoordinate2D(latitude: 21.283921, longitude: -157.831661))
mapView.addAnnotation(touringSpot) //TODO: change this to the first pin
self.navigationItem.rightBarButtonItem = self.editButtonItem() //toggle edit and Done
self.navigationItem.title = "Virtual Tourist"
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
if let savedPins = fetchedResultsController.fetchedObjects {
for pin in savedPins {
print("retrieved a pin from coredata")
showPinOnMap(pin as! Pin)
}
}
} catch let error as NSError {
print("error in retrieving saved pins: \(error)")
}
}
//show the pin as an annotation on map
func showPinOnMap(pin: Pin) {
if pin.isValid() { //check if the pin has coordinate set up
let locationAnnot = TouringLocationAnnotation(tourLocationPin: pin)
//TODO: fetch photo for the pin
if pin.photos.count == 0 {
print("about to fetch flickr photos for pin:")
pin.fetchPhotosFromFlickr({ (success, error) -> Void in
if success {
print("successfl in fetching flickr photos")
} else {
print("error in fetching flickr photos")
//TODO: give warning to user
return
}
});
}
mapView.addAnnotation(locationAnnot)
} else {
print("pin is invalid")
//TODO: give warning to user on invalid pin
}
}
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
}
以下是添加地图注释的方法:
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
func addMapAnnotation(gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.Began {
let touchPoint = gestureRecognizer.locationInView(mapView)
let newCoordinate = mapView.convertPoint(touchPoint, toCoordinateFromView: mapView)
let annotation = TouringSpot(title: "new spot", coordinate: newCoordinate)
var locationNameStr = ""
let locationDictionary: [String:AnyObject] = [
Pin.Keys.Name: "\(newCoordinate.latitude, newCoordinate.longitude)",
Pin.Keys.Latitude: newCoordinate.latitude,
Pin.Keys.Longitude: newCoordinate.longitude
]
defer {
//TODO: check for duplicate pins in database first?
let newPin = Pin(dictionary: locationDictionary, context: sharedContext)
newPin.name = locationNameStr
do {
//persist the new pin to core data
try sharedContext.save()
print("saved a pin!")
showPinOnMap(newPin)
} catch let error as NSError {
print("error saving the new pin in context")
}
}
//problem: cannot pass the locationNameStr to the defer{} block
//TODO: retrieve the location name as title of the annotation
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude), completionHandler: {(placemarks, error) -> Void in
if error != nil {
print("reverse geocoding failed with error: \(error)")
//return
} else if placemarks!.count > 0 {
let firstPlace = placemarks![0] as CLPlacemark
if firstPlace.country != nil {
locationNameStr = "a place in \(firstPlace.country!)"
}
else if firstPlace.locality != nil {
locationNameStr = "a place in \(firstPlace.locality!)"
}
print("location name: \(locationNameStr)")
}
})
}
}
点击“编辑”按钮后,用户可以点击图钉进行删除:
override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if editing {
print("going to edit the pins")
let titleDict: NSDictionary = [NSForegroundColorAttributeName: UIColor.redColor()
]
navigationController?.navigationBar.titleTextAttributes = titleDict as! [String : AnyObject]
self.navigationItem.title = "Click a pin for deletion"
editModeOn = true
} else {
print("done with editing the pins")
let titleDict: NSDictionary = [NSForegroundColorAttributeName: UIColor.blackColor()
]
navigationController?.navigationBar.titleTextAttributes = titleDict as! [String : AnyObject]
self.navigationItem.title = "Tourist"
editModeOn = false
}
}
以下是我对MKMapViewDelegate
:
extension ViewController: MKMapViewDelegate {
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let anno = annotation as? TouringLocationAnnotation {
print("calling the viewForAnnotation delegate")
var pinView: MKPinAnnotationView!
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(reusedPinId)
as? MKPinAnnotationView {
dequeuedView.annotation = anno
pinView = dequeuedView
} else {
pinView = MKPinAnnotationView(annotation: anno, reuseIdentifier: reusedPinId)
}
pinView.canShowCallout = true
if #available(iOS 9.0, *) {
pinView.pinTintColor = UIColor.purpleColor()
} else {
// Fallback on earlier versions
}
pinView.animatesDrop = true
// pinView.calloutOffset = CGPoint(x: -5, y: 5)
let btn = UIButton(type: .DetailDisclosure)
// btn.addTarget(self, action: Selector("showPhotosForPin:"), forControlEvents: UIControlEvents.TouchUpInside)
pinView.rightCalloutAccessoryView = btn //UIButton.buttonWithType(.DetailDisclosure) as! UIView
return pinView
}
return nil
}
//call out
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
print("callout accessory control triggered!")
/*
if let annotation = view.annotation as? TouringLocationAnnotation {
mapView.removeAnnotation(annotation)
}
*/
let annotation = view.annotation as! TouringLocationAnnotation
if control == view.rightCalloutAccessoryView {
print("right callout button is clicked")
}
}
func showPhotosForPin(sender: UIButton!) {
print("showing photos for pin")
}
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
let latitude = view.annotation!.coordinate.latitude
let longitude = view.annotation!.coordinate.longitude
//let annotation = view.annotation as! TouringLocationAnnotation
if !editModeOn {
print("did select the annotation View, getting its coordinates, latitude: \(latitude), longitude: \(longitude)")
// print("pin is: \(annotation.tourLocationPin.latitude)")
} else {
print("for deleting the pin")
}
}
}
引脚保留在CoreData
中,当应用程序启动时,它们将从持久性中获取并在地图上注释。从下面的屏幕截图中可以看出,这些引脚是用紫色标注的(唯一的红色引脚来自我的硬编码注释,而不是来自CoreData),我认为这表明我的引脚被转换为{{1} }成功输入。但是,当我点击引脚时,标注动作不会触发,我希望看到以下打印输出
MKAnnotationView
请注意,为简洁起见,我们省略了CoreData的代码,因为我认为它们与我的问题无关