按钮添加为注释视图子视图不能用?

问题描述 投票:0回答:1

我已经添加了一个子视图到 didSelect 的方法,并且工作正常(截图)。我在弹出窗口里面有一个按钮,它是活动的,并且启用了用户交互,但是我没有得到按钮的动作。

我做了一个视图调试,似乎按钮是在视图堆栈的顶部。

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

这个动作方法是在 Popupview

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

enter image description here

ios swift uibutton mapkit mkannotationview
1个回答
0
投票

你已经声明了你的 actionTapPickup 作为 @IBAction.

  • 你真的从NIB或在Interface Builder中设计的故事板实例化了这个视图吗?如果是的话,请确保你已经将你的 @IBAction 成功?您是否从 NIB (而不是以编程方式)?

  • 另一方面,如果您以编程方式创建了这个子视图,您就不会使用 @IBAction 修饰语,而只是将其标记为 @objc 然后手动添加目标为 .touchUpInside 事件。

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

如果你让我们知道你是通过编程还是通过NIB实例化这个自定义的popupcallout,我们就可以更详细的说明一下。(下面我的例子,就是程序化的实现。)

一句话,在自定义的callout中挂上一个按钮就像在任何地方挂上一个按钮一样。使用 @IBAction 为IB设计的视图,并使用 @objcaddTarget 为编程创建的按钮。


作为一个旁观者,一旦你有了眼前的问题,值得注意的是,在让自定义调用正常工作时,有一些微妙的问题。这个 位置感知编程指南。创建呼出 概述了这一点,但不幸的是,例子是在Objective-C中。总之,我们想要的行为是:如果你点击地图上的其他地方(即取消选择注解视图),调用应该会消失。

  • 如果你点击地图上的其他地方(比如取消选择注解视图), 调出应该会消失; 但是
  • 如果您点击注解视图的自定义呼出(但不是它的按钮),您就会发现 不要 想要取消选择注释。

要做到这一点,很大程度上可以归纳为两个并不明显的小技巧。

  1. 添加一个 hitTest 自定义呼出的注解视图,其中包括对点击的测试。这是为了确保当你点击呼出时,注释不会被取消选择。

  2. 在整个callout后面添加一个按钮,这样它就可以消耗任何错过你的 "60分钟后领取 "按钮,但仍在callout中的触动。

这样一来。

// 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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.