Search code examples
androidkotlinandroid-jetpack-compose

How to create custom Google Maps marker icon in compose


How can I create a custom marker icon with custom text like this in compose?

Currently, I am creating this icon using pin config in advanced marker, but it causes lag, using pin config in advanced marker is not as smooth as normal marker.

Note: Bus Icon is built in map

enter image description here

Red Marker with 22222 text is created using

AdvancedMarker(
    state = markerState,
    pinConfig = marker.pinConfig,
    title = "hello",
    snippet = "World",
    alpha = alpha,
   
)

I want to use this marker where I can provide the above icon to this marker function

Marker(
    state = markerState,
    icon = 
)

I can not use the pin config in Marker(). it requires BitmapDescriptor


Solution

  • To create a marker as you have shown in the image you need to follow these steps.

    Step 1. Create a Custom Marker Composable

    @Composable
    fun CustomMarkerView(text: String) {
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .size(100.dp)
                .background(Color.Red, shape = RoundedCornerShape(50.dp))
                .border(2.dp, Color.Black, shape = RoundedCornerShape(50.dp))
        ) {
            Text(text, color = Color.White, fontSize = 16.sp)
        }
    }
    

    Step 2. Convert Composable to Bitmap

    fun createMarkerBitmap(context: Context, text: String): Bitmap {
        // Create an empty Bitmap with a specific width, height, and config
        val bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)  // Initialize a Canvas to draw on the bitmap
    
        // Get the device screen density (to scale things correctly)
        val density = context.resources.displayMetrics.density
    
        // Create a ComposeView that will render the composable into a view
        val composeView = ComposeView(context).apply {
            setContent {
                // Render the custom marker composable inside this ComposeView
                CustomMarkerView(text = text)
            }
        }
    
        // Measure and layout the ComposeView to be rendered correctly
        composeView.measure(
            View.MeasureSpec.makeMeasureSpec((100 * density).toInt(), View.MeasureSpec.EXACTLY),
            View.MeasureSpec.makeMeasureSpec((100 * density).toInt(), View.MeasureSpec.EXACTLY)
        )
        composeView.layout(0, 0, composeView.measuredWidth, composeView.measuredHeight)
    
        // Finally, draw the ComposeView on the Canvas (which is linked to the Bitmap)
        composeView.draw(canvas)
    
        return bitmap  // Return the resulting Bitmap with the custom composable drawn
    }
    
    

    Step 3. Use BitmapDescriptor in Google Maps Marker

    
    val customMarkerBitmap = createMarkerBitmap(context, "22222")  // Create the bitmap with the desired text
    val markerOptions = MarkerOptions()
        .position(LatLng(0.0, 0.0))  // Set the position of the marker
        .icon(BitmapDescriptorFactory.fromBitmap(customMarkerBitmap))  // Use the generated Bitmap as the icon
    googleMap.addMarker(markerOptions)  // Add the marker to the GoogleMap instance
    
    

    How It Works: Custom Marker Design: The CustomMarkerView composable defines how to draw the marker. In this case, it is a red circle with a black border and centered text.

    Composable to Bitmap: The function is createMarkerBitmap. It takes this composable and renders it into a Bitmap. To do this, it uses a Canvas that it draws it onto the Bitmap after first rendering it inside a ComposeView.

    Google Maps Marker: Next, this bitmap was converted into a BitmapDescriptor, so that it could be used as the marker icon in Google Maps with the MarkerOptions.

    I think this method is more efficient than using the AdvancedMarker and avoids the lag you are experiencing.