Is it possible to make MGLPolyLines selectable? - Swift, MapBox
I've just checked back and it looks like this has been implemented though I'm not sure which Mapbox release rolled this out.
If you take a look at the simple Mapbox example, Annotation Models, that demos an MGLPolyline and interspaced circular annotations, you can make a simple mod to the supplied code and see for yourself. The demo looks like this:
If you look into the viewController code, add a couple of lines below the polyline creation:
let polyline = CustomPolyline(coordinates: &coordinates, count: UInt(coordinates.count))
polyline.title = "Polyline" // New line
polyline.subtitle = "Pretty Poly". // New line
// Set the custom `color` property, later used in the `mapView:strokeColorForShapeAnnotation:` delegate method.
polyline.color = .darkGray
Now you can tap and see a basic callout:
This example subclasses MGLPolyline (CustomPolyline) so that its appearance can be altered slightly but that doesn't change anything with regards to the tappability.
How to make a MGLPolyline tapable?
The Mapbox iOS API doesn't support that yet, unfortunately. See here.
There are a couple of workarounds within that link that you could try though.
UPDATE:
This is now possible: Check here.
Is it possible to create a custom popup for a MGLPolyline?
When you tap on the MGLPolyline you are selecting it. Even when you have returned false
from annotationCanShowCallout:
the polyline is selected after a tap even though there is probably no visible cue. This is why some of your taps have no visible action. These taps are deselecting the polyline (again invisibly).
What you can do is return false
from annotationCanShowCallout:
(assuming you don't want ANY annotations to have a callout) and use another delegate method to achieve your desired goal.
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return false
}
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
print("Tapped")
mapView.deselectAnnotation(annotation, animated: false)
}
By immediately deselecting the annotation you can register each tap as a selection, eliminating the missed ones.
Mapbox iOS SDK create a curve MGLPolyline with MKGeodesicPolyline get some strange
This is due to the fact the the line cross the international date change line so it's wrapping all the way around.
To avoid that you can add or subtract 360 from your longitude to fix it. https://github.com/mapbox/mapbox.js/issues/360
For example:
import Mapbox
import MapKit
public extension MGLPolyline {
class func geodesicPolyline(fromCoordinate: CLLocationCoordinate2D, toCoordinate: CLLocationCoordinate2D) -> MGLPolyline {
var coordinates = [fromCoordinate, toCoordinate]
let geodesicPolyline = MKGeodesicPolyline(coordinates: &coordinates, count: 2)
var normalizedCoordinates: [CLLocationCoordinate2D] = []
var previousCoordinate: CLLocationCoordinate2D?
for coordinate in geodesicPolyline.coordinates {
var normalizedCoordinate = coordinate
if let previousCoordinate = previousCoordinate, abs(previousCoordinate.longitude - coordinate.longitude) > 180 {
if (previousCoordinate.longitude > coordinate.longitude) {
normalizedCoordinate.longitude += 360
} else {
normalizedCoordinate.longitude -= 360
}
}
normalizedCoordinates.append(normalizedCoordinate)
previousCoordinate = normalizedCoordinate
}
return MGLPolyline(coordinates: normalizedCoordinates, count: UInt(geodesicPolyline.pointCount))
}
}
public extension MKPolyline {
var coordinates: [CLLocationCoordinate2D] {
var coords = [CLLocationCoordinate2D](repeating: kCLLocationCoordinate2DInvalid, count: self.pointCount)
self.getCoordinates(&coords, range: NSRange(location: 0, length: self.pointCount))
return coords
}
}
How can I change the color of an MGLPolyline?
I found that what needs to be done is you need to create a custom object for the polyline. The default MGLPolyline
does not support this.
Add a custom polyline like so:
class CustomPostPolyline: MGLPolyline {
var color: UIColor!
}
Put this in your didSelect
:
self.mapView.removeAnnotation(chosenPolyline!.polyline!)
chosenPolyline!.polyline!.lineColor = UIColor.green
self.mapView.addAnnotation(chosenPolyline!.polyline!)
How to change the color of a MGLPolyline?
You have to make mapView.delegate = self
Then implement this method:
func mapView(_ mapView: MGLMapView, strokeColorForShapeAnnotation annotation: MGLShape) -> UIColor {
return .blue
}
iOS Mapbox Updating the map while dragging annotation reverts the annotation to original coordinates
Here is the code explaining the Adonis's solution. Essentially add a pan gesture to a custom annotation's view and update the coords as and when the annotation is panned.
class CustomDraggableAnnotaionView: MGLAnnotationView {
required init(
reuseIdentifier: String?,
image: UIImage?,
annotation: CustomMapGLAnnotaion
) {
super.init(reuseIdentifier: reuseIdentifier)
setupDraggableAnnotations()
self.layer.zPosition = 10
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Draggable annotation handlers
private func setupDraggableAnnotations() {
addDraggableAnnotationGestureRecognizers()
}
private func addDraggableAnnotationGestureRecognizers() {
let panGesture = UIPanGestureRecognizer(
target: self,
action: #selector(self.draggedView(_:))
)
let tapGesture = UITapGestureRecognizer(
target: self,
action: #selector(self.tappedAnnotation(_:))
)
self.isUserInteractionEnabled = true
self.addGestureRecognizer(panGesture)
self.addGestureRecognizer(tapGesture)
for recognizer in self.gestureRecognizers! where recognizer is UITapGestureRecognizer {
tapGesture.require(toFail: recognizer)
}
for recognizer in self.gestureRecognizers! where recognizer is UIPanGestureRecognizer {
panGesture.require(toFail: recognizer)
}
}
@objc func draggedView(_ sender: UIPanGestureRecognizer) {
annotationObject?.draggable!.isCurrentlyDragging = true
let point = sender.location(in: MapManager.shared.mapView)
let coordinates = MapManager.shared.mapView.convert(
point,
toCoordinateFrom: MapManager.shared.mapView
)
annotationObject?.coordinate = coordinates
if sender.state == .ended {
// endDragging()
} else if sender.state == .began {
// startDragging()
annotationObject?.draggable!.handler.didStartDragging()
} else {
//
}
}
}
Related Topics
Replace Multiple Words from a String Based on the Values in an Array
Swift Uikit Dynamics Add Collision Boundary. After Rotation Does Not Work Correctly
Need Clarification for Swift Type Properties
Swift Sorting Array of Structs by String Double
Make Swiftui Rectangle Same Height or Width as Another Rectangle
How to Convert This Date Format in Swift
Decode/Encode Dictionary Keyed by Date
Handle Single Click and Double Click While Updating the View
Unexpectedly Found Nil While Unwrapping an Optional Value While Reading from Ds with Fromcstring
Is There a Neat Way to Represent a Fraction as an Attributed String
How to Pass Arguments into a Function with Completion Swift
Ordering Firebase Posts Chronologically Swift
Tableview Accessories Don't Load Correctly
Nsattributedstring and Emojis: Issue with Positions and Lengths