自定义大头针和自定义气泡的代码官方文档上都写的很详细,我这里不再记录,这篇主要记录的是自定义气泡上面有一个按钮,点击按钮响应对应事件的场景,效果如下:
上面的车是自定义的大头针,点击大头针弹出自定义气泡。
自定义一个View先:
class CCPOICallOutView: UIView {var guideActionCallBack:ClosureVoidToVoid?override init(frame: CGRect) {super.init(frame: frame)setUpUI()}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setUpUI() {self.addSubview(distanceLabel)self.addSubview(addressLabel)self.addSubview(guideBtn)self.backgroundColor = mainWhiteColorself.layer.cornerRadius = 2.0///布局略}///导航事件@objc func guidBtnAction() {self.guideActionCallBack?()}}
这个view就是气泡view,你需要什么样式就写成什么样式,接下来继承自MAAnnotationView来创建一个自己的大头针视图:
class CustomAnnotationView: MAAnnotationView {var delegate: CCCarLocationProtocol?var calloutView:CCPOICallOutView?let kCalloutWidth = 154.0.scaleBaselet kCalloutHeight = 61.0.scaleBaseoverride func setSelected(_ selected: Bool, animated: Bool) {if self.isSelected == selected { return }if selected {if (self.calloutView == nil) {self.calloutView = CCPOICallOutView(frame: CGRect(x: 0, y: 0, width: kCalloutWidth, height: kCalloutHeight))self.calloutView?.center = CGPoint(x: self.bounds.size.width/2 + self.calloutOffset.x, y: -self.bounds.size.height/2 + self.calloutOffset.y - 18.scaleBase)}self.calloutView?.title = self.annotation.titleself.calloutView?.subTitle = self.annotation.subtitleself.addSubview(self.calloutView!)self.calloutView?.guideActionCallBack = { [weak self] inself?.delegate?.guideToTargetAction()} } else {self.calloutView?.removeFromSuperview()}super.setSelected(selected, animated: animated)}}
让上面自定义的视图成为自定义大头针的气泡视图,布局完成。
这里遇到的一个问题是,气泡上的按钮怎么点都不响应,debug一下发现点击按钮响应的是map的单击事件。
于是分析了一下map--大头针--气泡视图,这三者的图层:
map上面有一个放有image的MAAnnotationView,这就是大头针视图,点击弹出的气泡视图也是MAAnnotationView上的一个视图,我们看到的气泡效果只不过是把气泡视图的位置给向上移动了一下,行程image在下calloutview在上的效果。
到这里也就可以解释为什么点击气泡视图的按钮响应的却是地图的点击事件了,因为气泡视图超出了父视图的范围,点击响应链无法传达到按钮。
于是我的解决方法是在自定义大头针视图里拦截点击事件,并重新分配:
///标记点和callOut气泡视图的关系:气泡视图是标记点视图的子视图,但是位置在标记点视图的外面,所以自定义的气泡视图上面的按钮方法无法响应。此处拦截标记点视图的hitTest方法,当当前hitPoint在自定义气泡视图的按钮上时,响应按钮的事件;当hitPoint在标记点外也不在按钮上时,响应父视图override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {if (point.x < 0 || point.x > self.bounds.width || point.y > self.bounds.size.height || point.y < 0) {if self.calloutView == nil {return self.superview}let callOutViewPoint = self.convert(point, to: self.calloutView)let btnPoint = self.calloutView?.convert(callOutViewPoint, to: self.calloutView?.guideBtn)let hitBtn = self.calloutView?.point(inside: btnPoint!, with: event)if hitBtn! {return self.calloutView?.guideBtn}return self.superview}return self}
思来想去也没有想到另外一种方法,如果你有其他办法可以解决这个问题 ,我们可以交流一下。