Skip to content

Both copy text to your clipboard — Build with AI copies a setup prompt to paste into Claude Code, Cursor, Codex or Copilot; Copy page as Markdown copies this page to paste into a chat. How it works

Display a Popup on Marker Click ​

This tutorial shows how to display custom popup windows when users tap on markers in your MapMetrics Android map.

Prerequisites ​

Basic Marker with Info Window ​

The simplest way to show a popup is using the built-in marker title and snippet:

kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.maplibre.android.MapMetrics
import org.maplibre.android.annotations.MarkerOptions
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.maps.MapView
import org.maplibre.android.maps.MapLibreMap
import org.maplibre.android.maps.Style

class PopupActivity : AppCompatActivity() {

    private lateinit var mapView: MapView
    private lateinit var map: MapLibreMap

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_map)

        mapView = findViewById(R.id.mapView)
        mapView.onCreate(savedInstanceState)
        mapView.getMapAsync { maplibreMap ->
            map = maplibreMap

            map.setStyle(
                Style.Builder().fromUri(
                    "https://gateway.mapmetrics-atlas.net/styles/YOUR_STYLE_ID?token=YOUR_API_KEY"
                )
            ) {
                // Add a marker with popup content
                map.addMarker(
                    MarkerOptions()
                        .position(LatLng(48.8584, 2.2945))
                        .title("Eiffel Tower")
                        .snippet("Paris, France — Built in 1889")
                )

                // Move camera to the marker
                map.cameraPosition = CameraPosition.Builder()
                    .target(LatLng(48.8584, 2.2945))
                    .zoom(14.0)
                    .build()
            }
        }
    }

    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 onDestroy() { super.onDestroy(); mapView.onDestroy() }
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mapView.onSaveInstanceState(outState)
    }
}

Multiple Markers with Popups ​

Add several markers with different popup content:

kotlin
map.setStyle(
    Style.Builder().fromUri(
        "https://gateway.mapmetrics-atlas.net/styles/YOUR_STYLE_ID?token=YOUR_API_KEY"
    )
) { style ->

    val places = listOf(
        Triple(LatLng(48.8584, 2.2945), "Eiffel Tower", "324m tall iron lattice tower"),
        Triple(LatLng(48.8606, 2.3376), "Louvre Museum", "World's largest art museum"),
        Triple(LatLng(48.8530, 2.3499), "Notre-Dame", "Medieval Catholic cathedral"),
        Triple(LatLng(48.8738, 2.2950), "Arc de Triomphe", "Honors those who fought for France"),
    )

    for ((position, title, description) in places) {
        map.addMarker(
            MarkerOptions()
                .position(position)
                .title(title)
                .snippet(description)
        )
    }

    // Fit camera to show all markers
    val bounds = org.maplibre.android.geometry.LatLngBounds.Builder()
    for ((position, _, _) in places) {
        bounds.include(position)
    }
    map.easeCamera(
        org.maplibre.android.camera.CameraUpdateFactory.newLatLngBounds(
            bounds.build(), 100
        ),
        1000
    )
}

Show a popup when the user taps anywhere on the map:

kotlin
map.setStyle(
    Style.Builder().fromUri(
        "https://gateway.mapmetrics-atlas.net/styles/YOUR_STYLE_ID?token=YOUR_API_KEY"
    )
) { style ->
    var currentMarker: org.maplibre.android.annotations.Marker? = null

    map.addOnMapClickListener { latLng ->
        // Remove previous marker
        currentMarker?.let { map.removeMarker(it) }

        // Add new marker with coordinates as popup
        currentMarker = map.addMarker(
            MarkerOptions()
                .position(latLng)
                .title("Tapped Location")
                .snippet(
                    "Lat: ${String.format("%.6f", latLng.latitude)}\n" +
                    "Lng: ${String.format("%.6f", latLng.longitude)}"
                )
        )

        // Show the info window immediately
        currentMarker?.showInfoWindow(map, mapView)

        true // consume the event
    }
}

Custom Info Window Adapter ​

Create a fully custom popup layout:

kotlin
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import org.maplibre.android.maps.MapLibreMap.InfoWindowAdapter

// Set custom adapter
map.setInfoWindowAdapter(object : InfoWindowAdapter {
    override fun getInfoWindow(marker: org.maplibre.android.annotations.Marker): View {
        val view = LayoutInflater.from(this@PopupActivity)
            .inflate(R.layout.custom_info_window, null)

        val title = view.findViewById<TextView>(R.id.info_title)
        val snippet = view.findViewById<TextView>(R.id.info_snippet)

        title.text = marker.title
        snippet.text = marker.snippet

        return view
    }
})

Custom layout XML (res/layout/custom_info_window.xml):

xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="12dp"
    android:background="@drawable/info_window_bg">

    <TextView
        android:id="@+id/info_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textStyle="bold"
        android:textColor="#333333" />

    <TextView
        android:id="@+id/info_snippet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        android:textColor="#666666"
        android:layout_marginTop="4dp" />

</LinearLayout>

Info Window Events ​

Listen for clicks on the info window popup:

kotlin
// Click on info window
map.setOnInfoWindowClickListener { marker ->
    // Navigate to detail screen, open URL, etc.
    Toast.makeText(
        this,
        "Clicked: ${marker.title}",
        Toast.LENGTH_SHORT
    ).show()
}

// Info window opens
map.setOnInfoWindowLongClickListener { marker ->
    Toast.makeText(
        this,
        "Long pressed: ${marker.title}",
        Toast.LENGTH_SHORT
    ).show()
}

// Info window closes
map.setOnInfoWindowCloseListener { marker ->
    // Cleanup or state updates
}

Next Steps ​


Tip: Info windows only support one open at a time — tapping a new marker automatically closes the previous popup. For multiple simultaneous popups, use a symbol layer with custom label text instead.