在MKMapView上为MKPolyline的绘制设置动画

时间:2017-10-21 13:40:46

标签: mapkit mkmapview mkpolyline

我有一个MKMapView来为一条线设置动画,方法是添加一条线,删除它,添加一个小段并将其重新添加到地图中。然而,这会给手机带来很多开销,看起来并不是最好的。我注意到谷歌地图和优步有干净的动画线条,无论长度或路线类型如何,都能显示顺畅运行的路线。有没有人对能耗更低,看起来更干净的解决方案有任何建议?

谢谢,SebO。

1 个答案:

答案 0 :(得分:0)

  1. 需要一个坐标数组。如果您只有开始和结束坐标,请使用以下代码获取坐标数组

    func getPointsOnRoute(from: CLLocation?, to: CLLocation?, on mapView: MKMapView?) -> [CLLocation]? {
    let NUMBER_OF_PIXELS_TO_SKIP: Int = 120
    //lower number will give a more smooth animation, but will result in more layers
    var ret = [Any]()
    
    var fromPoint: CGPoint? = nil
    if let aCoordinate = from?.coordinate {
        fromPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
    }
    var toPoint: CGPoint? = nil
    if let aCoordinate = to?.coordinate {
        toPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
    }
    let allPixels = getAllPoints(from: fromPoint!, to: toPoint!)
    var i = 0
    while i < (allPixels?.count)! {
        let pointVal = allPixels![i] as? NSValue
        ret.append(point(toLocation: mapView, from: (pointVal?.cgPointValue)!)!)
        i += NUMBER_OF_PIXELS_TO_SKIP
    }
    ret.append(point(toLocation: mapView, from: toPoint!)!)
    return ret as? [CLLocation] }
    
  2. 在 MKMapViewDelegate 的委托方法 - mapView(_:rendererFor:) 中使用坐标数组添加叠加层的渲染。

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    guard let polyline = overlay as? MKPolyline else {
            return MKOverlayRenderer()
        }
    
        let polylineRenderer = MKPolylineRenderer(overlay: polyline)
        polylineRenderer.strokeColor = .black
        polylineRenderer.lineWidth = 2
        return polylineRenderer
    }
    mapView.addOverlay(polyline) // add it to mapview
    
    1. 将折线渲染成小段以创建动画效果
    var drawingTimer: Timer?
    // ....// Somewhere in your View Controller
    func animate(route: [CLLocationCoordinate2D], duration: TimeInterval, completion: (() -> Void)?) {
            guard route.count > 0 else { return }
            var currentStep = 1
            let totalSteps = route.count
            let stepDrawDuration = duration/TimeInterval(totalSteps)
            var previousSegment: MKPolyline?
    
            drawingTimer = Timer.scheduledTimer(withTimeInterval: stepDrawDuration, repeats: true) { [weak self] timer in
                guard let self = self else {
                    // Invalidate animation if we can't retain self
                    timer.invalidate()
                    completion?()
                    return
                }
    
                if let previous = previousSegment {
                    // Remove last drawn segment if needed.
                    self.mapView.removeOverlay(previous)
                    previousSegment = nil
                }
    
                guard currentStep < totalSteps else {
                    // If this is the last animation step...
                    let finalPolyline = MKPolyline(coordinates: route, count: route.count)
                    self.mapView.addOverlay(finalPolyline)
                    // Assign the final polyline instance to the class property.
                    self.polyline = finalPolyline
                    timer.invalidate()
                    completion?()
                    return
                }
    
                // Animation step.
                // The current segment to draw consists of a coordinate array from 0 to the 'currentStep' taken from the route.
                let subCoordinates = Array(route.prefix(upTo: currentStep))
                let currentSegment = MKPolyline(coordinates: subCoordinates, count: subCoordinates.count)
                self.mapView.addOverlay(currentSegment)
    
                previousSegment = currentSegment
                currentStep += 1
            }
        }
    
相关问题