Skip to content

Commit d1b3b76

Browse files
committed
Add marker colors and update Example03Markers
1 parent 2b83519 commit d1b3b76

3 files changed

Lines changed: 90 additions & 13 deletions

File tree

examples/Example03Markers/src/main/kotlin/de/afarber/openmapview/example03markers/MainActivity.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable
1818
import androidx.compose.ui.Modifier
1919
import androidx.compose.ui.platform.LocalContext
2020
import androidx.compose.ui.viewinterop.AndroidView
21+
import de.afarber.openmapview.BitmapDescriptorFactory
2122
import de.afarber.openmapview.LatLng
2223
import de.afarber.openmapview.Marker
2324
import de.afarber.openmapview.OpenMapView
@@ -53,12 +54,13 @@ fun MapViewScreen() {
5354
setCenter(LatLng(51.4661, 7.2491))
5455
setZoom(14.0)
5556

56-
// Add several markers around Bochum
57+
// Add several markers around Bochum with different colors
5758
addMarker(
5859
Marker(
5960
position = LatLng(51.4661, 7.2491),
6061
title = "Bochum City Center",
6162
snippet = "Welcome to Bochum!",
63+
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED),
6264
),
6365
)
6466

@@ -67,6 +69,7 @@ fun MapViewScreen() {
6769
position = LatLng(51.4700, 7.2550),
6870
title = "North Location",
6971
snippet = "A place north of center",
72+
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE),
7073
),
7174
)
7275

@@ -75,6 +78,7 @@ fun MapViewScreen() {
7578
position = LatLng(51.4620, 7.2430),
7679
title = "South Location",
7780
snippet = "A place south of center",
81+
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN),
7882
),
7983
)
8084

@@ -83,6 +87,7 @@ fun MapViewScreen() {
8387
position = LatLng(51.4680, 7.2380),
8488
title = "West Location",
8589
snippet = "A place west of center",
90+
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE),
8691
),
8792
)
8893

@@ -91,6 +96,7 @@ fun MapViewScreen() {
9196
position = LatLng(51.4640, 7.2600),
9297
title = "East Location",
9398
snippet = "A place east of center",
99+
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA),
94100
),
95101
)
96102

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2025 Alexander Farber
3+
* SPDX-License-Identifier: MIT
4+
*
5+
* This file is part of the OpenMapView project (https://github.com/afarber/OpenMapView)
6+
*/
7+
8+
package de.afarber.openmapview
9+
10+
import android.graphics.Bitmap
11+
12+
/**
13+
* Factory for creating marker icons, compatible with Google Maps API.
14+
*
15+
* Provides predefined color constants and methods to generate colored marker icons.
16+
* Colors are specified using HSV hue values (0-360 degrees on the color wheel).
17+
*/
18+
object BitmapDescriptorFactory {
19+
/**
20+
* HUE constants matching Google Maps BitmapDescriptorFactory.
21+
* Values represent degrees on the HSV color wheel.
22+
*/
23+
const val HUE_RED = 0f
24+
const val HUE_ORANGE = 30f
25+
const val HUE_YELLOW = 60f
26+
const val HUE_GREEN = 120f
27+
const val HUE_CYAN = 180f
28+
const val HUE_AZURE = 210f
29+
const val HUE_BLUE = 240f
30+
const val HUE_VIOLET = 270f
31+
const val HUE_MAGENTA = 300f
32+
const val HUE_ROSE = 330f
33+
34+
/**
35+
* Creates a marker icon with the specified hue.
36+
*
37+
* @param hue The hue value (0-360) on the color wheel. Defaults to red (0).
38+
* 0=red, 120=green, 240=blue, etc.
39+
* @return A bitmap of the colored marker icon
40+
*/
41+
fun defaultMarker(hue: Float = HUE_RED): Bitmap = MarkerIconFactory.getDefaultIcon(hue)
42+
}

openmapview/src/main/kotlin/de/afarber/openmapview/MarkerIconFactory.kt

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,64 @@ import android.graphics.Paint
1414
import android.graphics.Path
1515

1616
/**
17-
* Factory for creating default marker icons.
17+
* Factory for creating default marker icons with customizable colors.
1818
*/
1919
internal object MarkerIconFactory {
2020
private const val DEFAULT_WIDTH = 48
2121
private const val DEFAULT_HEIGHT = 72
22-
private var cachedDefaultIcon: Bitmap? = null
22+
private const val MAX_CACHE_SIZE = 10
23+
24+
// LRU cache for colored marker icons (hue -> bitmap)
25+
private val iconCache = LinkedHashMap<Float, Bitmap>(MAX_CACHE_SIZE + 1, 0.75f, true)
2326

2427
/**
25-
* Creates or returns a cached default marker icon.
26-
* The icon is a red teardrop shape with a white circle in the center.
28+
* Creates or returns a cached marker icon with the specified hue.
29+
*
30+
* @param hue The hue value (0-360) on the HSV color wheel. Defaults to 0 (red).
31+
* @return A bitmap of the colored marker icon
2732
*/
28-
fun getDefaultIcon(): Bitmap {
29-
cachedDefaultIcon?.let { return it }
33+
fun getDefaultIcon(hue: Float = 0f): Bitmap {
34+
// Normalize hue to 0-360 range
35+
val normalizedHue = hue % 360f
36+
37+
// Return cached icon if available
38+
iconCache[normalizedHue]?.let { return it }
39+
40+
// Create new icon
41+
val bitmap = createMarkerIcon(normalizedHue)
42+
43+
// Add to cache with LRU eviction
44+
if (iconCache.size >= MAX_CACHE_SIZE) {
45+
val firstKey = iconCache.keys.first()
46+
iconCache.remove(firstKey)?.recycle()
47+
}
48+
iconCache[normalizedHue] = bitmap
49+
50+
return bitmap
51+
}
3052

53+
/**
54+
* Creates a marker icon bitmap with the specified hue.
55+
*/
56+
private fun createMarkerIcon(hue: Float): Bitmap {
3157
val bitmap = Bitmap.createBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT, Bitmap.Config.ARGB_8888)
3258
val canvas = Canvas(bitmap)
3359

60+
// Convert HSV to RGB
61+
val mainColor = Color.HSVToColor(floatArrayOf(hue, 1.0f, 1.0f))
62+
val borderColor = Color.HSVToColor(floatArrayOf(hue, 1.0f, 0.6f)) // Darker border
63+
3464
val markerPaint =
3565
Paint().apply {
3666
style = Paint.Style.FILL
37-
color = Color.RED
67+
color = mainColor
3868
isAntiAlias = true
3969
}
4070

4171
val borderPaint =
4272
Paint().apply {
4373
style = Paint.Style.STROKE
44-
color = Color.parseColor("#8B0000") // Dark red
74+
color = borderColor
4575
strokeWidth = 3f
4676
isAntiAlias = true
4777
}
@@ -75,15 +105,14 @@ internal object MarkerIconFactory {
75105
// Draw white center circle
76106
canvas.drawCircle(centerX, circleRadius + 2f, circleRadius * 0.4f, centerPaint)
77107

78-
cachedDefaultIcon = bitmap
79108
return bitmap
80109
}
81110

82111
/**
83-
* Clears the cached default icon to free memory.
112+
* Clears all cached icons to free memory.
84113
*/
85114
fun clearCache() {
86-
cachedDefaultIcon?.recycle()
87-
cachedDefaultIcon = null
115+
iconCache.values.forEach { it.recycle() }
116+
iconCache.clear()
88117
}
89118
}

0 commit comments

Comments
 (0)