iosswiftxcodemapkitmkoverlay

How to animate MKOverlayRenderer added in Mapview iOS?


I have a mapview as shown below

enter image description here

The lines drawn in the map are using MKPolyline. I have used apple MapKit framework to display my map. My requirement is when the user selects the annotation on Polyline, the polyline should show direction as shown below

enter image description here

How can I show the animation in my map view? MKOverlayRenderer inherits from NSObject, It is not possible to animate using UIView Animation. I found some link here , its in objective C for iOS 7, IS it possible in swift to do the same?


Solution

  • MKOverlayRender inherits from NSObject. So it is not possible to add CAlayer to MKOverlayRenderer as explained in this sample project. The steps I followed to get the following animation effect are

    1. Subclass MKOverlayRenderer and add a custom image as overlay on the map

      class MapOverlayView: MKOverlayRenderer {

      var overlayImage: UIImage
      var angle: CGFloat
      
      init(overlay: MKOverlay, overlayImage:UIImage, angle: CGFloat) {
          self.overlayImage = overlayImage
          self.angle = angle
          super.init(overlay: overlay)
      }
      
      override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
      
          let mapImage = overlayImage.cgImage
          let mapRect = rect(for: overlay.boundingMapRect)
      
          // Calculate centre point on which image should be rotated
          let centerPoint = CGPoint(x: mapRect.midX, y: mapRect.midY)
      
          let a = sqrt(pow(centerPoint.x, 2.0) + pow(centerPoint.y, 2.0))
      
          let sub1 = (centerPoint.y / a) * cos(angle / 2.0)
          let sub2 = (centerPoint.x / a) * sin(angle / 2.0)
          let deltaX = -2 * a * sin((0 - angle) / 2.0) * (sub1 + sub2)
      
          let sub3 = (centerPoint.x / a) * cos(angle / 2.0)
          let sub4 = (centerPoint.y / a) * sin(angle / 2.0)
          let deltaY = 2 * a * sin((0 - angle) / 2.0) * (sub3 - sub4)
      
          context.translateBy(x: deltaX, y: deltaY)
          context.rotate(by: angle)
          context.draw(mapImage!, in: mapRect)
      }
      

      }

      class MapOverlay: NSObject, MKOverlay {

      var coordinate: CLLocationCoordinate2D
      var boundingMapRect: MKMapRect
      var identifier: String?
      
      init(identifier:String, coord: CLLocationCoordinate2D, rect: MKMapRect) {
          self.coordinate = coord
          self.boundingMapRect = rect
          self.identifier = identifier
      }
      

      }

    2. Call a timer to change alpha value of added overlays

      var timer = Timer() timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.toggle), userInfo: nil, repeats: true)

    Function to change alpha of overlay renderer

    func changeAlphaValue(identifier: String) {
            let overlays = self.mapView.overlays
            let tag: String = identifier
            for overlay in overlays {
                if let overlay = overlay as? MapOverlay {
                    let identifier = overlay.identifier
                    if identifier == tag {
                        let renderer = mapView.renderer(for: overlay)
                        DispatchQueue.main.async{
                            renderer?.alpha = 1.0
                        }
                    }
                    else {
                        let renderer = mapView.renderer(for: overlay)
                        DispatchQueue.main.async{
                            renderer?.alpha = 0.0
                        }
                    }
                }
            }
        }
    

    This will give the following animation on map

    enter image description here

    The project is available on GitHub - link