diff options
Diffstat (limited to 'platform/ios/demo/Examples/Swift/CustomCalloutView.swift')
-rw-r--r-- | platform/ios/demo/Examples/Swift/CustomCalloutView.swift | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/platform/ios/demo/Examples/Swift/CustomCalloutView.swift b/platform/ios/demo/Examples/Swift/CustomCalloutView.swift new file mode 100644 index 0000000000..41483d41b4 --- /dev/null +++ b/platform/ios/demo/Examples/Swift/CustomCalloutView.swift @@ -0,0 +1,127 @@ +import Mapbox + +class CustomCalloutView: UIView, MGLCalloutView { + var representedObject: MGLAnnotation + + // Lazy initialization of optional vars for protocols causes segmentation fault: 11s in Swift 3.0. https://bugs.swift.org/browse/SR-1825 + + var leftAccessoryView = UIView() /* unused */ + var rightAccessoryView = UIView() /* unused */ + + weak var delegate: MGLCalloutViewDelegate? + + let tipHeight: CGFloat = 10.0 + let tipWidth: CGFloat = 20.0 + + let mainBody: UIButton + + required init(representedObject: MGLAnnotation) { + self.representedObject = representedObject + self.mainBody = UIButton(type: .system) + + super.init(frame: .zero) + + backgroundColor = .clear + + mainBody.backgroundColor = .darkGray + mainBody.tintColor = .white + mainBody.contentEdgeInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0) + mainBody.layer.cornerRadius = 4.0 + + addSubview(mainBody) + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - MGLCalloutView API + func presentCallout(from rect: CGRect, in view: UIView, constrainedTo constrainedView: UIView, animated: Bool) { + if !representedObject.responds(to: #selector(getter: MGLAnnotation.title)) { + return + } + + view.addSubview(self) + + // Prepare title label + mainBody.setTitle(representedObject.title!, for: .normal) + mainBody.sizeToFit() + + if isCalloutTappable() { + // Handle taps and eventually try to send them to the delegate (usually the map view) + mainBody.addTarget(self, action: #selector(CustomCalloutView.calloutTapped), for: .touchUpInside) + } else { + // Disable tapping and highlighting + mainBody.isUserInteractionEnabled = false + } + + // Prepare our frame, adding extra space at the bottom for the tip + let frameWidth = mainBody.bounds.size.width + let frameHeight = mainBody.bounds.size.height + tipHeight + let frameOriginX = rect.origin.x + (rect.size.width/2.0) - (frameWidth/2.0) + let frameOriginY = rect.origin.y - frameHeight + frame = CGRect(x: frameOriginX, y: frameOriginY, width: frameWidth, height: frameHeight) + + if animated { + alpha = 0 + + UIView.animate(withDuration: 0.2) { [weak self] in + self?.alpha = 1 + } + } + } + + func dismissCallout(animated: Bool) { + if (superview != nil) { + if animated { + UIView.animate(withDuration: 0.2, animations: { [weak self] in + self?.alpha = 0 + }, completion: { [weak self] _ in + self?.removeFromSuperview() + }) + } else { + removeFromSuperview() + } + } + } + + // MARK: - Callout interaction handlers + + func isCalloutTappable() -> Bool { + if let delegate = delegate { + if delegate.responds(to: #selector(MGLCalloutViewDelegate.calloutViewShouldHighlight)) { + return delegate.calloutViewShouldHighlight!(self) + } + } + return false + } + + func calloutTapped() { + if isCalloutTappable() && delegate!.responds(to: #selector(MGLCalloutViewDelegate.calloutViewTapped)) { + delegate!.calloutViewTapped!(self) + } + } + + // MARK: - Custom view styling + + override func draw(_ rect: CGRect) { + // Draw the pointed tip at the bottom + let fillColor : UIColor = .darkGray + + let tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0) + let tipBottom = CGPoint(x: rect.origin.x + (rect.size.width / 2.0), y: rect.origin.y + rect.size.height) + let heightWithoutTip = rect.size.height - tipHeight + + let currentContext = UIGraphicsGetCurrentContext()! + + let tipPath = CGMutablePath() + tipPath.move(to: CGPoint(x: tipLeft, y: heightWithoutTip)) + tipPath.addLine(to: CGPoint(x: tipBottom.x, y: tipBottom.y)) + tipPath.addLine(to: CGPoint(x: tipLeft + tipWidth, y: heightWithoutTip)) + tipPath.closeSubpath() + + fillColor.setFill() + currentContext.addPath(tipPath) + currentContext.fillPath() + } +} |