summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukas.paczos@gmail.com>2018-07-05 18:56:48 +0200
committerŁukasz Paczos <lukasz.paczos@mapbox.com>2018-07-06 13:22:08 +0200
commit282f89a9f3f40da1c2de97fd749366096e047538 (patch)
tree88a64ad571d13ff3081e05c45b696732c628bc7c
parent3bd24e655f63d347c399125d4f7880c50c2e3931 (diff)
downloadqtlocation-mapboxgl-282f89a9f3f40da1c2de97fd749366096e047538.tar.gz
[android] - added DraggableMarkerActivity
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt314
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_draggable_marker.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml1
5 files changed, 360 insertions, 13 deletions
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index a6c0732ee9..c87e9d09bf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -345,15 +345,15 @@
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
- android:name=".activity.snapshot.MapSnapshotterLocalStyleActivity"
- android:description="@string/description_map_snapshotter_local_style"
- android:label="@string/activity_map_snapshotter_local_style">
+ android:name=".activity.snapshot.MapSnapshotterLocalStyleActivity"
+ android:description="@string/description_map_snapshotter_local_style"
+ android:label="@string/activity_map_snapshotter_local_style">
<meta-data
- android:name="@string/category"
- android:value="@string/category_imagegenerator" />
+ android:name="@string/category"
+ android:value="@string/category_imagegenerator" />
<meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value=".activity.FeatureOverviewActivity" />
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
android:name=".activity.maplayout.DoubleMapActivity"
@@ -766,10 +766,22 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity" />
</activity>
+
+ <activity
+ android:name=".activity.style.DraggableMarkerActivity"
+ android:description="@string/description_draggable_marker"
+ android:label="@string/activity_draggable_maker">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_style" />
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity" />
+ </activity>
<activity
android:name=".activity.camera.GestureDetectorActivity"
- android:label="@string/activity_gesture_detector"
- android:description="@string/description_gesture_detector">
+ android:description="@string/description_gesture_detector"
+ android:label="@string/activity_gesture_detector">
<meta-data
android:name="@string/category"
android:value="@string/category_camera" />
@@ -789,14 +801,14 @@
android:name=".activity.espresso.EspressoTestActivity"
android:screenOrientation="portrait" />
<activity
- android:name=".activity.espresso.DeviceIndependentTestActivity"
- android:screenOrientation="portrait" />
+ android:name=".activity.espresso.DeviceIndependentTestActivity"
+ android:screenOrientation="portrait" />
<activity
android:name=".activity.style.FillExtrusionStyleTestActivity"
android:screenOrientation="portrait" />
<activity
android:name=".activity.render.RenderTestActivity"
- android:screenOrientation="landscape"/>
+ android:screenOrientation="landscape" />
<!-- Configuration Settings -->
<meta-data
android:name="com.mapbox.TestEventsServer"
@@ -811,4 +823,4 @@
<!-- android:value="true" /> -->
</application>
-</manifest>
+</manifest> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt
new file mode 100644
index 0000000000..48ebc2c154
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DraggableMarkerActivity.kt
@@ -0,0 +1,314 @@
+package com.mapbox.mapboxsdk.testapp.activity.style
+
+import android.graphics.PointF
+import android.os.Bundle
+import android.support.design.widget.Snackbar
+import android.support.v7.app.AppCompatActivity
+import android.view.MotionEvent
+import android.view.View
+import com.mapbox.android.gestures.AndroidGesturesManager
+import com.mapbox.android.gestures.MoveGestureDetector
+import com.mapbox.geojson.Feature
+import com.mapbox.geojson.FeatureCollection
+import com.mapbox.geojson.Point
+import com.mapbox.mapboxsdk.annotations.IconFactory
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.maps.MapView
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory.*
+import com.mapbox.mapboxsdk.style.layers.SymbolLayer
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
+import com.mapbox.mapboxsdk.testapp.R
+import kotlinx.android.synthetic.main.activity_draggable_marker.*
+
+/**
+ * An Activity that showcases how to make symbols draggable.
+ */
+class DraggableMarkerActivity : AppCompatActivity() {
+ companion object {
+ private const val sourceId = "source_draggable"
+ private const val layerId = "layer_draggable"
+ private const val markerImageId = "marker_icon_draggable"
+
+ private var latestId: Long = 0
+ fun generateMarkerId(): String {
+ if (latestId == Long.MAX_VALUE) {
+ throw RuntimeException("You've added too many markers.")
+ }
+ return latestId++.toString()
+ }
+ }
+
+ private val actionBarHeight: Int by lazy {
+ supportActionBar?.height ?: 0
+ }
+
+ private lateinit var mapboxMap: MapboxMap
+ private val featureCollection = FeatureCollection.fromFeatures(mutableListOf())
+ private val source = GeoJsonSource(sourceId, featureCollection)
+ private val layer = SymbolLayer(layerId, sourceId)
+ .withProperties(
+ iconImage(markerImageId),
+ iconAllowOverlap(true),
+ iconIgnorePlacement(true))
+
+ private var draggableSymbolsManager: DraggableSymbolsManager? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_draggable_marker)
+
+ mapView.onCreate(savedInstanceState)
+ mapView.getMapAsync { mapboxMap ->
+ this.mapboxMap = mapboxMap
+
+ // Setting up markers icon, source and layer
+ mapboxMap.addImage(markerImageId, IconFactory.getInstance(this).defaultMarker().bitmap)
+ mapboxMap.addSource(source)
+ mapboxMap.addLayer(layer)
+
+ // Add initial markers
+ addMarker(LatLng(52.407210, 16.924324))
+ addMarker(LatLng(41.382679, 2.181555))
+ addMarker(LatLng(51.514886, -0.112589))
+
+ // Initial camera position
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
+ LatLng(45.0, 8.0), 3.0
+ ))
+
+ mapboxMap.addOnMapClickListener {
+ // Adding a marker on map click
+ val features = mapboxMap.queryRenderedSymbols(it, layerId)
+ if (features.isEmpty()) {
+ addMarker(it)
+ } else {
+ // Displaying marker info on marker click
+ Snackbar.make(
+ mapView,
+ "Marker's position: %.4f, %.4f".format(it.latitude, it.longitude),
+ Snackbar.LENGTH_LONG)
+ .show()
+ }
+ }
+
+ draggableSymbolsManager = DraggableSymbolsManager(
+ mapView, mapboxMap, featureCollection, source, layerId, 0, actionBarHeight)
+
+ // Adding symbol drag listeners
+ draggableSymbolsManager?.addOnSymbolDragListener(object : DraggableSymbolsManager.OnSymbolDragListener {
+ override fun onSymbolDragStarted(id: String) {
+ draggedMarkerPositionTv.visibility = View.VISIBLE
+ Snackbar.make(
+ mapView,
+ "Marker drag started (%s)".format(id),
+ Snackbar.LENGTH_SHORT)
+ .show()
+ }
+
+ override fun onSymbolDrag(id: String) {
+ val point = featureCollection.features()?.find {
+ it.id() == id
+ }?.geometry() as Point
+ draggedMarkerPositionTv.text = "Dragged marker's position: %.4f, %.4f".format(point.latitude(), point.longitude())
+ }
+
+ override fun onSymbolDragFinished(id: String) {
+ draggedMarkerPositionTv.visibility = View.GONE
+ Snackbar.make(
+ mapView,
+ "Marker drag finished (%s)".format(id),
+ Snackbar.LENGTH_SHORT)
+ .show()
+ }
+ })
+ }
+ }
+
+ private fun addMarker(latLng: LatLng) {
+ featureCollection.features()?.add(
+ Feature.fromGeometry(Point.fromLngLat(latLng.longitude, latLng.latitude), null, generateMarkerId()))
+ source.setGeoJson(featureCollection)
+ }
+
+ override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
+ // Dispatching parent's touch events to the manager
+ draggableSymbolsManager?.onParentTouchEvent(ev)
+ return super.dispatchTouchEvent(ev)
+ }
+
+ /**
+ * A manager, that allows dragging symbols after they are long clicked.
+ * Since this manager lives outside of the Maps SDK, we need to intercept parent's motion events
+ * and pass them with [DraggableSymbolsManager.onParentTouchEvent].
+ * If we were to try and overwrite [AppCompatActivity.onTouchEvent], those events would've been
+ * consumed by the map.
+ *
+ * We also need to setup a [DraggableSymbolsManager.androidGesturesManager],
+ * because after disabling map's gestures and starting the drag process
+ * we still need to listen for move gesture events which map won't be able to provide anymore.
+ *
+ * @param mapView the mapView
+ * @param mapboxMap the mapboxMap
+ * @param symbolsCollection the collection that contains all the symbols that we want to be draggable
+ * @param symbolsSource the source that contains the [symbolsCollection]
+ * @param symbolsLayerId the ID of the layer that the symbols are displayed on
+ * @param touchAreaShiftX X-axis padding that is applied to the parent's window motion event,
+ * as that window can be bigger than the [mapView].
+ * @param touchAreaShiftY Y-axis padding that is applied to the parent's window motion event,
+ * as that window can be bigger than the [mapView].
+ * @param touchAreaMaxX maximum value of X-axis motion event
+ * @param touchAreaMaxY maximum value of Y-axis motion event
+ */
+ class DraggableSymbolsManager(mapView: MapView, private val mapboxMap: MapboxMap,
+ private val symbolsCollection: FeatureCollection,
+ private val symbolsSource: GeoJsonSource, private val symbolsLayerId: String,
+ private val touchAreaShiftX: Int = 0, private val touchAreaShiftY: Int = 0,
+ private val touchAreaMaxX: Int = mapView.width, private val touchAreaMaxY: Int = mapView.height) {
+
+ private val androidGesturesManager: AndroidGesturesManager = AndroidGesturesManager(mapView.context, false)
+ private var draggedSymbolId: String? = null
+ private val onSymbolDragListeners: MutableList<OnSymbolDragListener> = mutableListOf<OnSymbolDragListener>()
+
+ init {
+ mapboxMap.addOnMapLongClickListener {
+ // Starting the drag process on long click
+ draggedSymbolId = mapboxMap.queryRenderedSymbols(it, symbolsLayerId).firstOrNull()?.id()?.also { id ->
+ mapboxMap.uiSettings.setAllGesturesEnabled(false)
+ mapboxMap.gesturesManager.moveGestureDetector.interrupt()
+ notifyOnSymbolDragListeners {
+ onSymbolDragStarted(id)
+ }
+ }
+ }
+
+ androidGesturesManager.setMoveGestureListener(MyMoveGestureListener())
+ }
+
+ inner class MyMoveGestureListener : MoveGestureDetector.OnMoveGestureListener {
+ override fun onMoveBegin(detector: MoveGestureDetector): Boolean {
+ return true
+ }
+
+ override fun onMove(detector: MoveGestureDetector, distanceX: Float, distanceY: Float): Boolean {
+ if (detector.pointersCount > 1) {
+ // Stopping the drag when we don't work with a simple, on-pointer move anymore
+ stopDragging()
+ return true
+ }
+
+ // Updating symbol's position
+ draggedSymbolId?.also { draggedSymbolId ->
+ val moveObject = detector.getMoveObject(0)
+ val point = PointF(moveObject.currentX - touchAreaShiftX, moveObject.currentY - touchAreaShiftY)
+
+ if (point.x < 0 || point.y < 0 || point.x > touchAreaMaxX || point.y > touchAreaMaxY) {
+ stopDragging()
+ }
+
+ val latLng = mapboxMap.projection.fromScreenLocation(point)
+
+ symbolsCollection.features()?.indexOfFirst {
+ it.id() == draggedSymbolId
+ }?.also { index ->
+ symbolsCollection.features()?.get(index)?.also { oldFeature ->
+ val properties = oldFeature.properties()
+ val newFeature = Feature.fromGeometry(
+ Point.fromLngLat(latLng.longitude, latLng.latitude),
+ properties,
+ draggedSymbolId
+ )
+ symbolsCollection.features()?.set(index, newFeature)
+ symbolsSource.setGeoJson(symbolsCollection)
+ notifyOnSymbolDragListeners {
+ onSymbolDrag(draggedSymbolId)
+ }
+ return true
+ }
+ }
+ }
+
+ return false
+ }
+
+ override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) {
+ // Stopping the drag when move ends
+ stopDragging()
+ }
+ }
+
+ private fun stopDragging() {
+ mapboxMap.uiSettings.setAllGesturesEnabled(true)
+ draggedSymbolId?.let {
+ notifyOnSymbolDragListeners {
+ onSymbolDragFinished(it)
+ }
+ }
+ draggedSymbolId = null
+ }
+
+ fun onParentTouchEvent(ev: MotionEvent?) {
+ androidGesturesManager.onTouchEvent(ev)
+ }
+
+ private fun notifyOnSymbolDragListeners(action: OnSymbolDragListener.() -> Unit) {
+ onSymbolDragListeners.forEach(action)
+ }
+
+ fun addOnSymbolDragListener(listener: OnSymbolDragListener) {
+ onSymbolDragListeners.add(listener)
+ }
+
+ fun removeOnSymbolDragListener(listener: OnSymbolDragListener) {
+ onSymbolDragListeners.remove(listener)
+ }
+
+ interface OnSymbolDragListener {
+ fun onSymbolDragStarted(id: String)
+ fun onSymbolDrag(id: String)
+ fun onSymbolDragFinished(id: String)
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ mapView.onStart()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ mapView.onResume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ mapView.onPause()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ mapView.onStop()
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ mapView.onLowMemory()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ mapView.onDestroy()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle?) {
+ super.onSaveInstanceState(outState)
+ outState?.let {
+ mapView.onSaveInstanceState(it)
+ }
+ }
+}
+
+private fun MapboxMap.queryRenderedSymbols(latLng: LatLng, layerId: String): List<Feature> {
+ return this.queryRenderedFeatures(this.projection.toScreenLocation(latLng), layerId)
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_draggable_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_draggable_marker.xml
new file mode 100644
index 0000000000..2db336403d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_draggable_marker.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".activity.style.DraggableMarkerActivity">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@+id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <TextView
+ android:id="@+id/draggedMarkerPositionTv"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
index b515a4d3ae..bb4e0cfe6d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
@@ -69,4 +69,5 @@
<string name="description_hillshade">Example raster-dem source and hillshade layer</string>
<string name="description_heatmaplayer">Use HeatmapLayer to visualise earthquakes</string>
<string name="description_gesture_detector">Manipulate gestures detector\'s settings</string>
+ <string name="description_draggable_marker">Click to add a marker, long-click to drag</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
index 114ff38a0e..736c33fe34 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
@@ -69,4 +69,5 @@
<string name="activity_hillshade">Hillshade</string>
<string name="activity_heatmaplayer">Heatmap layer</string>
<string name="activity_gesture_detector">Gestures detector</string>
+ <string name="activity_draggable_maker">Draggable marker</string>
</resources> \ No newline at end of file