如何在Jetpack Compose中创建带自定义文本的Google Maps自定义标记图标
在Jetpack Compose中为Marker组件创建带自定义文本的标记图标
核心思路
普通Marker组件仅支持BitmapDescriptor类型的图标,因此我们需要将基础标记图标与自定义文本合成一张Bitmap,再转换为BitmapDescriptor,以此替代AdvancedMarker的pinConfig实现相同视觉效果,同时保证流畅性。
具体实现步骤
1. 编写BitmapDescriptor生成工具函数
创建工具函数,负责将基础图标与文本合成目标Bitmap,并转换为BitmapDescriptor:
import android.content.Context import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.drawable.Drawable import androidx.core.content.ContextCompat import com.google.android.gms.maps.model.BitmapDescriptor import com.google.android.gms.maps.model.BitmapDescriptorFactory fun createCustomMarkerWithText( context: Context, baseMarkerResId: Int, // 基础标记图标的资源ID text: String, textSize: Float = 24f, textColor: Int = Color.WHITE, textBackgroundColor: Int = Color.RED ): BitmapDescriptor { // 加载基础标记图标 val baseDrawable: Drawable? = ContextCompat.getDrawable(context, baseMarkerResId) ?: throw IllegalArgumentException("无效的图标资源ID") // 创建Bitmap画布 val bitmap = Bitmap.createBitmap( baseDrawable.intrinsicWidth, baseDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888 ) val canvas = Canvas(bitmap) baseDrawable.setBounds(0, 0, canvas.width, canvas.height) baseDrawable.draw(canvas) // 配置文本画笔 val textPaint = Paint().apply { color = textColor textSize = textSize isAntiAlias = true textAlign = Paint.Align.CENTER isFakeBoldText = true } // 计算文本居中位置 val xPos = canvas.width / 2f val yPos = canvas.height / 2f - (textPaint.descent() + textPaint.ascent()) / 2f // 绘制文本背景(可选) val textBounds = android.graphics.Rect() textPaint.getTextBounds(text, 0, text.length, textBounds) val bgPaint = Paint().apply { color = textBackgroundColor isAntiAlias = true } val bgRadius = maxOf(textBounds.width(), textBounds.height()) / 2f + 8f canvas.drawCircle(xPos, yPos, bgRadius, bgPaint) // 绘制文本 canvas.drawText(text, xPos, yPos, textPaint) // 转换为Marker所需的BitmapDescriptor return BitmapDescriptorFactory.fromBitmap(bitmap) }
2. 在Compose地图中使用Marker组件
在地图Composable中调用工具函数生成图标,传入Marker的icon参数:
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier 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 CustomMarkerMap() { val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(LatLng(39.9042, 116.4074), 12f) } val context = LocalContext.current GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { // 带自定义文本的红色标记 val customMarkerIcon = createCustomMarkerWithText( context = context, baseMarkerResId = R.drawable.ic_red_marker, // 替换为你的基础标记图标 text = "22222", textSize = 22f ) Marker( state = MarkerState(position = LatLng(39.9042, 116.4074)), icon = customMarkerIcon, title = "hello", snippet = "World" ) // 巴士内置图标标记 Marker( state = MarkerState(position = LatLng(39.91, 116.41)), icon = BitmapDescriptorFactory.fromResource(R.drawable.ic_bus), // 替换为地图内置巴士图标资源 title = "巴士站点" ) } }
3. 性能优化建议
- 缓存BitmapDescriptor:若多个标记使用相同样式,缓存生成的
BitmapDescriptor,避免重复创建Bitmap。 - 适配屏幕密度:根据设备屏幕密度调整文本大小和图标尺寸,保证跨设备显示一致。
- 复用绘图对象:在工具函数中复用
Paint对象,减少内存开销。
内容的提问来源于stack exchange,提问作者Pawandeep Singh
相关产品推荐
相关产品推荐

