Skip to content

Commit 2d6fe6a

Browse files
pjleonard37github-actions[bot]
authored andcommitted
Add custom vector icons examples for iOS and Android (#8285)
Ports the custom colorized vector icons from GL JS to iOS (SwiftUI) and Android (Jetpack Compose). Additionally, moves the functionality from the Icon Size Change examples into these new examples and removes the old examples. GitOrigin-RevId: b92c8c82cc24c5029b212e91db70518342cc260d
1 parent 42e85bc commit 2d6fe6a

File tree

7 files changed

+141
-177
lines changed

7 files changed

+141
-177
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -750,18 +750,6 @@
750750
android:name="android.support.PARENT_ACTIVITY"
751751
android:value=".ExampleOverviewActivity" />
752752
</activity>
753-
<activity
754-
android:name=".examples.markersandcallouts.IconSizeChangeOnClickActivity"
755-
android:description="@string/description_change_icon_size"
756-
android:exported="true"
757-
android:label="@string/activity_style_change_icon_size_title">
758-
<meta-data
759-
android:name="@string/category"
760-
android:value="@string/category_markers_and_callouts" />
761-
<meta-data
762-
android:name="android.support.PARENT_ACTIVITY"
763-
android:value=".ExampleOverviewActivity" />
764-
</activity>
765753
<activity
766754
android:name=".examples.markersandcallouts.AddMarkersSymbolActivity"
767755
android:description="@string/description_add_marker_symbol"

app/src/main/java/com/mapbox/maps/testapp/examples/markersandcallouts/IconSizeChangeOnClickActivity.kt

Lines changed: 0 additions & 155 deletions
This file was deleted.

app/src/main/res/layout/activity_icon_size_change_on_click.xml

Lines changed: 0 additions & 10 deletions
This file was deleted.

compose-app/src/main/AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@
9898
android:name="@string/category"
9999
android:value="@string/category_annotation" />
100100
</activity>
101+
<activity
102+
android:name=".examples.annotation.CustomVectorIconsActivity"
103+
android:description="@string/description_custom_vector_icons"
104+
android:exported="true"
105+
android:label="@string/activity_custom_vector_icons"
106+
android:parentActivityName=".ExampleOverviewActivity">
107+
<meta-data
108+
android:name="@string/category"
109+
android:value="@string/category_annotation" />
110+
</activity>
101111
<activity
102112
android:name=".examples.annotation.ViewAnnotationActivity"
103113
android:configChanges="orientation|screenSize|screenLayout"
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.mapbox.maps.compose.testapp.examples.annotation
2+
3+
import android.os.Bundle
4+
import androidx.activity.ComponentActivity
5+
import androidx.activity.compose.setContent
6+
import androidx.compose.foundation.layout.fillMaxSize
7+
import androidx.compose.runtime.getValue
8+
import androidx.compose.runtime.mutableStateOf
9+
import androidx.compose.runtime.remember
10+
import androidx.compose.runtime.setValue
11+
import androidx.compose.ui.Modifier
12+
import com.mapbox.geojson.Feature
13+
import com.mapbox.geojson.Point
14+
import com.mapbox.maps.MapboxDelicateApi
15+
import com.mapbox.maps.MapboxExperimental
16+
import com.mapbox.maps.compose.testapp.ExampleScaffold
17+
import com.mapbox.maps.compose.testapp.ui.theme.MapboxMapComposeTheme
18+
import com.mapbox.maps.extension.compose.MapboxMap
19+
import com.mapbox.maps.extension.compose.animation.viewport.rememberMapViewportState
20+
import com.mapbox.maps.extension.compose.style.BooleanValue
21+
import com.mapbox.maps.extension.compose.style.DoubleValue
22+
import com.mapbox.maps.extension.compose.style.MapStyle
23+
import com.mapbox.maps.extension.compose.style.layers.ImageValue
24+
import com.mapbox.maps.extension.compose.style.layers.generated.SymbolLayer
25+
import com.mapbox.maps.extension.compose.style.sources.GeoJSONData
26+
import com.mapbox.maps.extension.compose.style.sources.generated.rememberGeoJsonSourceState
27+
import com.mapbox.maps.extension.style.expressions.dsl.generated.image
28+
import com.mapbox.maps.extension.style.expressions.dsl.generated.switchCase
29+
import com.mapbox.maps.extension.style.expressions.generated.Expression
30+
31+
/**
32+
* Example demonstrating custom vector icons with dynamic styling and interaction.
33+
* This example shows how to:
34+
* - Dynamically colorize vector icons based on feature properties using the image expression
35+
* - Interactively change icon size by tapping on icons
36+
*
37+
* Vector icons are parameterized SVG images that can be styled at runtime. In this example,
38+
* three flag icons are colored red, yellow, and purple using the 'flagColor' property.
39+
* Tap any flag to toggle its size between 1x and 2x.
40+
*
41+
* For this example to work, the SVGs must live inside the map style. The SVG file was uploaded
42+
* to Mapbox Studio with the name `flag`, making it available for customization at runtime.
43+
* You can add vector icons to your own style in Mapbox Studio.
44+
*/
45+
@OptIn(MapboxDelicateApi::class, MapboxExperimental::class)
46+
public class CustomVectorIconsActivity : ComponentActivity() {
47+
override fun onCreate(savedInstanceState: Bundle?) {
48+
super.onCreate(savedInstanceState)
49+
setContent {
50+
var selectedFlagId by remember { mutableStateOf<String?>(null) }
51+
52+
// Create GeoJSON source with three flag locations
53+
val geoJsonSource = rememberGeoJsonSourceState {
54+
generateId = BooleanValue(true)
55+
}
56+
geoJsonSource.data = GeoJSONData(createFlagFeatures())
57+
58+
val mapViewportState = rememberMapViewportState {
59+
setCameraOptions {
60+
zoom(16.0)
61+
center(Point.fromLngLat(24.6881, 60.185755))
62+
}
63+
}
64+
65+
MapboxMapComposeTheme {
66+
ExampleScaffold {
67+
MapboxMap(
68+
Modifier.fillMaxSize(),
69+
mapViewportState = mapViewportState,
70+
style = {
71+
MapStyle(style = "mapbox://styles/mapbox-map-design/cm4r19bcm00ao01qvhp3jc2gi")
72+
}
73+
) {
74+
// Create symbol layer with parameterized icon
75+
SymbolLayer(
76+
sourceState = geoJsonSource,
77+
layerId = "points"
78+
) {
79+
interactionsState.onClicked { feature, _ ->
80+
feature.properties.optString("id").takeIf { it.isNotEmpty() }?.let { id ->
81+
selectedFlagId = if (selectedFlagId == id) null else id
82+
}
83+
true
84+
}
85+
iconImage = ImageValue(
86+
image {
87+
literal("flag")
88+
imageOptions("flag_color" to Expression.get("flagColor"))
89+
}
90+
)
91+
iconSize = DoubleValue(
92+
switchCase {
93+
eq {
94+
get { literal("id") }
95+
literal(selectedFlagId ?: "")
96+
}
97+
literal(2.0)
98+
literal(1.0)
99+
}
100+
)
101+
iconAllowOverlap = BooleanValue(true)
102+
}
103+
}
104+
}
105+
}
106+
}
107+
}
108+
109+
/**
110+
* Creates GeoJSON features with flag locations and colors.
111+
*/
112+
private fun createFlagFeatures(): List<Feature> {
113+
return listOf(
114+
createFlagFeature("flag-red", 24.68727, 60.185755, "red"),
115+
createFlagFeature("flag-yellow", 24.68827, 60.186255, "yellow"),
116+
createFlagFeature("flag-purple", 24.68927, 60.186055, "#800080")
117+
)
118+
}
119+
120+
/**
121+
* Creates a feature with a flag at the specified location and color.
122+
*/
123+
private fun createFlagFeature(id: String, longitude: Double, latitude: Double, color: String): Feature {
124+
val feature = Feature.fromGeometry(Point.fromLngLat(longitude, latitude))
125+
feature.addStringProperty("id", id)
126+
feature.addStringProperty("flagColor", color)
127+
return feature
128+
}
129+
}

compose-app/src/main/res/values/example_descriptions.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<string name="description_clip_layer">Showcase the usage of clip layer.</string>
3030
<string name="description_interactions">Showcase the interactions.</string>
3131
<string name="description_appearances">Change icon images dynamically using the Appearances API with feature-state</string>
32+
<string name="description_custom_vector_icons">Dynamically style vector icons with custom colors and interactively change their size on tap</string>
3233
<string name="description_precipitations">Showcase the rain and snow effects.</string>
3334
<string name="description_color_theme">Showcase color theme.</string>
3435
<string name="description_elevated_line">Showcase line elevation</string>

compose-app/src/main/res/values/example_titles.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<string name="activity_clip_layer">Clip layer example</string>
3030
<string name="activity_interactions">Interactions example</string>
3131
<string name="activity_appearances">Appearances</string>
32+
<string name="activity_custom_vector_icons">Custom Vector Icons</string>
3233
<string name="activity_precipitations">Precipitations example</string>
3334
<string name="activity_color_theme">Color theme example</string>
3435
<string name="activity_elevated_line">Elevated line example</string>

0 commit comments

Comments
 (0)