Skip to main content
Icon layers display textures (images) at specific map coordinates with configurable scaling behavior. They support user interaction through click and long-press handlers.

Basic Setup

Create an icon layer and add icons using the IconFactory.
val iconLayer = IconLayerInterface.create()
val texture = BitmapTextureHolder(/* drawable or bitmap */)
val icon = IconFactory.createIcon(
    identifier = "Icon",
    coordinate = coordinate,
    texture = texture,
    iconSize = Vec2F(iconSize, iconSize),
    scaleType = IconType.INVARIANT,
    blendMode = BlendMode.NORMAL
)
iconLayer.add(icon)

mapView.addLayer(iconLayer.asLayerInterface())

Custom Anchor Point

Control where the icon is positioned relative to its coordinate using a custom anchor.
Android
val iconWithCustomAnchor = IconFactory.createIconWithAnchor(
    "Icon with a custom Anchor",
    coordinate = coordinate,
    texture = texture,
    iconSize = Vec2F(iconSize, iconSize),
    scaleType = IconType.INVARIANT,
    blendMode = BlendMode.NORMAL,
    iconAnchor = Vec2F(0.5f, 1.0f) // e.g. horizontally centered at the bottom
)
iconLayer.add(iconWithCustomAnchor)

Anchor Point Examples

  • Vec2F(0.5f, 0.5f) - Center of icon (default)
  • Vec2F(0.5f, 1.0f) - Bottom center (typical for map pins)
  • Vec2F(0.0f, 0.0f) - Top-left corner
  • Vec2F(1.0f, 1.0f) - Bottom-right corner

SwiftUI Integration

For SwiftUI apps, use UIViewRepresentable to manage icon layers.
iOS (SwiftUI)
struct MapWithIconView: UIViewRepresentable {
    @Binding var camera: MapView.Camera
    let coordinate: MCCoord
    let imageName: String
    
    func makeUIView(context: Context) -> MCMapView {
        let mapView = MCMapView()
        
        // Add base layer
        mapView.add(layer: TiledRasterLayer("osm", webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"))
        
        // Add icon layer
        let iconLayer = MCIconLayerInterface.create()
        let image = UIImage(named: imageName)
        let texture = try! TextureHolder(image!.cgImage!)
        let icon = MCIconFactory.createIcon(
            "icon",
            coordinate: coordinate,
            texture: texture,
            iconSize: .init(x: Float(texture.getImageWidth()), y: Float(texture.getImageHeight())),
            scale: .FIXED,
            blendMode: .NORMAL
        )
        iconLayer?.add(icon)
        mapView.add(layer: iconLayer?.asLayerInterface())
        
        // Set initial camera position
        if let center = camera.center.value, let zoom = camera.zoom.value {
            mapView.camera.move(toCenterPositionZoom: center, zoom: zoom, animated: false)
        }
        
        return mapView
    }
    
    func updateUIView(_ uiView: MCMapView, context: Context) {
        // Handle updates if needed
    }
}

struct ContentView: View {
    @State private var camera = MapView.Camera(
        latitude: 46.962592372639634,
        longitude: 8.378232525377973,
        zoom: 1000000
    )
    
    var body: some View {
        MapWithIconView(
            camera: $camera,
            coordinate: camera.center.value ?? MCCoord(lat: 46.962592372639634, lon: 8.378232525377973),
            imageName: "your-image-name"
        )
    }
}

Adding User Interaction

Enable click and long-press handling for icons.
iconLayer.setLayerClickable(true)
iconLayer.setCallbackHandler(object : IconLayerCallbackInterface(){
    override fun onClickConfirmed(icons: ArrayList<IconInfoInterface>): Boolean {
        // React to icon click
        icons.forEach { icon ->
            Log.d("Map", "Clicked icon: ${icon.getIdentifier()}")
        }
        return true // Return true if handled
    }

    override fun onLongPress(icons: ArrayList<IconInfoInterface>): Boolean {
        // React to long press
        icons.forEach { icon ->
            Log.d("Map", "Long pressed icon: ${icon.getIdentifier()}")
        }
        return true // Return true if handled
    }
})

Updating Icon Position

You can update the position of an icon dynamically using the setCoordinate method.
Android
val icon = IconFactory.createIcon(
    identifier = "movable-icon",
    coordinate = initialCoordinate,
    texture = texture,
    iconSize = Vec2F(iconSize, iconSize),
    scaleType = IconType.INVARIANT,
    blendMode = BlendMode.NORMAL
)
iconLayer.add(icon)

// Later, update the position
icon.setCoordinate(newCoordinate)

IconFactory Parameters

identifier
String
required
Unique identifier for the icon
coordinate
Coord
required
Map coordinate where the icon should be displayed
texture
TextureHolder
required
Image texture for the icon
iconSize
Vec2F
required
Size of the icon in pixels (width, height)
scaleType
IconType
required
How the icon scales with camera movement
blendMode
BlendMode
required
Blending mode for rendering the icon
iconAnchor
Vec2F
Anchor point in normalized coordinates (0.0 to 1.0). Defaults to center (0.5, 0.5)

Icon Scale Types

IconType.INVARIANT - Icon size remains constant regardless of zoom levelIconType.FIXED - Icon scales with the map

Blend Modes

  • BlendMode.NORMAL - Standard alpha blending
  • Additional blend modes may be available depending on the platform

Creating Textures

// From Drawable
val drawable = ContextCompat.getDrawable(context, R.drawable.marker)
val texture = BitmapTextureHolder(drawable)

// From Bitmap
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.marker)
val texture = BitmapTextureHolder(bitmap)

Example: Multiple Icons

Android
val iconLayer = IconLayerInterface.create()
val markerTexture = BitmapTextureHolder(ContextCompat.getDrawable(context, R.drawable.marker))

val locations = listOf(
    Pair("Location 1", Coord(CoordinateSystemIdentifiers.EPSG4326(), 8.378, 46.962, 0.0)),
    Pair("Location 2", Coord(CoordinateSystemIdentifiers.EPSG4326(), 8.540, 47.377, 0.0)),
    Pair("Location 3", Coord(CoordinateSystemIdentifiers.EPSG4326(), 7.447, 46.947, 0.0))
)

locations.forEach { (name, coord) ->
    val icon = IconFactory.createIconWithAnchor(
        identifier = name,
        coordinate = coord,
        texture = markerTexture,
        iconSize = Vec2F(48f, 48f),
        scaleType = IconType.INVARIANT,
        blendMode = BlendMode.NORMAL,
        iconAnchor = Vec2F(0.5f, 1.0f) // Bottom-center anchor for map pins
    )
    iconLayer.add(icon)
}

iconLayer.setLayerClickable(true)
iconLayer.setCallbackHandler(object : IconLayerCallbackInterface(){
    override fun onClickConfirmed(icons: ArrayList<IconInfoInterface>): Boolean {
        icons.forEach { icon ->
            Toast.makeText(context, "Clicked: ${icon.getIdentifier()}", Toast.LENGTH_SHORT).show()
        }
        return true
    }
})

mapView.addLayer(iconLayer.asLayerInterface())
Use IconType.INVARIANT for UI elements like markers that should maintain a consistent size on screen.

Build docs developers (and LLMs) love