Last active
February 7, 2021 14:46
-
-
Save tobrun/349777a6ef0dfb55245a544344ee197a to your computer and use it in GitHub Desktop.
SymbolGenerator allows to convert a Android SDK View to a Bitmap. Use SymbolGenerator in combination with SymbolLayer. Add the result from SymbolGenerator#generate(View) with MapboxMap#addImage(String, Bitmap) and link the id of the image with PropertyFactory#iconImage(String) when setting properties to a SymbolLayer with SymbolLayer#setProperti…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Utility class to generate Bitmaps for Symbol. | |
* <p> | |
* Bitmaps can be added to the map with {@link com.mapbox.mapboxsdk.maps.MapboxMap#addImage(String, Bitmap)} | |
* </p> | |
*/ | |
public final class SymbolGenerator { | |
/** | |
* Generate a Bitmap from an Android SDK View. | |
* | |
* @param view the View to be drawn to a Bitmap | |
* @return the generated bitmap | |
*/ | |
public static Bitmap generate(@NonNull View view) { | |
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); | |
view.measure(measureSpec, measureSpec); | |
int measuredWidth = view.getMeasuredWidth(); | |
int measuredHeight = view.getMeasuredHeight(); | |
view.layout(0, 0, measuredWidth, measuredHeight); | |
Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888); | |
bitmap.eraseColor(Color.TRANSPARENT); | |
Canvas canvas = new Canvas(bitmap); | |
view.draw(canvas); | |
return bitmap; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.mapbox.mapboxsdk.testapp.activity.style; | |
import android.graphics.Color; | |
import android.graphics.PointF; | |
import android.os.Bundle; | |
import android.support.annotation.NonNull; | |
import android.support.v7.app.AppCompatActivity; | |
import android.view.Menu; | |
import android.view.MenuItem; | |
import android.widget.TextView; | |
import android.widget.Toast; | |
import com.google.gson.GsonBuilder; | |
import com.mapbox.mapboxsdk.geometry.LatLng; | |
import com.mapbox.mapboxsdk.maps.MapView; | |
import com.mapbox.mapboxsdk.maps.MapboxMap; | |
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; | |
import com.mapbox.mapboxsdk.style.layers.SymbolLayer; | |
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; | |
import com.mapbox.mapboxsdk.style.sources.Source; | |
import com.mapbox.mapboxsdk.style.utils.SymbolGenerator; | |
import com.mapbox.mapboxsdk.testapp.R; | |
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils; | |
import com.mapbox.services.commons.geojson.Feature; | |
import com.mapbox.services.commons.geojson.FeatureCollection; | |
import com.mapbox.services.commons.geojson.Geometry; | |
import com.mapbox.services.commons.geojson.custom.GeometryDeserializer; | |
import com.mapbox.services.commons.geojson.custom.PositionDeserializer; | |
import com.mapbox.services.commons.models.Position; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.List; | |
import timber.log.Timber; | |
import static com.mapbox.mapboxsdk.style.layers.Filter.eq; | |
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; | |
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; | |
public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapReadyCallback { | |
private static final String GENERATED_SYMBOL_SOURCE_ID = "com.mapbox.mapboxsdk.style.layers.symbol.source.id"; | |
private static final String GENERATED_SYMBOL_LAYER_ID_BASE = "com.mapbox.mapboxsdk.style.layers.symbol.layer.id."; | |
private static final String GENERATED_SYMBOL_IMAGE_ID_BASE = "com.mapbox.mapboxsdk.style.layers.symbol.image.id."; | |
private static final String KEY_FEATURE_ID = "brk_name"; | |
private final List<String> layerIds = new ArrayList<>(); | |
private MapView mapView; | |
private MapboxMap mapboxMap; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_symbol_generator); | |
mapView = (MapView) findViewById(R.id.mapView); | |
mapView.onCreate(savedInstanceState); | |
mapView.getMapAsync(this); | |
} | |
@Override | |
public void onMapReady(MapboxMap map) { | |
mapboxMap = map; | |
try { | |
// read local geojson from raw folder | |
String tinyCountriesJson = ResourceUtils.readRawResource(this, R.raw.tiny_countries); | |
// convert geojson to a model | |
FeatureCollection featureCollection = new GsonBuilder() | |
.registerTypeAdapter(Geometry.class, new GeometryDeserializer()) | |
.registerTypeAdapter(Position.class, new PositionDeserializer()) | |
.create().fromJson(tinyCountriesJson, FeatureCollection.class); | |
// add a geojson to the map | |
Source source = new GeoJsonSource(GENERATED_SYMBOL_SOURCE_ID, featureCollection); | |
mapboxMap.addSource(source); | |
// for each feature add a symbolLayer | |
for (Feature feature : featureCollection.getFeatures()) { | |
String countryName = feature.getStringProperty(KEY_FEATURE_ID); | |
// create View | |
TextView textView = new TextView(this); | |
textView.setBackgroundColor(getResources().getColor(R.color.blueAccent)); | |
textView.setPadding(10, 5 , 10 , 5); | |
textView.setTextColor(Color.WHITE); | |
textView.setText(countryName); | |
// create bitmap from view | |
String iconId = GENERATED_SYMBOL_IMAGE_ID_BASE + countryName; | |
mapboxMap.addImage(iconId, SymbolGenerator.generate(textView)); | |
// create layer for bitmap and filter source on name | |
String layerId = GENERATED_SYMBOL_LAYER_ID_BASE + countryName; | |
layerIds.add(layerId); | |
mapboxMap.addLayer(new SymbolLayer(layerId, GENERATED_SYMBOL_SOURCE_ID) | |
.withProperties( | |
iconImage(iconId), | |
iconAllowOverlap(false) | |
).withFilter( | |
eq(KEY_FEATURE_ID, countryName) | |
) | |
); | |
} | |
addSymbolClickListener(); | |
} catch (IOException exception) { | |
Timber.e(exception); | |
} | |
} | |
private void addSymbolClickListener() { | |
mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() { | |
@Override | |
public void onMapClick(@NonNull LatLng point) { | |
PointF screenPoint = mapboxMap.getProjection().toScreenLocation(point); | |
String[] layerIdsArray = layerIds.toArray(new String[layerIds.size()]); | |
List<Feature> features = mapboxMap.queryRenderedFeatures(screenPoint, layerIdsArray); | |
if (!features.isEmpty()) { | |
Timber.v("Feature was clicked with data: %s", features.get(0).toJson()); | |
Toast.makeText( | |
SymbolGeneratorActivity.this, | |
"hello from: " + features.get(0).getStringProperty("name_sort"), | |
Toast.LENGTH_LONG).show(); | |
} | |
} | |
}); | |
} | |
@Override | |
public boolean onCreateOptionsMenu(Menu menu) { | |
getMenuInflater().inflate(R.menu.menu_generator_symbol, menu); | |
return super.onCreateOptionsMenu(menu); | |
} | |
@Override | |
public boolean onOptionsItemSelected(MenuItem item) { | |
if (item.getItemId() == R.id.menu_action_icon_overlap) { | |
for (String layerId : layerIds) { | |
SymbolLayer layer = mapboxMap.getLayerAs(layerId); | |
layer.setProperties(iconAllowOverlap(layer.getIconAllowOverlap().getValue() ? false : true)); | |
} | |
} | |
return super.onOptionsItemSelected(item); | |
} | |
@Override | |
protected void onStart() { | |
super.onStart(); | |
mapView.onStart(); | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
mapView.onResume(); | |
} | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
mapView.onPause(); | |
} | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
mapView.onStop(); | |
} | |
@Override | |
public void onSaveInstanceState(Bundle outState) { | |
super.onSaveInstanceState(outState); | |
mapView.onSaveInstanceState(outState); | |
} | |
@Override | |
public void onLowMemory() { | |
super.onLowMemory(); | |
mapView.onLowMemory(); | |
} | |
@Override | |
public void onDestroy() { | |
super.onDestroy(); | |
mapView.onDestroy(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment