You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 4中如何在Google Maps实现相机沿Polyline动画?

实现Google Maps相机沿折线的动画效果(Swift 4)

嘿,我来帮你搞定这个需求!你已经有了折线编码字符串(示例:s_~fGwyptMSkFnBK),并且写好了基础的折线加载代码:

let polyline = GMSPolyline(path: GMSPath(fromEncodedPath:polylineString)) 
polyline.map = self.mapView 

下面给你两种实用的实现方案,从基础到进阶,按需选择:

方案一:逐顶点跳转的基础动画

这个方案简单直接,让相机沿着折线的每个顶点依次移动,适合快速实现需求:

  1. 首先从编码路径中提取所有的坐标点
  2. 用定时器逐个更新相机位置,控制每个点的移动时长
// 1. 提取折线的所有坐标点
guard let path = GMSPath(fromEncodedPath: polylineString) else { 
    print("Invalid polyline string")
    return 
}
var coordinateArray = [CLLocationCoordinate2D]()
for index in 0..<path.count() {
    coordinateArray.append(path.coordinate(at: index))
}

// 2. 设置动画参数并启动定时器
let moveDuration: TimeInterval = 0.6 // 每个顶点间的动画时长
var currentPointIndex = 0

let animationTimer = Timer.scheduledTimer(withTimeInterval: moveDuration, repeats: true) { timer in
    guard currentPointIndex < coordinateArray.count else {
        timer.invalidate() // 动画结束,停止定时器
        return
    }
    // 更新相机位置
    let targetCoord = coordinateArray[currentPointIndex]
    let targetCamera = GMSCameraPosition.camera(withTarget: targetCoord, zoom: 15)
    self.mapView.animate(to: targetCamera)
    currentPointIndex += 1
}

// 记得在合适的时机(比如页面销毁)销毁定时器,避免内存泄漏
// animationTimer.invalidate()

方案二:流畅的连续路径动画

如果想要更自然的平滑移动(不是跳点,而是沿着路径连续滑动),可以结合CATransaction来控制动画曲线和完成回调:

guard let path = GMSPath(fromEncodedPath: polylineString) else { return }
let totalAnimationDuration: TimeInterval = 12.0 // 整个动画的总时长
let totalSteps = path.count() - 1
if totalSteps <= 0 { return }

var currentStep = 0
let stepDuration = totalAnimationDuration / Double(totalSteps)

// 递归实现连续动画
func animateToNextSegment() {
    guard currentStep < totalSteps else { return }
    
    let startCoord = path.coordinate(at: currentStep)
    let endCoord = path.coordinate(at: currentStep + 1)
    
    // 使用CATransaction自定义动画属性
    CATransaction.begin()
    CATransaction.setAnimationDuration(stepDuration)
    // 用缓动函数让动画更自然
    CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .easeInEaseOut))
    
    // 更新相机到下一个点
    let targetCamera = GMSCameraPosition.camera(withTarget: endCoord, zoom: 15, bearing: 0, viewingAngle: 0)
    self.mapView.animate(to: targetCamera)
    
    // 当前段动画完成后,启动下一段
    CATransaction.setCompletionBlock {
        currentStep += 1
        self.animateToNextSegment()
    }
    CATransaction.commit()
}

// 启动动画
animateToNextSegment()

额外优化小技巧

  • 动态时长:可以根据折线的实际长度(计算所有点的距离总和)来动态设置总时长,避免长折线动画太快或短折线动画太慢
  • 朝向跟随:如果需要相机始终朝向前进方向,可以计算相邻两点的方位角,设置GMSCameraPosition的bearing参数
  • 性能优化:对于超长折线,可以每隔几个点取一个关键节点,减少动画步数,提升流畅度

内容的提问来源于stack exchange,提问作者Dima Nizanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:12:59