Skip to content

Commit

Permalink
Add feature id to annotations; prepare showcase of callout annotations (
Browse files Browse the repository at this point in the history
#994)

* Add feature id to annotations; prepare showcase of callout annotations

* Re-use id for annotation

* Update example

* Allow view annotation be draggable
  • Loading branch information
kiryldz authored Dec 15, 2021
1 parent ca39a85 commit fe87eab
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 1 deletion.
12 changes: 12 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,18 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".ExampleOverviewActivity" />
</activity>
<activity
android:name=".examples.markersandcallouts.AnnotationWithCalloutActivity"
android:description="@string/description_view_annotation_callout_annotation"
android:exported="true"
android:label="@string/activity_view_annotations_callout_annotation">
<meta-data
android:name="@string/category"
android:value="@string/category_markers_and_callouts" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ExampleOverviewActivity" />
</activity>
<activity
android:name=".TestMapActivity"
android:exported="true" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/example_descriptions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,5 @@
<string name="description_osm">Using raster source and layer to render OSM tiles with TileSet class</string>
<string name="description_view_annotation">Add view annotation anchored to a symbol layer feature</string>
<string name="description_view_annotation_basic">Add view annotation on a map click</string>
<string name="description_view_annotation_callout_annotation">Callout view using annotation plugin</string>
</resources>
1 change: 1 addition & 0 deletions app/src/main/res/values/example_titles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,5 @@
<string name="activity_osm">TileJson</string>
<string name="activity_view_annotations">View annotations: advanced example</string>
<string name="activity_view_annotations_basic">View annotations: basic example</string>
<string name="activity_view_annotations_callout_annotation">View annotations: annotation callout</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ abstract class AnnotationManagerImpl<G : Geometry, T : Annotation<G>, S : Annota
private fun convertAnnotationsToFeatures(annotations: Collection<T>): List<Feature> =
annotations.map {
it.setUsedDataDrivenProperties()
Feature.fromGeometry(it.geometry, it.getJsonObjectCopy())
Feature.fromGeometry(it.geometry, it.getJsonObjectCopy(), it.featureIdentifier)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ abstract class Annotation<T : Geometry>(
*/
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.
*/
Expand All @@ -87,5 +92,7 @@ abstract class Annotation<T : Geometry>(
* Minimum latitude value in Mercator projection.
*/
const val MIN_MERCATOR_LATITUDE = -85.05112877980659

private const val FEATURE_IDENTIFIER_PREFIX = "mapbox_annotation_"
}
}

0 comments on commit fe87eab

Please sign in to comment.