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

SwiftUI中如何覆盖动画逻辑?解决Mapbox与MapKit动画差异

SwiftUI动画差异:MapKit与Mapbox标注动画行为对比

我对SwiftUI动画的底层逻辑一直搞不懂——虽然从功能层面知道把状态变更包裹在withAnimation代码块中会触发动画,但具体的实现逻辑完全不透明。

最近遇到一个具体问题:尝试为地图标注的位置变更添加动画时,使用Apple的MapKit,将位置变更包裹在withAnimation中,标注会从原位置平滑移动至新位置;但使用Mapbox时,原标注会直接消失,再在新位置重新出现,完全没有过渡动画。

MapKit最小可复现示例(MRE)

import SwiftUI
import MapKit

extension CLLocationCoordinate2D {
    static let londonA = CLLocationCoordinate2D(
        latitude: 51.507222,
        longitude: -0.1275
    )
    
    static let londonB = CLLocationCoordinate2D(
        latitude: 51.508222,
        longitude: -0.1276
    )
}

struct MapkitMapView: View {
    private let position = MapCameraPosition.region(
        MKCoordinateRegion(
            center: .londonA,
            span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005)
        )
    )
    @State var curLocation: CLLocationCoordinate2D = .londonA
    
    var body: some View {
        Map(initialPosition: position) {
            Annotation("id", coordinate: curLocation) {
                Circle()
            }
        }
        .ignoresSafeArea()
        .overlay(alignment: .bottomTrailing) {
            Button("Change location") {
                withAnimation {
                    curLocation = .londonB // 相同的状态变更逻辑
                }
            }
        }
    }
}

Mapbox相同逻辑示例

(使用Mapbox SDK需先完成账号配置)

import SwiftUI
@_spi(Experimental) import MapboxMaps

struct MapboxMapView: View {
    private let position = Viewport.camera(
        center: .londonA,
        zoom: 16
    )
    @State var curLocation: CLLocationCoordinate2D = .londonA

    var body: some View {
        Map(initialViewport: position) {
            MapViewAnnotation(coordinate: curLocation) {
                Circle()
            }
        }
        .ignoresSafeArea()
        .overlay(alignment: .bottomTrailing) {
            Button("Change location") {
                withAnimation {
                    curLocation = .londonB // 相同的状态变更逻辑
                }
            }
        }
    }
}

根据建议修改后的Mapbox示例

import SwiftUI
@_spi(Experimental) import MapboxMaps

struct AnimatedMap: View, Animatable {
    private let position = Viewport.camera(
        center: .londonA,
        zoom: 16
    )
    var x: Double
    var y: Double
    
    var animatableData: AnimatablePair<Double, Double> {
        get { AnimatablePair(x, y) }
        set {
            x = newValue.first
            y = newValue.second
        }
    }
    
    var body: some View {
        Map(initialViewport: position) {
            MapViewAnnotation(coordinate: CLLocationCoordinate2D(latitude: x, longitude: y)) {
                Circle()
            }
        }
    }
}

struct AnimatedMapView: View {
    @State var x = 51.507222
    @State var y = -0.1275
    @State var i = 0
    
    var body: some View {
        AnimatedMap(x: x, y: y)
            .ignoresSafeArea()
            .animation(.smooth(duration: 5), value: x)
            .animation(.smooth(duration: 5), value: y)
            .overlay(alignment: .bottomTrailing) {
                Button("Change location") {
// ###### 快速切换位置会出现问题
                    let (x_i, y_i) = [(51.508222, -0.1276), (51.507222, -0.1275)][i % 2]
                    x = x_i
                    y = y_i
                    i += 1
                }
            }
    }
}

核心疑问

  • MapKit与Mapbox的动画表现差异根源是什么?
  • 如何修改Mapbox的动画逻辑,让标注位置变更时能像MapKit一样平滑过渡?
  • 更通用的问题:两个自定义View,使用相同的withAnimation包裹状态变更,为什么动画表现会不同?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 20:55:19