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
相关产品推荐
相关产品推荐

