Annotation along route in MapKit
Questioner's edit:
Finally made it work with the help of this answer. I added this to the code below, where it says Here do the magic:
MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint)];
Original answer:
I don't know whether this will work or not. Just my idea on your question.
I guess you would have created the routes as following
(Check my inline comments)
MKDirectionsRequest *request =
[[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = _destination;
request.requestsAlternateRoutes = NO;
MKDirections *directions =
[[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
} else {
for (MKRoute *route in response.routes)
{
[_routeMap addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
//Here do the magic
//MKPolyline confronts to MKOverlay so you can get the coordinate like
//route.polyline.coordinate once you get the coordinate then you can build
//a annotation. A annotation is nothing but a coordinate with some title.
//According to MKOverlay coordinate property it justs gives you the
//center point of the overlay area
[self createAndAddAnnotationForCoordinate:route.polyline.coordinate]
}
}
}];
Adding Annotation
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D) coordinate{
MyAnnotation* annotation= [[MyAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = @"Any Title";
annotation.subtitle = @"Any Subtitle";
[yourMap addAnnotation: annotation];
}
How to add annotations at a certain distance along a MKPolyline route using iOS MapKit in Swift?
Treat your poly line points as a sequence of line segments. Start out with the target distance, 13 miles. Iterate over the points as line segments - .windows(ofCount: 2), compute the length of that line segment, if remaining distance is < line segment length, then your target point is the point that is 'remaining distance' from start of line segment in the direction of end of line segment. Otherwise, subtracting the line segment's length from remaining distance, until either you find your target or fall off the end of the poly line. The question of whether each line segment on poly line represents straight line (along map projection) or great circles (on surface of earth) is unimportant unless the distance between points is large.
MapKit: Route not being displayed between two annotations
You've almost got it.
The one issue that you need to resolve is the use of the MKMapView
delegate functions.
The easiest way to do that is to subclass MKMapView
and make your own map view that has conforms to MKMapViewDelegate
.
Firstly, create your own map view, subclassing MKMapView
and conforming to MKMapViewDelegate
. At the moment you're only really using the rendererFor overlay
delegate method so I'll just implement that, but you can add other methods if you require them.
class WrappableMapView: MKMapView, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = .red
renderer.lineWidth = 4.0
return renderer
}
}
Then you need to update your UIViewRepresentable
to use the new WrappableMapView
that you just created. I have gone for making a functional example, so here I am passing in the request and destination locations. You can handle this how you want but at least this will give you something that works.
struct MyMapView: UIViewRepresentable {
@Binding var requestLocation: CLLocationCoordinate2D
@Binding var destinationLocation: CLLocationCoordinate2D
private let mapView = WrappableMapView()
func makeUIView(context: UIViewRepresentableContext<MyMapView>) -> WrappableMapView {
mapView.delegate = mapView // make sure we set our delegate to be the mapView we just created
return mapView
}
func updateUIView(_ uiView: WrappableMapView, context: UIViewRepresentableContext<MyMapView>) {
let requestAnnotation = MKPointAnnotation()
requestAnnotation.coordinate = requestLocation
requestAnnotation.title = "Package Title"
uiView.addAnnotation(requestAnnotation)
let destinationAnnotation = MKPointAnnotation()
destinationAnnotation.coordinate = destinationLocation
destinationAnnotation.title = "Destination"
uiView.addAnnotation(destinationAnnotation)
let requestPlacemark = MKPlacemark(coordinate: requestLocation)
let destinationPlacemark = MKPlacemark(coordinate: destinationLocation)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: requestPlacemark)
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { response, error in
guard let response = response else { return }
let route = response.routes[0]
uiView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
uiView.setRegion(MKCoordinateRegion(rect), animated: true)
// if you want insets use this instead of setRegion
// uiView.setVisibleMapRect(rect, edgePadding: .init(top: 50.0, left: 50.0, bottom: 50.0, right: 50.0), animated: true)
}
}
}
Finally we can put it all together with a ContentView
that shows it works:
struct ContentView: View {
@State var requestLocation = CLLocationCoordinate2D(latitude: 51.509865, longitude: -0.118092)
@State var destinationLocation = CLLocationCoordinate2D(latitude: 51.501266, longitude: -0.093210)
var body: some View {
MyMapView(requestLocation: $requestLocation, destinationLocation: $destinationLocation)
}
}
This is what it should look like:
One thing to note, using the rendererFor overlay
delegate function in the simulator causes an error. This only happens in the simulator and not on device, so don't be surprised if you see an error message like this in the console.
2019-11-08 18:50:30.034066+0000 StackOverflow[80354:9526181] Compiler error: Invalid library file
Related Topics
Clipstobounds Causes Uiimage to Not Display in iOS10 & Xcode 8
Encryption with Rsa Public Key on iOS
How to Wait for Method That Has Completion Block (All on Main Thread)
Core Location Not Working in iOS 8
In Os X 10.10 (Yosemite Beta), How to Test Using iOS 6.1 Simulator
Uitableview Scrolls to Top When Reloading Cells with Changing Cell Heights
Header Displaced in Tableview with Uirefreshcontrol
How to List (Almost) All Emojis in Swift for iOS 8 Without Using Any Form of Lookup Tables
Autolayout Aspect Ratio for Uiimageview/Uiview
Xcode/Swift 'Filename Used Twice' Build Error
How Big Can the Payload Be When Sending Data via Watchconnectivity
Can't Import Embedded Framework with Xcode 6 Gm
"Can't Find Model for Source Store" Occurring During iPhone "Automatic Lightweight Migration"