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

如何在Jetpack Compose中使用自定义Composable作为地图标记图标

在Jetpack Compose的Google Map中使用自定义Composable作为标记图标

要将自定义Composable转换为Google Map Marker所需的BitmapDescriptor,可以通过将Composable渲染到ComposeView并转换为Bitmap来实现,具体步骤如下:

1. 实现Composable转BitmapDescriptor的工具函数

创建工具函数负责将传入的Composable渲染为BitmapDescriptor:

import android.content.Context
import android.view.View
import android.view.View.MeasureSpec
import androidx.compose.runtime.Composable
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.platform.ComposeView
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory

@Composable
fun composableToBitmapDescriptor(
    context: Context,
    content: @Composable () -> Unit
): BitmapDescriptor {
    val composeView = ComposeView(context).apply {
        setContent {
            content()
        }
        // 测量并布局ComposeView,确保Composable正确绘制
        val widthSpec = MeasureSpec.makeMeasureSpec(
            LayoutNode.DefaultWidth, MeasureSpec.UNSPECIFIED
        )
        val heightSpec = MeasureSpec.makeMeasureSpec(
            LayoutNode.DefaultHeight, MeasureSpec.UNSPECIFIED
        )
        measure(widthSpec, heightSpec)
        layout(0, 0, measuredWidth, measuredHeight)
    }
    val bitmap = composeView.drawToBitmap()
    return BitmapDescriptorFactory.fromBitmap(bitmap)
}

2. 在Google Map中使用自定义Marker

自定义Marker Composable(你的原有代码)

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

@Composable
fun CustomMarker() {
    Box(
        modifier = Modifier
            .size(width = 85.dp, height = 40.dp)
    ) {
        Box(
            modifier = Modifier
                .size(40.dp)
                .rotate(45f)
                .clip(RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp, bottomStart = 20.dp))
                .border(
                    2.dp,
                    color = Color.White,
                    shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp, bottomStart = 20.dp)
                )
                .background(
                    brush = Brush.verticalGradient(
                        listOf(
                            Color(0xff11A5CF),
                            Color(0xff04CFBB)
                        )
                    )
                ),
            contentAlignment = Alignment.Center
        )
    }
}

修改后的Google Map代码

import android.util.Log
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.ui.platform.LocalContext
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.Marker
import com.google.maps.android.compose.MarkerState
import com.google.maps.android.compose.rememberCameraPositionState

@Composable
fun MapScreen() {
    val latLongList by remember {
        mutableStateOf(
            listOf(
                LatLng(23.091579064649835,72.53389410674572),
                LatLng(22.32911404585704, 70.79109091311693),
                LatLng(24.5791114644088, 72.69674610346556),
                LatLng(22.356990318569245, 73.18480521440506),
                LatLng(21.155952265072994, 72.84413181245327)
            )
        )
    }
    var index by remember { mutableIntStateOf(0) }
    val cameraState = rememberCameraPositionState {
        position = CameraPosition(latLongList[index], 15f, 0f, 0f)
    }
    val context = LocalContext.current

    GoogleMap(
        modifier = Modifier.fillMaxSize(),
        onMapClick = { latLng ->
            Log.d("location", "${latLng.latitude} and ${latLng.longitude}")
        },
        cameraPositionState = cameraState
    ) {
        latLongList.forEachIndexed { _, latLng ->
            val markerState = rememberMarkerState(position = latLng)
            // 缓存图标,避免重复生成提升性能
            val markerIcon by remember {
                derivedStateOf {
                    composableToBitmapDescriptor(context) {
                        CustomMarker()
                    }
                }
            }
            Marker(
                state = markerState,
                icon = markerIcon
            )
        }
    }
}

注意事项

  • 使用remember和derivedStateOf缓存生成的BitmapDescriptor,避免每次重组重新渲染Composable
  • 确保自定义Marker的尺寸固定,避免测量异常
  • 若项目未包含相关依赖,需确保添加androidx.compose.ui:ui-viewbinding(通常已包含在Compose核心依赖中)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:52:18