summaryrefslogtreecommitdiff
path: root/platform/ios/demo/Examples/Swift/CustomCalloutView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ios/demo/Examples/Swift/CustomCalloutView.swift')
-rw-r--r--platform/ios/demo/Examples/Swift/CustomCalloutView.swift127
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()
+ }
+}