动画MKMapView摄像头标题转换

时间:2017-06-01 19:52:07

标签: ios mkmapview core-animation cadisplaylink

当userTrackingMode为followWithHeading时,我想要实现的是mapView中的动画(地图如何旋转)。

事情是我不能在这里使用这种跟踪模式,因为我们根据不同的位置信息而不是iOS提供的位置信息绘制我们自己的蓝点。每次标题更新时,我都要设置mapView的摄像头标题值,但要设置动画以使其平滑。

目前我已尝试过:

  1. setCamera: animated:当标题经常更改时,这不会很好。
  2. animateWithDuration:animations:completion:这根本不起作用。
  3. 我尝试了CADisplayLink,就像下面的代码一样,过渡仍不顺利。
  4. CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateHeading)]; timer.frameInterval = 5; [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];

    updateHeading方法中,我只是将mapView的相机设置为当前标题self.camera.heading = newHeading.trueHeading;

    我想这不起作用,因为我每隔5/60秒只设置一次相机,这不是动画。

    有人能指出实现这个目的的正确方法吗?任何想法都将受到赞赏。

1 个答案:

答案 0 :(得分:0)

使用CADisplayLink时我有些运气,如果您移动较大的角度(例如170度),则速度会稍慢一些,但总体来说效果会很好。我将考虑在其中添加缓动功能,但是暂时这是我所见过的最平滑的路线。

private var headingDisplayLink: CADisplayLink?
private var desiredHeading: Double = 0

func locationManager(didUpdateHeading newHeading: CLHeading) {
    self.updateHeading(to: newHeading.trueHeading)
}

private func updateHeading(to heading: Double) {
    self.desiredHeading = heading.rounded()

    if self.headingDisplayLink == nil {
        self.headingDisplayLink = CADisplayLink(target: self, selector: #selector(self.headingDisplayLinkUpdate(link:)))
        self.headingDisplayLinkUpdate(link: self.headingDisplayLink!)
        self.headingDisplayLink?.add(to: RunLoop.main, forMode: .defaultRunLoopMode)
    }
}

@objc private func headingDisplayLinkUpdate(link: CADisplayLink) {
    if let camera = self.mapView?.camera.copy() as? MKMapCamera {
        var delta: Double = self.desiredHeading > camera.heading ? 1 : -1
        let difference = fabs(camera.heading - self.desiredHeading)
        if difference > 180 {
            delta *= -1
        }

        camera.heading += delta
        self.mapView?.setCamera(camera, animated: false)

        if camera.heading.rounded() == self.desiredHeading {
            self.headingDisplayLink?.invalidate()
            self.headingDisplayLink = nil
        }
    }
}