【问题标题】:Button added as an annotation view subview not working?添加为注释视图子视图的按钮不起作用?
【发布时间】:2020-07-04 21:26:09
【问题描述】:

我在地图的didSelect 方法的注释视图中添加了一个子视图,它按预期工作(截图)。我在弹出窗口中有一个按钮,它处于活动状态并启用了用户交互,但我没有收到按钮操作?

我进行了视图调试,似乎该按钮位于视图堆栈的顶部。

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

这个动作方法在Popupview里面

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

【问题讨论】:

    标签: ios swift uibutton mapkit mkannotationview


    【解决方案1】:

    您已将您的actionTapPickup 声明为@IBAction

    • 您是否真的从在 Interface Builder 中设计的 NIB 或情节提要中实例化了此视图?如果是这样,请确保您已成功连接您的@IBAction?您是从NIB 实例化此视图(而不是通过编程方式)?

    • 另一方面,如果您以编程方式创建此子视图,则不会使用 @IBAction 限定符,而是将其标记为 @objc,然后手动添加 .touchUpInside 事件的目标:

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

    如果您让我们知道您是通过编程方式还是通过 NIB 实例化此自定义弹出/标注,我们可以更详细地概述这一点。 (下面我的示例是程序化实现。)

    归根结底,在自定义标注中连接按钮很像在任何地方连接按钮。将@IBAction 用于IB 设计的视图,将@objcaddTarget 用于以编程方式创建的按钮。


    顺便说一句,一旦您解决了眼前的问题,值得注意的是,在让自定义标注正常工作方面存在一些微妙的问题。 Location Awareness Programming Guide: Creating Callouts 对此进行了概述,但不幸的是,这些示例是在 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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多