簡體   English   中英

添加為注釋視圖子視圖的按鈕不起作用?

[英]Button added as an annotation view subview not working?

我在地圖的didSelect方法的注釋視圖中添加了一個子視圖,它按預期工作(截圖)。 我在彈出窗口中有一個按鈕,它處於活動狀態並且啟用了用戶交互,但是我沒有得到按鈕操作?

我做了一個視圖調試,看起來按鈕在視圖堆棧的頂部。

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    DispatchQueue.main.async {        
        view.addSubview(self.popupView)
    }
}

此操作方法位於Popupview

@IBAction func actionTapPickup(_ sender: UIButton) {
   print("button tapped)
}

在此處輸入圖片說明

您已將actionTapPickup聲明為@IBAction

  • 你真的從接口生成器中設計的 NIB 或故事板實例化了這個視圖嗎? 如果是這樣,請確保您成功連接了@IBAction 您是從NIB實例化此視圖(而不是以編程方式)嗎?

  • 另一方面,如果您以編程方式創建此子視圖,則不會使用@IBAction限定符,而只是將其標記為@objc ,然后手動添加.touchUpInside事件的目標:

     button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)

如果您讓我們知道您是以編程方式還是通過 NIB 實例化此自定義彈出窗口/標注,我們可以更詳細地概述這一點。 (我下面的示例是程序化實現。)

最重要的是,在自定義標注中連接按鈕就像在任何地方連接按鈕一樣。 使用@IBAction為IB設計的意見,並使用@objcaddTarget為程序創建按鈕。


順便說一句,一旦您解決了眼前的問題,值得注意的是,讓自定義標注正常工作存在一些微妙的問題。 位置感知編程指南:創建標注概述了這一點,但不幸的是,示例是在 Objective-C 中的。 無論如何,我們想要的行為是:

  • 如果您點擊地圖上的其他地方(即取消選擇注釋視圖),標注應該消失; 但無論如何
  • 如果您點擊注釋視圖的自定義標注(但不是在其按鈕上),您希望取消選擇注釋。

為了實現這一點,它在很大程度上可以歸結為兩個不完全明顯的小技巧:

  1. 為注釋視圖添加一個hitTest ,其中包括對自定義標注的命中測試。 這是為了確保在您點擊標注時不會取消選擇注釋。

  2. 在整個標注后面添加一個按鈕,以便它消耗任何錯過“60 分鍾內接聽”按鈕但仍在標注中的觸摸。

因此:

// let’s assume we have an annotation for our pickup location

class PickupLocationAnnotation: MKPointAnnotation {
    let hours: String

    init(hours: String) {
        self.hours = hours
        super.init()
    }
}

// let’s have a protocol for the callout to inform view controller that the “pickup” button was tapped

protocol CalloutViewDelegate: class {
    func calloutTapped(for annotation: MKAnnotation)
}

// Our callout view class

class CalloutView: UIView {
    weak var annotation: MKAnnotation?
    weak var delegate: CalloutViewDelegate?

    let button: UIButton = {
        let button = UIButton(type: .system)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("Tap here to pickup in 60 Mins", for: .normal)
        button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
        return button
    }()

    lazy var label: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.text = (annotation as? PickupLocationAnnotation)?.hours
        return label
    }()

    init(annotation: MKAnnotation?, delegate: CalloutViewDelegate) {
        self.annotation = annotation
        self.delegate = delegate
        super.init(frame: .zero)
        configure()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func configure() {
        addBackgroundButton(to: self)
        addSubview(button)
        addSubview(label)

        NSLayoutConstraint.activate([
            button.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
            button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
            button.topAnchor.constraint(equalTo: topAnchor, constant: 10),
            button.bottomAnchor.constraint(equalTo: label.topAnchor, constant: -10),

            label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
            label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
            label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10)
        ])

        layer.cornerRadius = 10
        layer.borderColor = UIColor.blue.cgColor
        layer.borderWidth = 2
        backgroundColor = .white
    }

    @objc func didTapButton(_ sender: Any) {
        if let annotation = annotation {
            delegate?.calloutTapped(for: annotation)
        }
    }

    fileprivate func addBackgroundButton(to view: UIView) {
        let button = UIButton(type: .custom)
        button.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.topAnchor.constraint(equalTo: view.topAnchor),
            button.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            button.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            button.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
    }
}

// our annotation view for our pickup annotations

class PickupLocationAnnotationView: MKPinAnnotationView {
    weak var calloutView: UIView?

    override func prepareForDisplay() {
        super.prepareForDisplay()
        canShowCallout = false
    }

    // make sure that hits in callout are recognized as not-deselecting the annotation view

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if let hitView = super.hitTest(point, with: event) { return hitView }

        if let calloutView = calloutView {
            let point = convert(point, to: calloutView)
            return calloutView.hitTest(point, with: event)
        }

        return nil
    }

    // lets move the add callout here, inside the annotation view class,
    // so the annotation view can keep track of its callout

    func addCallout(delegate: CalloutViewDelegate) {
        removeCallout()

        let view = CalloutView(annotation: annotation, delegate: delegate)
        view.translatesAutoresizingMaskIntoConstraints = false
        addSubview(view)
        calloutView = view

        NSLayoutConstraint.activate([
            view.centerXAnchor.constraint(equalTo: centerXAnchor),
            view.bottomAnchor.constraint(equalTo: topAnchor, constant: -10)
        ])
    }

    func removeCallout() {
        calloutView?.removeFromSuperview()
    }
}

// random view controller example that adds an annotation

class ViewController: UIViewController {
    @IBOutlet weak var mapView: MKMapView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let coordinate = CLLocationCoordinate2D(latitude: 37.332693, longitude: -122.03071)
        mapView.camera = MKMapCamera(lookingAtCenter: coordinate, fromDistance: 1_000, pitch: 0, heading: 0)
        mapView.register(PickupLocationAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)

        let hours = """
            Mon to Thu 10am-7pm
            Fri 12pm-9pm
            Sat 10am-11pm
            """
        let annotation = PickupLocationAnnotation(hours: hours)
        annotation.coordinate = coordinate
        mapView.addAnnotation(annotation)
    }
}

// the selecting and deselecting of annotation views

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
        if let view = view as? PickupLocationAnnotationView {
            view.addCallout(delegate: self)
        }
    }

    func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
        if let view = view as? PickupLocationAnnotationView {
            view.removeCallout()
        }
    }
}

// the delegate conformance so view controller can know when the callout button was tapped

extension ViewController: CalloutViewDelegate {
    func calloutTapped(for annotation: MKAnnotation) {
        print(#function)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM