From 9e09525990cf755d88e5bc64dec9bfb0b2da02ce Mon Sep 17 00:00:00 2001 From: tobrun Date: Thu, 6 Sep 2018 12:36:30 +0200 Subject: [android] - add OnSymbolClickListener --- .../mapboxsdk/symbol/OnSymbolClickListener.java | 15 +++++ .../java/com/mapbox/mapboxsdk/symbol/Symbol.java | 9 +++ .../com/mapbox/mapboxsdk/symbol/SymbolManager.java | 66 +++++++++++++++++++--- .../com/mapbox/mapboxsdk/symbol/symbol.java.ejs | 9 +++ .../mapbox/mapboxsdk/symbol/symbolManager.java.ejs | 66 +++++++++++++++++++--- .../activity/maplayout/SimpleMapActivity.java | 10 ++++ 6 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/OnSymbolClickListener.java diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/OnSymbolClickListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/OnSymbolClickListener.java new file mode 100644 index 0000000000..a14a170580 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/OnSymbolClickListener.java @@ -0,0 +1,15 @@ +package com.mapbox.mapboxsdk.symbol; + +/** + * Interface definition for a callback to be invoked when a symbol has been clicked. + */ +public interface OnSymbolClickListener { + + /** + * Invoked when a symbol has been clicked. + * + * @param symbol that has been clicked + */ + void onSymbolClick(Symbol symbol); + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/Symbol.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/Symbol.java index f4155e1b07..9984858d11 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/Symbol.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/Symbol.java @@ -50,6 +50,15 @@ public class Symbol { return jsonObject; } + /** + * Get the symbol id. + * + * @return the symbol id + */ + public long getId() { + return jsonObject.get(ID_KEY).getAsLong(); + } + /** * Set the LatLng of the symbol, which represents the location of the symbol on the map * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/SymbolManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/SymbolManager.java index c0b745d954..3615906d4b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/SymbolManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/SymbolManager.java @@ -2,9 +2,12 @@ package com.mapbox.mapboxsdk.symbol; +import android.graphics.PointF; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.annotation.VisibleForTesting; +import android.support.v4.util.LongSparseArray; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -31,8 +34,12 @@ public class SymbolManager { private GeoJsonSource geoJsonSource; private SymbolLayer symbolLayer; + // callback listeners + private OnSymbolClickListener symbolClickListener; + // internal data set - private List symbolList = new ArrayList<>(); + private final LongSparseArray symbols = new LongSparseArray<>(); + private final List features = new ArrayList<>(); private long currentMarkerId; /** @@ -62,6 +69,7 @@ public class SymbolManager { this.symbolLayer = symbolLayer; mapboxMap.addSource(geoJsonSource); mapboxMap.addLayer(symbolLayer); + mapboxMap.addOnMapClickListener(new MapClickResolver(mapboxMap)); } /** @@ -74,8 +82,8 @@ public class SymbolManager { public Symbol createSymbol(@NonNull LatLng latLng) { Symbol symbol = new Symbol(this, currentMarkerId); symbol.setLatLng(latLng); + symbols.put(currentMarkerId, symbol); currentMarkerId++; - symbolList.add(symbol); return symbol; } @@ -86,7 +94,7 @@ public class SymbolManager { */ @UiThread public void deleteSymbol(@NonNull Symbol symbol) { - symbolList.remove(symbol); + symbols.remove(symbol.getId()); updateSource(); } @@ -96,8 +104,8 @@ public class SymbolManager { * @return list of symbols */ @UiThread - public List getSymbols() { - return symbolList; + public LongSparseArray getSymbols() { + return symbols; } /** @@ -105,13 +113,26 @@ public class SymbolManager { */ public void updateSource() { // todo move feature creation to a background thread? - List features = new ArrayList<>(); - for (Symbol symbol : symbolList) { + features.clear(); + Symbol symbol; + for (int i = 0; i < symbols.size(); i++) { + symbol = symbols.valueAt(i); features.add(Feature.fromGeometry(symbol.getGeometry(), symbol.getFeature())); } geoJsonSource.setGeoJson(FeatureCollection.fromFeatures(features)); } + /** + * Set a callback to be invoked when a symbol has been clicked. + *

+ * To unset, use a null argument. + *

+ * + * @param symbolClickListener the callback to be invoked when a symbol is clicked, or null to unset + */ + public void setOnSymbolClickListener(@Nullable OnSymbolClickListener symbolClickListener) { + this.symbolClickListener = symbolClickListener; + } private static PropertyValue[] getLayerDefinition() { return new PropertyValue[]{ @@ -594,4 +615,35 @@ public class SymbolManager { symbolLayer.setProperties(textTranslateAnchor(value)); } + + + /** + * Inner class for transforming map click events into symbol clicks + */ + private class MapClickResolver implements MapboxMap.OnMapClickListener { + + private MapboxMap mapboxMap; + + private MapClickResolver(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + } + + @Override + public void onMapClick(@NonNull LatLng point) { + if (symbolClickListener == null) { + return; + } + + PointF screenLocation = mapboxMap.getProjection().toScreenLocation(point); + List features = mapboxMap.queryRenderedFeatures(screenLocation, ID_GEOJSON_LAYER); + if (!features.isEmpty()) { + long symbolId = features.get(0).getProperty(Symbol.ID_KEY).getAsLong(); + Symbol symbol = symbols.get(symbolId); + if (symbol != null) { + symbolClickListener.onSymbolClick(symbols.get(symbolId)); + } + } + } + } + } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbol.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbol.java.ejs index 966e1681de..91632c81b7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbol.java.ejs +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbol.java.ejs @@ -55,6 +55,15 @@ public class Symbol { return jsonObject; } + /** + * Get the symbol id. + * + * @return the symbol id + */ + public long getId() { + return jsonObject.get(ID_KEY).getAsLong(); + } + /** * Set the LatLng of the symbol, which represents the location of the symbol on the map * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbolManager.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbolManager.java.ejs index 6beb700241..3d52867ac6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbolManager.java.ejs +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/symbol/symbolManager.java.ejs @@ -7,9 +7,12 @@ package com.mapbox.mapboxsdk.symbol; +import android.graphics.PointF; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.annotation.VisibleForTesting; +import android.support.v4.util.LongSparseArray; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -36,8 +39,12 @@ public class SymbolManager { private GeoJsonSource geoJsonSource; private SymbolLayer symbolLayer; + // callback listeners + private OnSymbolClickListener symbolClickListener; + // internal data set - private List symbolList = new ArrayList<>(); + private final LongSparseArray symbols = new LongSparseArray<>(); + private final List features = new ArrayList<>(); private long currentMarkerId; /** @@ -67,6 +74,7 @@ public class SymbolManager { this.symbolLayer = symbolLayer; mapboxMap.addSource(geoJsonSource); mapboxMap.addLayer(symbolLayer); + mapboxMap.addOnMapClickListener(new MapClickResolver(mapboxMap)); } /** @@ -79,8 +87,8 @@ public class SymbolManager { public Symbol createSymbol(@NonNull LatLng latLng) { Symbol symbol = new Symbol(this, currentMarkerId); symbol.setLatLng(latLng); + symbols.put(currentMarkerId, symbol); currentMarkerId++; - symbolList.add(symbol); return symbol; } @@ -91,7 +99,7 @@ public class SymbolManager { */ @UiThread public void deleteSymbol(@NonNull Symbol symbol) { - symbolList.remove(symbol); + symbols.remove(symbol.getId()); updateSource(); } @@ -101,8 +109,8 @@ public class SymbolManager { * @return list of symbols */ @UiThread - public List getSymbols() { - return symbolList; + public LongSparseArray getSymbols() { + return symbols; } /** @@ -110,13 +118,26 @@ public class SymbolManager { */ public void updateSource() { // todo move feature creation to a background thread? - List features = new ArrayList<>(); - for (Symbol symbol : symbolList) { + features.clear(); + Symbol symbol; + for (int i = 0; i < symbols.size(); i++) { + symbol = symbols.valueAt(i); features.add(Feature.fromGeometry(symbol.getGeometry(), symbol.getFeature())); } geoJsonSource.setGeoJson(FeatureCollection.fromFeatures(features)); } + /** + * Set a callback to be invoked when a symbol has been clicked. + *

+ * To unset, use a null argument. + *

+ * + * @param symbolClickListener the callback to be invoked when a symbol is clicked, or null to unset + */ + public void setOnSymbolClickListener(@Nullable OnSymbolClickListener symbolClickListener) { + this.symbolClickListener = symbolClickListener; + } private static PropertyValue[] getLayerDefinition() { return new PropertyValue[]{ @@ -150,4 +171,35 @@ public class SymbolManager { <% } -%> <% } -%> + + + /** + * Inner class for transforming map click events into symbol clicks + */ + private class MapClickResolver implements MapboxMap.OnMapClickListener { + + private MapboxMap mapboxMap; + + private MapClickResolver(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + } + + @Override + public void onMapClick(@NonNull LatLng point) { + if (symbolClickListener == null) { + return; + } + + PointF screenLocation = mapboxMap.getProjection().toScreenLocation(point); + List features = mapboxMap.queryRenderedFeatures(screenLocation, ID_GEOJSON_LAYER); + if (!features.isEmpty()) { + long symbolId = features.get(0).getProperty(Symbol.ID_KEY).getAsLong(); + Symbol symbol = symbols.get(symbolId); + if (symbol != null) { + symbolClickListener.onSymbolClick(symbols.get(symbolId)); + } + } + } + } + } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java index d61122d4b0..7e49dad78b 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java @@ -11,9 +11,11 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.style.layers.Property; import com.mapbox.mapboxsdk.style.layers.PropertyFactory; +import com.mapbox.mapboxsdk.symbol.OnSymbolClickListener; import com.mapbox.mapboxsdk.symbol.Symbol; import com.mapbox.mapboxsdk.symbol.SymbolManager; import com.mapbox.mapboxsdk.testapp.R; +import timber.log.Timber; import java.util.Random; @@ -41,6 +43,14 @@ public class SimpleMapActivity extends AppCompatActivity { // create symbol manager SymbolManager symbolManager = new SymbolManager(mapboxMap); + symbolManager.setOnSymbolClickListener(new OnSymbolClickListener() { + @Override + public void onSymbolClick(Symbol symbol) { + Timber.e("Symbol clicked with id: %s", symbol.getId()); + } + }); + + // set non data driven properties symbolManager.setIconAllowOverlap(true); symbolManager.setTextAllowOverlap(true); -- cgit v1.2.1