Skip to content

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.MapMetricsMap
import org.maplibre.android.maps.Style

class PopupActivity : AppCompatActivity() {

    private lateinit var mapView: MapView
    private lateinit var map: MapMetricsMap

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

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

            map.setStyle(
                Style.Builder().fromUri(
                    "https://gateway.mapmetrics.org/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.org/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.org/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.MapMetricsMap.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.