我正在使用地图盒 Android SDK 来使用地图。
我正在使用符号图层在地图中添加动态符号。
我的代码:
for (Feature feature : featureCollection.features()) {
String report_id = feature.getStringProperty("report_id");
switch (report_id) {
case "1": {
Bitmap bitmap = null;
Drawable drawable = ContextCompat.getDrawable(activity, R.mipmap.ic_location_black);
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
bitmap = bitmapDrawable.getBitmap();
}
} else {
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
}
if (bitmap != null) {
mapboxMap.getStyle().addImage(MARKER_IMAGE_ID + report_id, bitmap);
}
mapboxMap.getStyle().addLayer(new SymbolLayer(MARKER_IMAGE_ID + report_id, GEOJSON_SOURCE_ID)
.withProperties(
iconImage(MARKER_IMAGE_ID + report_id),
iconAllowOverlap(true),
iconSize(0.7f)
));
break;
}
case "2": {
Bitmap bitmap = null;
Drawable drawable = ContextCompat.getDrawable(activity, R.mipmap.ic_current_pin);
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
bitmap = bitmapDrawable.getBitmap();
}
} else {
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
}
if (bitmap != null) {
mapboxMap.getStyle().addImage(MARKER_IMAGE_ID + report_id, bitmap);
}
mapboxMap.getStyle().addLayer(new SymbolLayer(MARKER_IMAGE_ID + report_id, GEOJSON_SOURCE_ID)
.withProperties(
iconImage(MARKER_IMAGE_ID + report_id),
iconAllowOverlap(true),
iconSize(0.7f)
));
break;
}
case "3": {
Bitmap bitmap = null;
Drawable drawable = ContextCompat.getDrawable(activity, R.mipmap.ic_current_location);
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
bitmap = bitmapDrawable.getBitmap();
}
} else {
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
}
if (bitmap != null) {
mapboxMap.getStyle().addImage(MARKER_IMAGE_ID + report_id, bitmap);
}
mapboxMap.getStyle().addLayer(new SymbolLayer(MARKER_IMAGE_ID + report_id, GEOJSON_SOURCE_ID)
.withProperties(
iconImage(MARKER_IMAGE_ID + report_id),
iconAllowOverlap(true),
iconSize(0.7f)
));
break;
}
default: {
Bitmap bitmap = null;
Drawable drawable = ContextCompat.getDrawable(activity, R.mipmap.ic_location_transparent);
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
bitmap = bitmapDrawable.getBitmap();
}
} else {
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
}
if (bitmap != null) {
mapboxMap.getStyle().addImage(MARKER_IMAGE_ID + report_id, bitmap);
}
mapboxMap.getStyle().addLayer(new SymbolLayer(MARKER_IMAGE_ID + report_id, GEOJSON_SOURCE_ID)
.withProperties(
iconImage(MARKER_IMAGE_ID + report_id),
iconAllowOverlap(true),
iconSize(0.7f)
));
break;
}
}
}
但是我得到的是所有符号中的所有图像,而不是像这样的特定单个符号中的单个图像
https://www.screencast.com/t/hcoetxj0G
我想为单个符号层生成单个图像。
请知道答案的人帮帮我。
我使用了https://www.diffchecker.com/,看起来 switch/case 部分的各个部分之间的唯一区别是您正在使用的 mipmap 图像。如果是这样,我会考虑使用 Maps SDK 的匹配表达式来设置图标。请参阅https://docs.mapbox.com/android/maps/examples/marker-symbol-layer/。我已经采取了 https://docs.mapbox.com/android/maps/examples/marker-symbol-layer/ 并进行了调整以匹配您所拥有的
import android.graphics.BitmapFactory;
import android.os.Bundle;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxandroiddemo.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.match;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
/**
* Display {@link SymbolLayer} icons on the map.
*/
public class BasicSymbolLayerActivity extends AppCompatActivity implements
OnMapReadyCallback {
private static final String SOURCE_ID = "SOURCE_ID";
private static final String ICON_ID = "ICON_ID";
private static final String LAYER_ID = "LAYER_ID";
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Mapbox access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Mapbox.getInstance(this, getString(R.string.access_token));
// This contains the MapView in XML and needs to be called after the access token is configured.
setContentView(R.layout.activity_style_basic_symbol_layer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
List<Feature> symbolLayerIconFeatureList = new ArrayList<>();
symbolLayerIconFeatureList.add(Feature.fromGeometry(
Point.fromLngLat(-57.225365, -33.213144)));
symbolLayerIconFeatureList.add(Feature.fromGeometry(
Point.fromLngLat(-54.14164, -33.981818)));
symbolLayerIconFeatureList.add(Feature.fromGeometry(
Point.fromLngLat(-56.990533, -30.583266)));
mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cjf4m44iw0uza2spb3q0a7s41")
// Add the SymbolLayer icon image to the map style
.withImage("black_location_icon_id", BitmapFactory.decodeResource(activity.getResources(), R.drawable.ic_location_black))
.withImage("current_pin_icon_id", BitmapFactory.decodeResource(activity.getResources(), R.drawable.ic_current_pin))
.withImage("current_location_icon_id", BitmapFactory.decodeResource(activity.getResources(), R.drawable.ic_current_location))
.withImage("location_transparent_icon_id", BitmapFactory.decodeResource(activity.getResources(), R.drawable.ic_location_transparent))
// Adding a GeoJson source for the SymbolLayer icons.
.withSource(new GeoJsonSource(SOURCE_ID,
FeatureCollection.fromFeatures(symbolLayerIconFeatureList)))
// Adding the actual SymbolLayer to the map style. An offset is added that the bottom of the red
// marker icon gets fixed to the coordinate, rather than the middle of the icon being fixed to
// the coordinate point. This is offset is not always needed and is dependent on the image
// that you use for the SymbolLayer icon.
.withLayer(new SymbolLayer(LAYER_ID, SOURCE_ID)
.withProperties(
iconImage(match(get("report_id"), literal("location_transparent_icon_id"),
stop(literal("1"), "black_location_icon_id"),
stop(literal("2"), "current_pin_icon_id"),
stop(literal("3"), "current_location_icon_id"))),
iconAllowOverlap(true),
iconIgnorePlacement(true),
iconAllowOverlap(true),
iconSize(0.7f)
)
), new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// Map is set up and the style has loaded. Now you can add additional data or make other map adjustments.
}
});
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
地图 SDK 还具有
addOnStyleImageMissingListener
:https://docs.mapbox.com/android/maps/examples/missing-icon/
另外,我会使用以下内容代替
mapboxMap.getStyle()
。 mapboxMap.getStyle()
有机会回归null
。
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
}
});
在地图上显示不同类型的兴趣点,例如卫生间、步道起点和野餐区。为此,我们将为每个 POI 类别定义自定义符号并将其覆盖在地图上。
mapView.getMapboxMap().loadStyle(
styleExtension = style(Style.TRAFFIC_NIGHT) {
// Define custom images for symbols
+image(RESTROOMS) {
bitmap(drawableIdToBitmap(requireContext(), R.drawable.ic_rest_rooms))
}
+image(TRAIL_HEAD) {
bitmap(drawableIdToBitmap(requireContext(), R.drawable.ic_trail_head))
}
+image(PICNIC_AREA) {
bitmap(drawableIdToBitmap(requireContext(), R.drawable.ic_panic_area))
}
+symbolLayer(LAYER_ID, SOURCE_ID) {
sourceLayer(CIRLCE_LAYER_ID)
// Assign the appropriate icon image based on the POI type
iconImage(
switchCase {
eq {
get {
literal(ICON_KEY)
}
literal(KEY_PICNIC_AREA)
}
literal(PICNIC_AREA)
eq {
get {
literal(ICON_KEY)
}
literal(KEY_RESTROOMS)
}
literal(RESTROOMS)
eq {
get {
literal(ICON_KEY)
}
literal(KEY_TRAIL_HEAD)
}
literal(TRAIL_HEAD)
// Default case is to return an empty string so no icon will be loaded
literal("")
}
)
iconAllowOverlap(true)
iconAnchor(IconAnchor.BOTTOM)
// Display text for each POI
textField(
Expression.get(TEXT_KEY)
)
textColor("#FFFFFF")
}
}
)
在上面的代码中,我们为卫生间、步道起点和野餐区符号定义了自定义图像。
symbolLayer
用于指定这些符号在地图上的显示方式。 iconImage
属性根据 POI 类型动态选择适当的图标,并且我们还为每个 POI 显示文本。
要使用数据填充我们的自定义符号图层,我们需要一个数据源。在此示例中,我们将使用包含示例数据的 GeoJSON 源。
private val samplejson = """{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-122.4167, 37.7833]
},
"properties": {
"name": "Golden Gate Bridge",
"POITYPE": "Restroom",
"TEXT_KEY": "Rest Room"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-122.4084, 37.7833]
},
"properties": {
"name": "Golden Gate Park",
"POITYPE": "Trailhead",
"TEXT_KEY": "Trail heading"
}
}
]
}"""
此 GeoJSON 源包含两个表示兴趣点的要素,每个要素都有一个位置、名称、POI 类型以及要在地图上显示的文本。
### Adding the Data to the Map
最后,我们将 GeoJSON 数据添加到地图中,并将其与我们之前定义的符号图层关联起来。
val geoJsonSource = GeoJsonSource.Builder(SOURCE_ID)
.data(samplejson)
.build()
val symbolLayer = SymbolLayer(CIRLCE_LAYER_ID, SOURCE_ID)
it.addSource(geoJsonSource)
it.addLayer(symbolLayer)
在加载 Mapbox 样式扩展后使用上面的代码,例如:
mapView.getMapboxMap().loadStyle(/* above/your-style-extension*/){ it->//you map style there after they get load
val geoJsonSource = GeoJsonSource.Builder(SOURCE_ID)
.data(samplejson)
.build()
val symbolLayer = SymbolLayer(CIRLCE_LAYER_ID, SOURCE_ID)
it.addSource(geoJsonSource)
it.addLayer(symbolLayer)
}
private val RESTROOMS = "RESTROOMS"
private val TRAIL_HEAD = "trailhead"
private val PICNIC_AREA = "PICNIC_AREA"
private val KEY_PICNIC_AREA = "Picnic Area"
private val KEY_RESTROOMS = "Restroom"
private val KEY_TRAIL_HEAD = "Trailhead"
private val ICON_KEY = "POITYPE"
private val TEXT_KEY = "TEXT_KEY"
private val CIRLCE_LAYER_ID = "symbol-layer"
private val SOURCE_ID = "SOURCE_ID"
private val LAYER_ID = "LAYER_ID"
现在,来自 GeoJSON 源的自定义符号和文本将根据 POI 类型显示在地图上。 上述功能 geoJson 将在旧金山展示