Google Map

Add a Marker

A map by itself is useful for exploring, but what if you want to tell the user where something is?

That's where markers come in, and where the GoogleMap content parameter becomes useful.

Our GoogleMap call is going to get more complex over the next several steps. By Creating a new @Composable to hold the map, we can set up parameters

show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
// ...
import com.google.maps.android.compose.rememberMarkerState

@Composable
fun GoogleMapDisplay(
    place: LatLng,
    placeDescription: String,
    modifier: Modifier,
) {
    val placeState =
        rememberMarkerState(key = place.toString(), position = place)

    GoogleMap(
        modifier = modifier,
    ) {
        MarkerInfoWindowContent(
            state = placeState,
            title = placeDescription,
            onClick = {
                placeState.showInfoWindow()
                true
            }
        )
    }
}

and Simplify the Caller (passing in a place)

show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/MainActivity.kt
// ...
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        setContent {
            GoogleMapsTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
//                  GoogleMap(
                    val googleHQ = LatLng(37.42423291057923, -122.08811454627153)

                    GoogleMapDisplay(
                        place = googleHQ,
                        placeDescription = "Google HQ",
                        modifier = Modifier.padding(innerPadding).fillMaxSize(),
//                  ) {
//                      // no content yet
//                  }
                    )
                }
            }
        }
    }
}

Our new @Composable takes a LatLng for the place to display the marker, a String description of the marker, and a Modifier. It's a great habit to pass Modifiers into your Composable functions; this allows the caller more control over how the called Composable is placed. You'll want to Pass the Modifier}} to the top-level Composable that your function calls, or use it as a base modifier (rather than passing Modifier.xxx(), you'll pass modifier.xxx() to start with the passed-in Modifier).

show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
// ...

@Composable
fun GoogleMapDisplay(
    // ...
) {
    // ...

    GoogleMap(
        modifier = modifier,
    ) {
        MarkerInfoWindowContent(
            // ...
    }
}

Now for the marker. We need to set up the data for the Marker - we use rememberMarkerState to create and remember a MarkerState instance. This instance will be re-created whenever the key passed to it is changed. In this example, we want to change the position whenever the LatLng changes. rememberMarkerState takes a String as a key, so we just convert the LatLng to a String.

Once we have data, we can Create the Marker in the GoogleMap content.

show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
// ...

@Composable
fun GoogleMapDisplay(
    // ...
    modifier: Modifier,
) {
    val placeState =
        rememberMarkerState(key = place.toString(), position = place)

    GoogleMap(
        modifier = modifier,
    ) {
        MarkerInfoWindowContent(
            state = placeState,
            title = placeDescription,
            onClick = {
                placeState.showInfoWindow()
                true
            }
        )
    }
}

Running the application is a bit disappointing; we're still centered at 0.0, 0.0. If we pan over we'll see the marker:

We have a Marker!

You can zoom by double-tapping, pinching, or tapping the "+" button to see

Zooming in

If you tap on the marker, its description is displayed and the map centers on the marker:

Marker Description


All code changes

ADDED: app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
package com.androidbyexample.compose.google.google.maps

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.MarkerInfoWindowContent
import com.google.maps.android.compose.rememberMarkerState

@Composable fun GoogleMapDisplay( place: LatLng, placeDescription: String, modifier: Modifier, ) {
val placeState = rememberMarkerState(key = place.toString(), position = place)
GoogleMap(
modifier = modifier,
) {
MarkerInfoWindowContent( state = placeState, title = placeDescription, onClick = { placeState.showInfoWindow() true } )
} }
CHANGED: app/src/main/java/com/androidbyexample/compose/google/google/maps/MainActivity.kt
package com.androidbyexample.compose.google.google.maps

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.androidbyexample.compose.google.google.maps.ui.theme.GoogleMapsTheme
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.GoogleMap

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            GoogleMapsTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
// GoogleMap( val googleHQ = LatLng(37.42423291057923, -122.08811454627153) GoogleMapDisplay( place = googleHQ, placeDescription = "Google HQ", modifier = Modifier.padding(innerPadding).fillMaxSize(), // ) { // // no content yet // } )
} } } } }