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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 03:50:38