iOS 8 SDK, Swift, MapKit Drawing a Route - swift

I need to draw route between two points and I'm using MKDirectionsRequest for my purpose.
Getting a route is OK, but I have trouble with drawing it.
In iOS 8 SDK there's no function
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
There is only this one:
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer!
And for some reason, I can't understand why that method isn't called.
Delegate for MapView is set and MapKit is imported.
Here is the rendererForOverlay function that is implemented:
func rendererForOverlay(overlay: MKOverlay!) -> MKOverlayRenderer! {
println("rendererForOverlay");
var overlayRenderer : MKOverlayRenderer = MKOverlayRenderer(overlay: overlay);
var overlayView : MKPolylineRenderer = MKPolylineRenderer(overlay: overlay);
view.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.5);
return overlayView;
}

The map view isn't calling your rendererForOverlay method because it is not named correctly.
The method must be named exactly:
mapView(mapView:rendererForOverlay)
but in your code it's named:
rendererForOverlay(overlay:)
In addition, you should check that the type of the overlay argument is MKPolyline and set the strokeColor of the polyline renderer.
(The view.backgroundColor in the existing code is actually changing the background color of the view controller's view -- not the polyline.)
Example:
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
println("rendererForOverlay");
if (overlay is MKPolyline) {
var pr = MKPolylineRenderer(overlay: overlay);
pr.strokeColor = UIColor.blueColor().colorWithAlphaComponent(0.5);
pr.lineWidth = 5;
return pr;
}
return nil
}

Related

How I automatically rotate annotationView image following map rotating in MKMapKit?

My code does rotate annotationViewImage, when the map rotated.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "mark")
annotationView.image = UIImage(named: "pinArrow")
let ang = mapView.camera.heading
let radi = Double.pi * Double(ang / 360)
let resultAng = 2 * Float(radi)
annotationView.transform = CGAffineTransform(rotationAngle: CGFloat(-resultAng))
annotationView.canShowCallout = true
return annotationView
}
above code, when the map rotates, do not implement the above method.
So add below code
func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
print("visible")
let anns = mapView.annotations
mapView.removeAnnotations(anns)
mapView.addAnnotations(anns)
}
and then, when map rotate, so do annotationView image.
But so a few some slow and loading time a few some long.
Because map moving delegate of above code, so many doing and repeat.
I seek a more simple way without loading slow.
How rotate sync map and annotationView image?

Prevent replacing of WMS Overlay while adding Polygon or Polyline to MKMapView

I have implemented Web Map Service in the MKMapView by subclassing the MKTileOverlay & rendering it using MKTileOverlayRenderer. It works fine and displays the custom map properly.
When I call method like mapView.addOverlay(polyLine) to add Polyline or Polygon. The WMS overlay gets replaced with the Apple Maps overly.
// Set up the overlay and adds it to MKMapView.
func setupTileRenderer() {
let wmsURL = formTemplate?.wmsURL
let overlay = WMSTileOverlay(urlTemplate: wmsURL)
overlay.canReplaceMapContent = true
mapView.addOverlay(overlay, level: .aboveLabels)
tileRenderer = MKTileOverlayRenderer(tileOverlay: overlay)
wmsTileOverlay = overlay
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolyline {
let render = MKPolylineRenderer(overlay: overlay)
render.lineWidth = 2
render.strokeColor = UIColor.red
return render
} else if overlay is MKPolygon {
let render = MKPolygonRenderer(overlay: overlay)
render.lineWidth = 2
render.strokeColor = UIColor.red
return render
} else if overlay is WMSTileOverlay {
return tileRenderer!
}
return MKOverlayRenderer(overlay: overlay)
}
How do I prevent this? I don't want wmsTileOverlay to get replaced while adding polyline or polygon.
I realised that before drawing the polygon I was removing the previous overlays so at that time I was removing all the overlays. Just checking the overlay is WMSTileOverlay then not removing it.
/// Clears the overlays added by the user.
func clearOverlaysOnMapView() {
for overlay in mapView.overlays {
if !(overlay is WMSTileOverlay) {
mapView.removeOverlay(overlay)
}
}
}

How to prevent overlays on the map from disappearing when zoom scale changes in swift?

I am trying to render an overlay (polygon) on the map using swift MapKit. I can render successfully but when I zoom out too much then zoom in again, all the rendered polygons get disappear. How can I prevent that from happening and force the rendered polygons to stay on the map at all zoom scales? I am using MapKit and MKPolygonRenderer.
I add the polygons to the map using the following method in my viewController:
// function to add polygon overlay to the map
private func addPolygonsToMap() {
guard let polygons = arrayOfpolygons else {
return
}
for polygon in polygons {
mapView.addOverlay(polygon)
}
}
My view controller conforms to MKMapViewDelegate and here is the delegate method for it.
// method for overlay on map
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolygonRenderer(overlay: overlay)
renderer.fillColor = UIColor.purple.withAlphaComponent(0.4)
renderer.strokeColor = .black
renderer.lineWidth = 2
return renderer
}
here is a simple demonstration with some points to draw a test polygon.
https://developer.apple.com/documentation/mapkitjs/mapkit/polygonoverlay
I did not find any swift solution for this problem.
I am running on simulator with iOS 13.

MKPolygon Swift not appearing

Im trying to create a shape on my map but I'm having a hard time finding any information about mkpolygon with swift. I was hoping someone on here would see this and point me into the right direction.
This is what I currently have but the polygon is not appearing.
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
let pr = MKPolygonRenderer(overlay: overlay)
pr.strokeColor = UIColor.purpleColor()
pr.lineWidth = 14
return pr
}
func createPolyline(mapView: MKMapView) {
var points=[CLLocationCoordinate2DMake(49.142677, -123.135139),CLLocationCoordinate2DMake(49.142730, -123.125794),CLLocationCoordinate2DMake(49.140874, -123.125805),CLLocationCoordinate2DMake(49.140885, -123.135214)]
let polygon = MKPolygon(coordinates: &points, count: points.count)
self.mapView.addOverlay(polygon)
}
Turns out what I was forgetting was to set the map view delegate. I will leave this up incase anyone wants to see what I used to get mkpolygon working in swift.

How add description to MKPolyline & MKPolygon?

How add annotations to polyline and polygon in Swift & MapKit? By Point is simple.
S.,
I'm not sure what you're asking here, but I assume you want to display an annotation somewhere on the polyline.
First the intro how to get the the polyline:
So, lets assume you have an array of CLLocation objects that will draw the polyline on the map. We call this array of location objects: myLocations and it's of type [CLLocation]. Now somewhere in your app you call a method that creates the polyline, we call this method createOverlayObject(locations: [CLLocation]) -> MKPolyline.
Your call could look like this:
let overlayPolyline = createOverlayObject(myLocations)
The method you called then could look like this:
func createOverlayObject(locations: [CLLocation]) -> MKPolyline {
//This method creates the polyline overlay that you want to draw.
var mapCoordinates = [CLLocationCoordinate2D]()
for overlayLocation in locations {
mapCoordinates.append(overlayLocation.coordinate)
}
let polyline = MKPolyline(coordinates: &mapCoordinates[0], count: mapCoordinates.count)
return polyline
}
This was the first part, don't forget to implement the mapView(_: rendererForOverlay overlay:) to get the line rendered. this part could look something like this:
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
//This function creatss the renderer for the polyline overlay. This makes the polyline actually display on screen.
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = mapLineColor //The color you want your polyline to be.
renderer.lineWidth = self.lineWidth
return renderer
}
Now the second part get the annotation somewhere on the map. This is actually straight forward if you know what the coordinates are where you want to put your annotation. creating and displaying the annotation is straightforward again, assuming you have defined a map view called myNiceMapView:
func createAnnotation(myCoordinate: CLLocationCoordinate2D) {
let myAnnotation = MKPointAnnotation()
myAnnotation.title = "My nice title"
startAnnotation.coordinate = myCoordinate
self.myNiceMapView.addAnnotations([myAnnotation])
}
Don't forget to implement mapView(_: MKMapView, viewForAnnotation annotation:) -> MKAnnotationView? method, which might look like:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
//This is the mapview delegate method that adjusts the annotation views.
if annotation.isKindOfClass(MKUserLocation) {
//We don't do anything with the user location, so ignore an annotation that has to do with the user location.
return nil
}
let identifier = "customPin"
let trackAnnotation = MKAnnotationView.init(annotation: annotation, reuseIdentifier: identifier)
trackAnnotation.canShowCallout = true
if annotation.title! == "Some specific title" { //Display a different image
trackAnnotation.image = UIImage(named: "StartAnnotation")
let offsetHeight = (trackAnnotation.image?.size.height)! / 2.0
trackAnnotation.centerOffset = CGPointMake(0, -offsetHeight)
} else { //Display a standard image.
trackAnnotation.image = UIImage(named: "StopAnnotation")
let offsetHeight = (trackAnnotation.image?.size.height)! / 2.0
trackAnnotation.centerOffset = CGPointMake(0, -offsetHeight)
}
return trackAnnotation
}
Now the challenges is finding the right coordinate where to put your annotation. I can't find anything better than that you have a CLLocationCoordinate2D that references the location you want to put the annotation. Then with a for-in loop find the location where you want to put your annotation, something like this:
for location in myLocations {
if (location.latitude == myReferenceCoordinate.latitude) && (location.longitude == myReferenceCoordinate.longitude) {
self.createAnnotation(location: CLLOcationCoordinate2D)
}
}
Hope this answers your question.