如何使用Kotlin及Mapbox Android SDK v10.9.1实现标记点位置动画?
Mapbox SDK v10.9.1 (Kotlin) 标记点位置动画实现
核心思路
在Mapbox SDK v10+版本中,推荐使用SymbolLayer管理标记点。通过ValueAnimator插值计算起始点到终点的坐标,逐帧更新标记点的几何位置,实现平滑的移动动画。
步骤1:配置依赖
确保模块级build.gradle中引入正确版本的SDK:
dependencies { implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:10.9.1' }
步骤2:布局中添加MapView
<com.mapbox.mapboxsdk.maps.MapView android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" mapbox:mapbox_cameraTargetLat="37.7749" mapbox:mapbox_cameraTargetLng="-122.4194" mapbox:mapbox_cameraZoom="12.0" />
步骤3:实现标记点动画代码
import android.animation.ValueAnimator import android.graphics.BitmapFactory import android.os.Bundle import android.view.animation.AccelerateDecelerateInterpolator import androidx.appcompat.app.AppCompatActivity import com.mapbox.geojson.Feature import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point import com.mapbox.mapboxsdk.Mapbox import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.OnMapReadyCallback import com.mapbox.mapboxsdk.style.layers.SymbolLayer import com.mapbox.mapboxsdk.style.sources.GeoJsonSource import com.mapbox.mapboxsdk.style.layers.PropertyFactory as PF class MainActivity : AppCompatActivity(), OnMapReadyCallback { private lateinit var mapView: MapView private lateinit var mapboxMap: MapboxMap private var markerSymbolId: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 初始化Mapbox(替换为你的access token) Mapbox.getInstance(this, getString(R.string.mapbox_access_token)) setContentView(R.layout.activity_main) mapView = findViewById(R.id.mapView) mapView.onCreate(savedInstanceState) mapView.getMapAsync(this) } override fun onMapReady(map: MapboxMap) { mapboxMap = map // 初始化标记点 initMarker() // 启动位置动画:从旧金山市区到另一个地点,时长3秒 startMarkerAnimation( start = LatLng(37.7749, -122.4194), end = LatLng(37.7895, -122.401), duration = 3000L ) } private fun initMarker() { mapboxMap.getStyle { style -> // 1. 创建GeoJson数据源 val markerSource = GeoJsonSource("marker-source") style.addSource(markerSource) // 2. 添加自定义标记图标(可选,可替换为默认图标) val markerBitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_custom_marker) style.addImage("custom-marker", markerBitmap) // 3. 创建SymbolLayer并添加到地图 val markerLayer = SymbolLayer("marker-layer", "marker-source") .withProperties( PF.iconImage("custom-marker"), // 使用自定义图标 PF.iconSize(1.0f) // 可选:设置图标锚点、偏移等属性 ) style.addLayer(markerLayer) // 4. 添加初始位置的标记点 val initialPoint = Point.fromLngLat(-122.4194, 37.7749) val initialFeature = Feature.fromGeometry(initialPoint) markerSymbolId = initialFeature.id markerSource.setGeoJson(FeatureCollection.fromFeatures(arrayOf(initialFeature))) } } private fun startMarkerAnimation(start: LatLng, end: LatLng, duration: Long) { val startPoint = Point.fromLngLat(start.longitude, start.latitude) val endPoint = Point.fromLngLat(end.longitude, end.latitude) ValueAnimator.ofFloat(0f, 1f).apply { this.duration = duration interpolator = AccelerateDecelerateInterpolator() // 先加速后减速的平滑效果 addUpdateListener { anim -> val progress = anim.animatedValue as Float // 插值计算当前帧的坐标 val currentLng = startPoint.longitude() + (endPoint.longitude() - startPoint.longitude()) * progress val currentLat = startPoint.latitude() + (endPoint.latitude() - startPoint.latitude()) * progress // 更新标记点位置 mapboxMap.getStyle { style -> val source = style.getSourceAs<GeoJsonSource>("marker-source") source?.let { val updatedFeature = Feature.fromGeometry(Point.fromLngLat(currentLng, currentLat)) updatedFeature.id = markerSymbolId it.setGeoJson(FeatureCollection.fromFeatures(arrayOf(updatedFeature))) } } } }.start() } // 必须实现MapView的生命周期方法 override fun onStart() { super.onStart() mapView.onStart() } override fun onResume() { super.onResume() mapView.onResume() } override fun onPause() { super.onPause() mapView.onPause() } override fun onStop() { super.onStop() mapView.onStop() } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) mapView.onSaveInstanceState(outState) } override fun onDestroy() { super.onDestroy() mapView.onDestroy() } override fun onLowMemory() { super.onLowMemory() mapView.onLowMemory() } }
关键说明
- 默认图标替代:如果不需要自定义图标,可将
PF.iconImage("custom-marker")替换为PF.iconImage("mapbox-marker-icon"),无需加载自定义图片。 - 插值器选择:可替换
AccelerateDecelerateInterpolator为LinearInterpolator实现匀速动画,或其他插值器满足不同动画曲线需求。 - 样式加载时机:所有操作需在地图样式加载完成后执行(即
getStyle回调内),避免空指针异常。
内容的提问来源于stack exchange,提问作者gsy
相关产品推荐
相关产品推荐

