在用户位置标注上添加附件按钮

Adding accessory button on user location callout

我正在制作一个可点击的地标。我设置了地标的标题。标题是地址。我想如果你点击那个地址,它会推送到另一个视图以显示地址号码、城市、国家等。我试过这段代码。但是它在地标中的应用程序中没有UIButton,为什么?

编辑: 如果我将断点放在 func calloutAccessoryControlTapped 上,它不会崩溃。

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

    if annotation is MKUserLocation {
        //return nil so map view draws "blue dot" for standard user location
        return nil
    }

    var pin = "pin"

    var view = Mapa.dequeueReusableAnnotationViewWithIdentifier(pin) as? MKPinAnnotationView
    if view == nil {
        view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: pin)
        view!.canShowCallout = true
        view!.animatesDrop = true
        var arrowButton = UIButton()
        view!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
    } else {
        view!.annotation = annotation
    }
    return view
}

func mapView(Mapa: MKMapView!, annotation: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {

    if control == annotation.rightCalloutAccessoryView {
        println("Pressed!")
    }
}

完整代码:

import UIKit
import CoreLocation
import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {

    @IBOutlet weak var Mapa: MKMapView!
    let locationManager = CLLocationManager()
    var detail: UIButton!

    override func viewDidLoad()
    {
        super.viewDidLoad()


        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()



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


    }

    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()

    }



    //--- Find Address of Current Location ---//

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
    {
        //--- CLGeocode to get address of current location ---//
        CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in
            let spanX = 0.007
            let spanY = 0.007
            var newRegion = MKCoordinateRegion(center: self.Mapa.userLocation.coordinate, span: MKCoordinateSpanMake(spanX, spanY))
            self.Mapa.setRegion(newRegion, animated: true)


            if (error != nil)
            {
                println("Reverse geocoder failed with error" + error.localizedDescription)
                return
            }

            if placemarks.count > 0
            {
                let pm = placemarks[0] as! CLPlacemark
                self.displayLocationInfo(pm)
            }
            else
            {
                println("Problem with the data received from geocoder")
            }
        })

    }


    func displayLocationInfo(placemark: CLPlacemark?)
    {
        if let Placemark = placemark
        {
            //Stop updating kvôli vydrži baterke
            locationManager.stopUpdatingLocation()
            let location = self.locationManager.location
            var latitude: Double = location.coordinate.latitude
            var longitude: Double = location.coordinate.longitude
            let adresa = (Placemark.thoroughfare != nil) ? Placemark.thoroughfare : "Ulica: "
            let cislo = (Placemark.subThoroughfare != nil) ? Placemark.subThoroughfare : "Číslo ulice:"
            let mesto = (Placemark.locality != nil) ? Placemark.locality : "Mesto: "
            let stat = (Placemark.country != nil) ? Placemark.country : "Štát: "




            var coordinates:CLLocationCoordinate2D = placemark!.location.coordinate
            let theLocation: MKUserLocation = Mapa.userLocation
            theLocation.title = adresa




            println("GPS Súradnice :: \(latitude), \(longitude)")
            println(mesto)
            println(adresa)
            println(cislo)
            println(stat)

        }

    }

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!)
    {
        println("Chyba pri aktualizovaní lokácie " + error.localizedDescription)
    }

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

        if annotation is MKUserLocation {
            //return nil so map view draws "blue dot" for standard user location
            return nil
        }

        var pin = "pin"

        var view = Mapa.dequeueReusableAnnotationViewWithIdentifier(pin) as? MKPinAnnotationView
        if view == nil {
            view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: pin)
            view!.canShowCallout = true
            view!.animatesDrop = true
            var arrowButton = UIButton()
            view!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
        } else {
            view!.annotation = annotation
        }
        return view
    }

    func mapView(Mapa: MKMapView!, annotation: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {

        if control == annotation.rightCalloutAccessoryView {
            println("Pressed!")
        }
    }
}

您想在蓝点(用户位置)的标注上放置一个附件按钮。

viewForAnnotation 委托方法中,您确实有创建注释视图和设置 rightCalloutAccessoryView 的代码,但在方法的顶部有以下代码:

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

    if annotation is MKUserLocation {
        //return nil so map view draws "blue dot" for standard user location
        return nil
    }

地图的用户位置注释类型为 MKUserLocation,因此当地图视图为其调用 viewForAnnotation 时,此代码 returns nil 用于地图视图解释为 "display the default view and callout for this annotation"。默认标注仅显示标题和副标题。

创建自定义视图并设置 rightCalloutAccessoryView 的代码永远不会执行。


要设置 rightCalloutAccessoryView,您需要引用实际注释 view object.

您可以删除 MKUserLocationreturn nil,但您会得到一个标准图钉而不是动画蓝点。

您无法创建自己的动画蓝点视图实例,因为 class 是私有的。

因此您无法在 viewForAnnotation 委托方法中创建或访问用户位置注释视图。


您可以可靠地访问实际用户位置注释视图的地方是 didAddAnnotationViews 委托方法。我建议使用这种方法,因为这意味着实际上已经创建了一个注释视图并显示在屏幕上。

在此方法中,调用地图视图的 viewForAnnotation 实例方法并将其 userLocation 注释传递给它,然后设置视图的 rightCalloutAccessoryView:

func mapView(mapView: MKMapView!, didAddAnnotationViews views: [AnyObject]!) {
    if let ulav = mapView.viewForAnnotation(mapView.userLocation) {
        ulav.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
    }
}


与未出现的标注按钮无关,但:
您的 calloutAccessoryControlTapped 委托方法命名错误,点击按钮时不会被调用。

您的方法名为 mapView(annotation:calloutAccessoryControlTapped)

annotation 参数必须命名为 annotationView,即使将地图视图参数命名为 Mapa 也可以,但我建议坚持使用文档中给出的签名,以便修改后的方法将是:

func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
    if control == annotationView.rightCalloutAccessoryView {
        println("Pressed!")
    }
}