diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f91d972b30..fb14e66940 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1112,6 +1112,18 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".ExampleOverviewActivity" /> + + + + diff --git a/app/src/main/java/com/mapbox/maps/testapp/examples/markersandcallouts/AnnotationWithCalloutActivity.kt b/app/src/main/java/com/mapbox/maps/testapp/examples/markersandcallouts/AnnotationWithCalloutActivity.kt new file mode 100644 index 0000000000..5328e9d1cf --- /dev/null +++ b/app/src/main/java/com/mapbox/maps/testapp/examples/markersandcallouts/AnnotationWithCalloutActivity.kt @@ -0,0 +1,139 @@ +package com.mapbox.maps.testapp.examples.markersandcallouts + +import android.annotation.SuppressLint +import android.graphics.Bitmap +import android.os.Bundle +import android.view.View +import android.widget.Button +import androidx.appcompat.app.AppCompatActivity +import com.mapbox.geojson.Point +import com.mapbox.maps.MapView +import com.mapbox.maps.Style +import com.mapbox.maps.ViewAnnotationAnchor +import com.mapbox.maps.extension.style.layers.properties.generated.IconAnchor +import com.mapbox.maps.plugin.annotation.Annotation +import com.mapbox.maps.plugin.annotation.annotations +import com.mapbox.maps.plugin.annotation.generated.* +import com.mapbox.maps.testapp.R +import com.mapbox.maps.testapp.databinding.ActivityViewAnnotationShowcaseBinding +import com.mapbox.maps.testapp.databinding.ItemCalloutViewBinding +import com.mapbox.maps.testapp.utils.BitmapUtils +import com.mapbox.maps.viewannotation.viewAnnotationOptions + +/** + * Example how to add view annotation to the point annotation. + */ +class AnnotationWithCalloutActivity : AppCompatActivity() { + + private lateinit var pointAnnotationManager: PointAnnotationManager + private lateinit var pointAnnotation: PointAnnotation + private lateinit var viewAnnotation: View + + @SuppressLint("SetTextI18n") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val binding = ActivityViewAnnotationShowcaseBinding.inflate(layoutInflater) + setContentView(binding.root) + + val iconBitmap = BitmapUtils.bitmapFromDrawableRes( + this@AnnotationWithCalloutActivity, + R.drawable.blue_marker_view + )!! + + binding.mapView.getMapboxMap().loadStyleUri(Style.MAPBOX_STREETS) { + prepareAnnotationMarker(binding.mapView, iconBitmap) + prepareViewAnnotation(binding.mapView) + // show / hide view annotation based on a marker click + pointAnnotationManager.addClickListener { clickedAnnotation -> + if (pointAnnotation == clickedAnnotation) { + viewAnnotation.toggleViewVisibility() + } + true + } + // show / hide view annotation based on marker visibility + binding.fabStyleToggle.setOnClickListener { + pointAnnotation.iconImageBitmap = if (pointAnnotation.iconImage == null) iconBitmap else null + pointAnnotationManager.update(pointAnnotation) + } + // update view annotation geometry if dragging the marker + pointAnnotationManager.addDragListener(object : OnPointAnnotationDragListener { + override fun onAnnotationDragStarted(annotation: Annotation<*>) { + } + + override fun onAnnotationDrag(annotation: Annotation<*>) { + if (annotation == pointAnnotation) { + binding.mapView.viewAnnotationManager.updateViewAnnotation( + viewAnnotation, + viewAnnotationOptions { + geometry(pointAnnotation.geometry) + } + ) + ItemCalloutViewBinding.bind(viewAnnotation).apply { + textNativeView.text = "lat=%.2f\nlon=%.2f".format( + pointAnnotation.geometry.latitude(), + pointAnnotation.geometry.longitude() + ) + } + } + } + + override fun onAnnotationDragFinished(annotation: Annotation<*>) { + } + }) + } + } + + private fun View.toggleViewVisibility() { + visibility = if (visibility == View.VISIBLE) View.GONE else View.VISIBLE + } + + @SuppressLint("SetTextI18n") + private fun prepareViewAnnotation(mapView: MapView) { + val viewAnnotationManager = mapView.viewAnnotationManager + viewAnnotation = viewAnnotationManager.addViewAnnotation( + resId = R.layout.item_callout_view, + options = viewAnnotationOptions { + geometry(POINT) + associatedFeatureId(pointAnnotation.featureIdentifier) + anchor(ViewAnnotationAnchor.BOTTOM) + offsetY((pointAnnotation.iconImageBitmap?.height!!).toInt()) + } + ) + ItemCalloutViewBinding.bind(viewAnnotation).apply { + textNativeView.text = "lat=%.2f\nlon=%.2f".format(POINT.latitude(), POINT.longitude()) + closeNativeView.setOnClickListener { + viewAnnotationManager.removeViewAnnotation(viewAnnotation) + } + selectButton.setOnClickListener { b -> + val button = b as Button + val isSelected = button.text.toString().equals("SELECT", true) + val pxDelta = if (isSelected) SELECTED_ADD_COEF_PX else -SELECTED_ADD_COEF_PX + button.text = if (isSelected) "DESELECT" else "SELECT" + viewAnnotationManager.updateViewAnnotation( + viewAnnotation, + viewAnnotationOptions { + width(viewAnnotationManager.getViewAnnotationOptionsByView(viewAnnotation)?.width!! + pxDelta) + height(viewAnnotationManager.getViewAnnotationOptionsByView(viewAnnotation)?.height!! + pxDelta) + selected(isSelected) + } + ) + } + } + } + + private fun prepareAnnotationMarker(mapView: MapView, iconBitmap: Bitmap) { + val annotationPlugin = mapView.annotations + val pointAnnotationOptions: PointAnnotationOptions = PointAnnotationOptions() + .withPoint(POINT) + .withIconImage(iconBitmap) + .withIconAnchor(IconAnchor.BOTTOM) + .withDraggable(true) + pointAnnotationManager = annotationPlugin.createPointAnnotationManager() + pointAnnotation = pointAnnotationManager.create(pointAnnotationOptions) + } + + private companion object { + const val SELECTED_ADD_COEF_PX = 50 + val POINT: Point = Point.fromLngLat(0.381457, 6.687337) + } +} \ No newline at end of file diff --git a/app/src/main/res/values/example_descriptions.xml b/app/src/main/res/values/example_descriptions.xml index b55db5e083..3afdaa3f5d 100644 --- a/app/src/main/res/values/example_descriptions.xml +++ b/app/src/main/res/values/example_descriptions.xml @@ -87,4 +87,5 @@ Using raster source and layer to render OSM tiles with TileSet class Add view annotation anchored to a symbol layer feature Add view annotation on a map click + Callout view using annotation plugin diff --git a/app/src/main/res/values/example_titles.xml b/app/src/main/res/values/example_titles.xml index bd70bf9cba..6c78b71fce 100644 --- a/app/src/main/res/values/example_titles.xml +++ b/app/src/main/res/values/example_titles.xml @@ -87,4 +87,5 @@ TileJson View annotations: advanced example View annotations: basic example + View annotations: annotation callout diff --git a/plugin-annotation/src/main/java/com/mapbox/maps/plugin/annotation/AnnotationManagerImpl.kt b/plugin-annotation/src/main/java/com/mapbox/maps/plugin/annotation/AnnotationManagerImpl.kt index 79cec2e929..505952462e 100644 --- a/plugin-annotation/src/main/java/com/mapbox/maps/plugin/annotation/AnnotationManagerImpl.kt +++ b/plugin-annotation/src/main/java/com/mapbox/maps/plugin/annotation/AnnotationManagerImpl.kt @@ -453,7 +453,7 @@ abstract class AnnotationManagerImpl, S : Annota private fun convertAnnotationsToFeatures(annotations: Collection): List = annotations.map { it.setUsedDataDrivenProperties() - Feature.fromGeometry(it.geometry, it.getJsonObjectCopy()) + Feature.fromGeometry(it.geometry, it.getJsonObjectCopy(), it.featureIdentifier) } /** diff --git a/sdk-base/src/main/java/com/mapbox/maps/plugin/annotation/Annotation.kt b/sdk-base/src/main/java/com/mapbox/maps/plugin/annotation/Annotation.kt index f2507b87d7..b39b412320 100644 --- a/sdk-base/src/main/java/com/mapbox/maps/plugin/annotation/Annotation.kt +++ b/sdk-base/src/main/java/com/mapbox/maps/plugin/annotation/Annotation.kt @@ -71,6 +71,11 @@ abstract class Annotation( */ var isSelected: Boolean = false + /** + * Unique feature identifier. May be useful to connect an annotation with view annotation. + */ + val featureIdentifier = FEATURE_IDENTIFIER_PREFIX + id.toString() + /** * Static variables and methods. */ @@ -87,5 +92,7 @@ abstract class Annotation( * Minimum latitude value in Mercator projection. */ const val MIN_MERCATOR_LATITUDE = -85.05112877980659 + + private const val FEATURE_IDENTIFIER_PREFIX = "mapbox_annotation_" } } \ No newline at end of file