MapBox Android版开发 3 地图样式v11
- 前言
- MapBox样式对比
- 主要类和方法
- Style类
- Style类
- 默认的MapBox样式
- OnStyleLoaded 接口
- MapboxMap类
- 获取样式
- 设置样式
- 本地化扩展
- 示例代码
- 地图样式类
- 界面布局
- 控件响应事件
- 运行效果图
- 附不同样式中的图层
前言
可以使用Mapbox Maps SDK自定义数据样式、调整地图样式、添加字体、创建数据驱动的可视化等。可以使用Mapbox Standard
、Mapbox Standard Satellite
,或通过调整地图的颜色、图标和字体来创建自定义地图样式。
有两种方法可以自定义地图的外观:
- 使用Mapbox Studio创建自定义地图样式。
- 使用Maps SDK在运行时动态更新地图功能。并可以动态切换语言,调整标签大小以提高可读性,根据一天中的时间调暗地图,个性化图标和地图颜色。
本文重点介绍MapBox默认的样式,样式相关的类和方法,以及如何动态更新样式并本地化语言。
MapBox样式对比
风格 | 常量 | 说明 | v9 | v11 |
---|---|---|---|---|
Mapbox Standard | STANDARD | A dynamic and performant 3D style that is the default for Mapbox maps. | - | standard |
Mapbox Standard Satellite | STANDARD_SATELLITE | Combines updated satellite imagery and vector layers to offer users improved clarity and detail. | - | standard-satellite |
Mapbox Streets | MAPBOX_STREETS | A complete base map, perfect for incorporating your own data. | streets-v11 | streets-v12 |
Outdoors | OUTDOORS | A general-purpose style tailored to outdoor activities. | outdoors-v11 | outdoors-v12 |
Light | LIGHT | Subtle light backdrop for data visualizations. | light-v10 | light-v11 |
Dark | DARK | Subtle dark backdrop for data visualizations. | dark-v10 | dark-v11 |
Satellite | SATELLITE | A beautiful global satellite and aerial imagery layer. | satellite-v9 | satellite-v9 |
Satellite Streets | SATELLITE_STREETS | Global satellite and aerial imagery with unobtrusive labels. | satellite-streets-v11 | satellite-streets-v12 |
Traffic Day | TRAFFIC_DAY | Color-coded roads based on live traffic congestion data. | traffic-day-v2 | traffic-day-v2 |
Traffic Night | TRAFFIC_NIGHT | Color-coded roads based on live traffic congestion data, designed to maximize legibility in low-light situations. | traffic-night-v2 | traffic-night-v2 |
主要类和方法
Style类
Style
对象是指应用程序中使用的Mapbox地图样式。
Style类
class Style internal constructor(
styleManager: StyleManager,
pixelRatio: Float,
mapLoadingErrorDelegate: MapLoadingErrorDelegate,
) : MapboxStyleManager(styleManager, pixelRatio, mapLoadingErrorDelegate) {
@Volatile
private var isStyleValid = true
/**
* Returns the existing style layers.
*
* @return The list containing the ids of the existing style layers.
*/
override val styleLayers: List<StyleObjectInfo>
@MainThread
get() {
checkNativeStyle("getStyleLayers")
return super.styleLayers
}
...
}
- MapboxStyleManager 类
open class MapboxStyleManager @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) constructor(
/**
* Native style manager instance.
*/
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
val styleManager: StyleManager,
/**
* Current pixel ratio.
*/
val pixelRatio: Float,
/**
* For internal usage.
*/
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
val mapLoadingErrorDelegate: MapLoadingErrorDelegate,
) {
}
...
}
- StyleManager 类
public class StyleManager extends Observable {
@MainThread
public native boolean isStyleLoaded();
@MainThread
public native boolean styleLayerExists(@NonNull String layerId);
@NonNull
@MainThread
public native List<StyleObjectInfo> getStyleLayers();
...
}
默认的MapBox样式
const val STANDARD = "mapbox://styles/mapbox/standard"
const val STANDARD_SATELLITE = "mapbox://styles/mapbox/standard-satellite"
const val MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v12"
const val OUTDOORS = "mapbox://styles/mapbox/outdoors-v12"
const val LIGHT = "mapbox://styles/mapbox/light-v11"
const val DARK = "mapbox://styles/mapbox/dark-v11"
const val SATELLITE = "mapbox://styles/mapbox/satellite-v9"
const val SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-streets-v12"
const val TRAFFIC_DAY = "mapbox://styles/mapbox/traffic-day-v2"
const val TRAFFIC_NIGHT = "mapbox://styles/mapbox/traffic-night-v2"
OnStyleLoaded 接口
/**
* Callback to be invoked when a style has finished loading.
*/
fun interface OnStyleLoaded {
/**
* Invoked when a style has finished loading.
*
* @param style the style that has finished loading
*/
fun onStyleLoaded(style: Style)
}
MapboxMap类
获取样式
var style: Style? = null
@JvmSynthetic
internal set
get() {
checkNativeMap("getStyle")
return field
}
设置样式
@JvmOverloads
fun loadStyle(
style: String,
onStyleLoaded: Style.OnStyleLoaded? = null,
) {
checkNativeMap("loadStyle")
initializeStyleLoad(
onStyleLoaded,
styleDataStyleLoadedListener = {},
)
applyStyle(style)
}
private fun applyStyle(style: String) {
if (style.isValidUri()) {
nativeMap.setStyleURI(style)
} else {
nativeMap.setStyleJSON(style.ifBlank { "{}" })
}
}
本地化扩展
com.mapbox.maps.extension.localization
包中实现了本地化功能,这种方法不支持standard
样式。主要实现代码如下:
@JvmOverloads
fun MapboxStyleManager.localizeLabels(locale: Locale, layerIds: List<String>? = null) {
if (styleURI == "mapbox://styles/mapbox/standard") {
throw RuntimeException(
"Mapbox Standard style does not support client-side runtime localization." +
" Consider using Mapbox internationalization capability instead: https://www.mapbox.com/blog/maps-internationalization-34-languages"
)
}
setMapLanguage(locale, this, layerIds)
}
internal fun setMapLanguage(locale: Locale, style: MapboxStyleManager, layerIds: List<String>?) {
val convertedLocale = "name_${locale.language}"
if (!isSupportedLanguage(convertedLocale)) {
logE(TAG, "Locale: $locale is not supported.")
return
}
layerIds?.forEach { id ->
localizeTextFieldExpression(
style = style,
layerId = id,
locale = locale,
convertedLocale = convertedLocale,
filterSymbolLayers = true,
)
} ?: style.styleLayers.forEach { layer ->
if (layer.type == SYMBOL) {
localizeTextFieldExpression(
style = style,
layerId = layer.id,
locale = locale,
convertedLocale = convertedLocale,
filterSymbolLayers = false,
)
}
}
}
private fun localizeTextFieldExpression(
style: MapboxStyleManager,
layerId: String,
locale: Locale,
convertedLocale: String,
filterSymbolLayers: Boolean,
) {
if (filterSymbolLayers) {
val type = style.getStyleLayerProperty(layerId, TYPE).value.contents as? String
if (type != SYMBOL) {
return
}
}
val textFieldProperty = style.getStyleLayerProperty(layerId, TEXT_FIELD)
if (textFieldProperty.kind != StylePropertyValueKind.EXPRESSION) {
return
}
val textField = textFieldProperty.value.toJson()
val adaptedLocale = adaptLocaleToV8orV7IfNeeded(
style,
style.getStyleLayerProperty(layerId, SOURCE).value.contents as? String ?: "",
locale
) ?: convertedLocale
val getExpression = get(adaptedLocale).toJson()
val localizedTextFieldExpressionAsJson = textField.replace(
EXPRESSION_REGEX,
getExpression
).replace(EXPRESSION_ABBR_REGEX, getExpression)
if (BuildConfig.DEBUG) {
logI(TAG, "Localize layer with expression: $localizedTextFieldExpressionAsJson")
}
val expected = Value.fromJson(localizedTextFieldExpressionAsJson)
expected.value?.let { value ->
style.setStyleLayerProperty(
layerId,
TEXT_FIELD,
value
)
} ?: run {
logE(TAG, "An error ${expected.error} occurred when converting $localizedTextFieldExpressionAsJson to a Value!")
}
}
示例代码
地图样式类
设置地图样式,样式加载完成后重新本地化地图语言。
package com.example.mapdemo
import com.mapbox.maps.MapboxMap
import com.mapbox.maps.Style
import com.mapbox.maps.extension.localization.localizeLabels
import java.util.Locale
class MapStyle(map: MapboxMap) {
private var map = map
fun changeStyle(style: String) {
map.loadStyle(style) {
var layers = it.styleLayers
if (style != Style.STANDARD && style != Style.STANDARD_SATELLITE) {
it.localizeLabels(Locale.CHINESE)
}
}
}
}
界面布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.mapbox.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottomView"
app:layout_constraintTop_toTopOf="parent"
app:mapbox_cameraBearing="0.0"
app:mapbox_cameraPitch="0.0"
app:mapbox_cameraTargetLat="32.2857965"
app:mapbox_cameraTargetLng="104.293174"
app:mapbox_cameraZoom="2" />
<HorizontalScrollView
android:id="@+id/bottomView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/background_dark"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/mapView">
<RadioGroup
android:id="@+id/RadioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingHorizontal="10dp">
<RadioButton
android:id="@+id/standard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:onClick="setMapStyle"
android:text="3D基础"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/standardSatellite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="setMapStyle"
android:text="3D影像"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/streets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:onClick="setMapStyle"
android:text="基础"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/satellite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="setMapStyle"
android:text="影像"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/satelliteStreets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="setMapStyle"
android:text="影像标签"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/outdoors"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="setMapStyle"
android:text="户外"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/light"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:onClick="setMapStyle"
android:text="浅"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/dark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:onClick="setMapStyle"
android:text="深"
android:textColor="@color/white"
android:textStyle="bold" />
</RadioGroup>
</HorizontalScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
控件响应事件
fun setMapStyle(view: View) {
val checked = (view as RadioButton).isChecked
if (!checked)
return
val id = view.getId()
if (id == R.id.standard) {
mapStyle.changeStyle(Style.STANDARD)
} else if (id == R.id.standardSatellite) {
mapStyle.changeStyle(Style.STANDARD_SATELLITE)
} else if (id == R.id.streets) {
mapStyle.changeStyle(Style.MAPBOX_STREETS)
} else if (id == R.id.satellite) {
mapStyle.changeStyle(Style.SATELLITE)
} else if (id == R.id.satelliteStreets) {
mapStyle.changeStyle(Style.SATELLITE_STREETS)
} else if (id == R.id.outdoors) {
mapStyle.changeStyle(Style.OUTDOORS)
} else if (id == R.id.light) {
mapStyle.changeStyle(Style.LIGHT)
} else if (id == R.id.dark) {
mapStyle.changeStyle(Style.DARK)
}
}
运行效果图
3D基础 | 3D影像 | |
---|---|---|
基础 | 影像 | 影像+标签 |
户外 | 浅 | 深 |
附不同样式中的图层
查看地图样式的图层Z索引顺序和图层ID。
样式 | 图层 |
---|---|
Mapbox Standard | - |
Mapbox Standard Satellite | - |
Mapbox Streets | land, landcover, national-park, landuse, pitch-outline, waterway-shadow, water-shadow, waterway, water, water-depth, hillshade, land-structure-polygon, land-structure-line, aeroway-polygon, aeroway-line, building, building-underground, tunnel-minor-case, tunnel-street-case, tunnel-minor-link-case, tunnel-secondary-tertiary-case, tunnel-primary-case, tunnel-major-link-case, tunnel-motorway-trunk-case, tunnel-path, tunnel-steps, tunnel-pedestrian, tunnel-construction, tunnel-minor, tunnel-minor-link, tunnel-major-link, tunnel-street, tunnel-street-low, tunnel-secondary-tertiary, tunnel-primary, tunnel-motorway-trunk, tunnel-oneway-arrow-blue, tunnel-oneway-arrow-white, ferry, ferry-auto, road-pedestrian-polygon-fill, road-pedestrian-polygon-pattern, road-path-bg, road-steps-bg, road-pedestrian-case, road-path, road-steps, road-pedestrian, golf-hole-line, road-polygon, turning-feature-outline, road-minor-case, road-street-case, road-minor-link-case, road-secondary-tertiary-case, road-primary-case, road-major-link-case, road-motorway-trunk-case, turning-feature, road-construction, road-minor, road-minor-link, road-major-link, road-street, road-street-low, road-secondary-tertiary, road-primary, road-motorway-trunk, road-rail, road-rail-tracks, level-crossing, road-oneway-arrow-blue, road-oneway-arrow-white, crosswalks, bridge-path-bg, bridge-steps-bg, bridge-pedestrian-case, bridge-path, bridge-steps, bridge-pedestrian, bridge-minor-case, bridge-street-case, bridge-minor-link-case, bridge-secondary-tertiary-case, bridge-primary-case, bridge-major-link-case, bridge-motorway-trunk-case, bridge-construction, bridge-minor, bridge-minor-link, bridge-major-link, bridge-street, bridge-street-low, bridge-secondary-tertiary, bridge-primary, bridge-motorway-trunk, bridge-major-link-2-case, bridge-motorway-trunk-2-case, bridge-major-link-2, bridge-motorway-trunk-2, bridge-oneway-arrow-blue, bridge-oneway-arrow-white, bridge-rail, bridge-rail-tracks, aerialway, admin-1-boundary-bg, admin-0-boundary-bg, admin-1-boundary, admin-0-boundary, admin-0-boundary-disputed, building-entrance, building-number-label, block-number-label, road-label, road-intersection, road-number-shield, road-exit-shield, path-pedestrian-label, golf-hole-label, ferry-aerialway-label, waterway-label, natural-line-label, natural-point-label, water-line-label, water-point-label, poi-label, transit-label, airport-label, settlement-subdivision-label, settlement-minor-label, settlement-major-label, state-label, country-label, continent-label |
Satellite | background, satellite |
Satellite Streets | background, satellite, tunnel-minor-case, tunnel-street-case, tunnel-minor-link-case, tunnel-secondary-tertiary-case, tunnel-primary-case, tunnel-major-link-case, tunnel-motorway-trunk-case, tunnel-path, tunnel-steps, tunnel-pedestrian, tunnel-minor, tunnel-minor-link, tunnel-major-link, tunnel-street, tunnel-street-low, tunnel-secondary-tertiary, tunnel-primary, tunnel-motorway-trunk, road-path, road-steps, road-pedestrian, road-minor-case, road-street-case, road-minor-link-case, road-secondary-tertiary-case, road-primary-case, road-major-link-case, road-motorway-trunk-case, road-minor, road-minor-link, road-major-link, road-street, road-street-low, road-secondary-tertiary, road-primary, road-motorway-trunk, bridge-path, bridge-steps, bridge-pedestrian, bridge-minor-case, bridge-street-case, bridge-minor-link-case, bridge-secondary-tertiary-case, bridge-primary-case, bridge-major-link-case, bridge-motorway-trunk-case, bridge-minor, bridge-minor-link, bridge-major-link, bridge-street, bridge-street-low, bridge-secondary-tertiary, bridge-primary, bridge-motorway-trunk, bridge-major-link-2-case, bridge-motorway-trunk-2-case, bridge-major-link-2, bridge-motorway-trunk-2, aerialway, admin-1-boundary-bg, admin-0-boundary-bg, admin-1-boundary, admin-0-boundary, admin-0-boundary-disputed, road-label, road-intersection, road-number-shield, road-exit-shield, path-pedestrian-label, ferry-aerialway-label, waterway-label, natural-line-label, natural-point-label, water-line-label, water-point-label, poi-label, transit-label, airport-label, settlement-subdivision-label, settlement-minor-label, settlement-major-label, state-label, country-label, continent-label |
Outdoors | land, landcover, national-park, national-park_tint-band, landuse, pitch-outline, waterway-shadow, water-shadow, waterway, water, water-depth, wetland, wetland-pattern, hillshade, contour-line, land-structure-polygon, land-structure-line, aeroway-polygon, aeroway-line, building, building-underground, tunnel-minor-case, tunnel-street-case, tunnel-minor-link-case, tunnel-secondary-tertiary-case, tunnel-primary-case, tunnel-major-link-case, tunnel-motorway-trunk-case, tunnel-path-trail, tunnel-path-cycleway-piste, tunnel-path, tunnel-steps, tunnel-pedestrian, tunnel-construction, tunnel-minor, tunnel-minor-link, tunnel-major-link, tunnel-street, tunnel-street-low, tunnel-secondary-tertiary, tunnel-primary, tunnel-motorway-trunk, tunnel-oneway-arrow-blue, tunnel-oneway-arrow-white, cliff, ferry, ferry-auto, road-pedestrian-polygon-fill, road-pedestrian-polygon-pattern, road-path-bg, road-steps-bg, road-pedestrian-case, road-path-trail, road-path-cycleway-piste, road-path, road-steps, road-pedestrian, golf-hole-line, road-polygon, turning-feature-outline, road-minor-case, road-street-case, road-minor-link-case, road-secondary-tertiary-case, road-primary-case, road-major-link-case, road-motorway-trunk-case, turning-feature, road-construction, road-minor, road-minor-link, road-major-link, road-street, road-street-low, road-secondary-tertiary, road-primary, road-motorway-trunk, road-rail, road-rail-tracks, level-crossing, road-oneway-arrow-blue, road-oneway-arrow-white, crosswalks, gate-fence-hedge, bridge-path-bg, bridge-steps-bg, bridge-pedestrian-case, bridge-path-trail, bridge-path-cycleway-piste, bridge-path, bridge-steps, bridge-pedestrian, gate-label, bridge-minor-case, bridge-street-case, bridge-minor-link-case, bridge-secondary-tertiary-case, bridge-primary-case, bridge-major-link-case, bridge-motorway-trunk-case, bridge-construction, bridge-minor, bridge-minor-link, bridge-major-link, bridge-street, bridge-street-low, bridge-secondary-tertiary, bridge-primary, bridge-motorway-trunk, bridge-major-link-2-case, bridge-motorway-trunk-2-case, bridge-major-link-2, bridge-motorway-trunk-2, bridge-oneway-arrow-blue, bridge-oneway-arrow-white, bridge-rail, bridge-rail-tracks, aerialway, admin-1-boundary-bg, admin-0-boundary-bg, admin-1-boundary, admin-0-boundary, admin-0-boundary-disputed, contour-label, building-entrance, building-number-label, block-number-label, road-label, road-intersection, road-number-shield, road-exit-shield, path-pedestrian-label, golf-hole-label, ferry-aerialway-label, waterway-label, natural-line-label, natural-point-label, water-line-label, water-point-label, poi-label, transit-label, airport-label, settlement-subdivision-label, settlement-minor-label, settlement-major-label, state-label, country-label, continent-label |
Light | land, national-park, landuse, waterway, water, land-structure-polygon, land-structure-line, aeroway-polygon, aeroway-line, building, tunnel-path-trail, tunnel-path-cycleway-piste, tunnel-path, tunnel-steps, tunnel-pedestrian, tunnel-simple, road-path-trail, road-path-cycleway-piste, road-path, road-steps, road-pedestrian, road-simple, road-rail, bridge-path-trail, bridge-path-cycleway-piste, bridge-path, bridge-steps, bridge-pedestrian, bridge-case-simple, bridge-simple, bridge-rail, admin-1-boundary-bg, admin-0-boundary-bg, admin-1-boundary, admin-0-boundary, admin-0-boundary-disputed, road-label-simple, waterway-label, natural-line-label, natural-point-label, water-line-label, water-point-label, poi-label, airport-label, settlement-subdivision-label, settlement-minor-label, settlement-major-label, state-label, country-label, continent-label |
Dark | land, national-park, landuse, waterway, water, land-structure-polygon, land-structure-line, aeroway-polygon, aeroway-line, building, tunnel-path-trail, tunnel-path-cycleway-piste, tunnel-path, tunnel-steps, tunnel-pedestrian, tunnel-simple, road-path-trail, road-path-cycleway-piste, road-path, road-steps, road-pedestrian, road-simple, road-rail, bridge-path-trail, bridge-path-cycleway-piste, bridge-path, bridge-steps, bridge-pedestrian, bridge-case-simple, bridge-simple, bridge-rail, admin-1-boundary-bg, admin-0-boundary-bg, admin-1-boundary, admin-0-boundary, admin-0-boundary-disputed, road-label-simple, waterway-label, natural-line-label, natural-point-label, water-line-label, water-point-label, poi-label, airport-label, settlement-subdivision-label, settlement-minor-label, settlement-major-label, state-label, country-label, continent-label |