Android Question MarkerDragListener in GoogleMapExtras

Roger Daley

Well-Known Member
Licensed User
Longtime User
Hi All,

I am trying to get the correct process for MarkerDragListener operation when there are multiple markers.

In the code below there are two markers and originally I "Dimensioned" a DragListener for each marker with a corresponding Sub for each marker-drag. I found that only one sub was called, and called when either marker was dragged.

1. Is this correct or have I missed something?
2. If correct how do I differentiate the markers for different Subs or different actions within the Sub.

B4X:
Sub Map_Ready
  Log("map ready")
  gmap = mFragment.GetMap
  If gmap.IsInitialized = False Then
  ToastMessageShow("Error initializing map.", True)
  Else
  'Create BTSMarker Options including ICON
     Dim BTSOptions As MarkerOptions
     Dim BitmapDescriptor1 As BitmapDescriptor
     Dim BitmapDescriptorFactory1 As BitmapDescriptorFactory
  BTSOptions.Initialize
  BTSOptions.Draggable(True) 
  BTSOptions.Position2(BTSLat, BTSLng).Snippet("pkt").Title("BASE")
     BitmapDescriptor1=BitmapDescriptorFactory1.FromAsset("bts.png") 
     BTSOptions.Icon(BitmapDescriptor1)
     'Creat BTS marker and "Drag" listener
     BTSMarker=GoogleMapsExtras1.AddMarker(gmap, BTSOptions)
  Dim BTSDragListener As OnMarkerDragListener
  BTSDragListener.Initialize("BTSDragListener")
  GoogleMapsExtras1.SetOnMarkerDragListener(gmap,BTSDragListener)

  'Create LANDMarker Options including ICON
     Dim LANDOptions As MarkerOptions
     Dim BitmapDescriptor2 As BitmapDescriptor
     Dim BitmapDescriptorFactory2 As BitmapDescriptorFactory
  LANDOptions.Initialize
  LANDOptions.Draggable(True) 
  LANDOptions.Position2(LANDLat, LANDLng).Snippet("pkt").Title("LANDMARK")
     BitmapDescriptor2=BitmapDescriptorFactory2.FromAsset("landmark.png") 
     LANDOptions.Icon(BitmapDescriptor2)
     'Creat LANDMarker marker and "Drag" listener
     LANDMarker =GoogleMapsExtras1.AddMarker(gmap, LANDOptions)
  'Dim LANDDragListener As OnMarkerDragListener
  'LANDDragListener.Initialize("LANDDragListener")
  'GoogleMapsExtras1.SetOnMarkerDragListener(gmap,LANDDragListener)

  cp.Initialize2(MapLat, MapLng, MapZoom, MapBearing, 0 )
  gmap.AnimateCamera(cp)
     gmap.maptype = MapTypeInt
       'MapTypeInt: 1=Road Map, 2=Satellite, 3=Terrain, 4=Satellite with Labels
     gmap.GetUiSettings.CompassEnabled = False
  End If
End Sub

Sub BTSDragListener_DragEnd(Marker1 As Marker)
  'Log("DragEnd")
    Dim BTSLatLng As LatLng
    BTSLatLng = BTSMarker.Position
    BTSLat = BTSLatLng.Latitude
    BTSLng = BTSLatLng.Longitude
End Sub

Regards Roger
 

DonManfred

Expert
Licensed User
Longtime User
One time Marker1 is the BTSMarker the other time Marker1 is the LANDMarker.
If you can set a TAG when creating the markers (dont know) you can use this tag to differentiate them
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
In theory you can create a drag listener for each marker and when each marker is dragged only it's drag listener will raise events.
Both drag listeners should not raise events when a single marker is dragged.

Again in theory you could use a single drag listener to listen for drag events on both markers.
Then in the various drag listener _Drag??? event subs you'd need a way to identify which marker the event relates to.

I say 'in theory' as you may have found a bug in GoogleMapsExtras.

Can you put a simple project together that displays 2 draggable markers each with their own drag listener?
I'll give it a test and see what the problem is.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
I'll give it a test and see what the problem is.
I dont know whether it is already doable (dont use the lib) but if the Marker object can hold a "Tag" then it should be work without changes too.
The TO just need to use the Marker1.Tag to distinguish the calls in this case.
Just my 2 cent without working with markers actually
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Ooops my mistake - ignore what i posted in my last message.
The GoogleMap can have only a single drag listener set and you have to identify the dragged marker in the drag listener _Drag??? event subs.

So that means you need a way to identify the dragged marker.

@DonManfred a marker does have a unique String read only 'id', but it does not have a readable/writable Tag property like standard Views have.
Here is the documentation for the Marker getId() method:
https://developer.android.com/reference/com/google/android/gms/maps/model/Marker.html#getId()
The MarkerExtras object can be used to get this id, alternatively JavaObject could be used.

But rather than using the id i'd suggest keeping global references to each draggable marker and comparing the marker passed to the drag listener sub to these draggable markers:

B4X:
'	** i'll assume you dim BTSMarker and LANDMarker as Global objects **

Sub Map_Ready
  Log("map ready")
  gmap = mFragment.GetMap
  If gmap.IsInitialized = False Then
  ToastMessageShow("Error initializing map.", True)
  Else
  'Create BTSMarker Options including ICON
     Dim BTSOptions As MarkerOptions
     Dim BitmapDescriptor1 As BitmapDescriptor
     Dim BitmapDescriptorFactory1 As BitmapDescriptorFactory
  BTSOptions.Initialize
  BTSOptions.Draggable(True) 
  BTSOptions.Position2(BTSLat, BTSLng).Snippet("pkt").Title("BASE")
     BitmapDescriptor1=BitmapDescriptorFactory1.FromAsset("bts.png") 
     BTSOptions.Icon(BitmapDescriptor1)
     'Creat BTS marker
     BTSMarker=GoogleMapsExtras1.AddMarker(gmap, BTSOptions)

  'Create LANDMarker Options including ICON
     Dim LANDOptions As MarkerOptions
     Dim BitmapDescriptor2 As BitmapDescriptor
     Dim BitmapDescriptorFactory2 As BitmapDescriptorFactory
  LANDOptions.Initialize
  LANDOptions.Draggable(True) 
  LANDOptions.Position2(LANDLat, LANDLng).Snippet("pkt").Title("LANDMARK")
     BitmapDescriptor2=BitmapDescriptorFactory2.FromAsset("landmark.png") 
     LANDOptions.Icon(BitmapDescriptor2)
     'Creat LANDMarker marker
     LANDMarker =GoogleMapsExtras1.AddMarker(gmap, LANDOptions)

  ' create DragListener
  Dim DragListener1 As OnMarkerDragListener
  DragListener1.Initialize("DragListener1")
  GoogleMapsExtras1.SetOnMarkerDragListener(gmap,DragListener1)
  
  cp.Initialize2(MapLat, MapLng, MapZoom, MapBearing, 0 )
  gmap.AnimateCamera(cp)
     gmap.maptype = MapTypeInt
       'MapTypeInt: 1=Road Map, 2=Satellite, 3=Terrain, 4=Satellite with Labels
     gmap.GetUiSettings.CompassEnabled = False
  End If
End Sub

Sub DragListener1_DragEnd(Marker1 As Marker)
  'Log("DragEnd")
  Select Marker1
  	Case BTSMarker
   	  Dim BTSLatLng As LatLng
  	  BTSLatLng = BTSMarker.Position
  	  BTSLat = BTSLatLng.Latitude
      BTSLng = BTSLatLng.Longitude
  	Case LANDMarker
  	  ' do something when LANDMarker is dragged
  End Select
End Sub
 
Upvote 0

Roger Daley

Well-Known Member
Licensed User
Longtime User
Thanks for the feedback guys

Warwound your explanation was spot on. As I already keep lat and long of each marker it is easy to check which has moved.
The important thing is I will be doing it correctly and not just guessing.

Many thanks Roger
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
The important thing is I will be doing it correctly and not just guessing.
he MarkerExtras object can be used to get this id, alternatively JavaObject could be used.
so i guess this should help here... After creating a marker; get the id of it and hold this info. Use this info then to identify the marker used in the raised event
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
so i guess this should help here... After creating a marker; get the id of it and hold this info. Use this info then to identify the marker used in the raised event

That's possible but means you now have 2 global references: a reference to the marker id and a reference to the marker itself.
My code example shows that if you have a reference to the marker there's no real need to keep a reference to the marker id too.

Ideally the GoogleMap would have a method such as:

GetMarkerById(MarkerId As String) As Marker

But it doesn't - there's requests for Google to implement such a method but currently no such method.

You could create a Map where the Map keys are marker id values and the Map values are marker objects.
It depends on how many marker objects you need to reference - whether it's worth creating a Map or simply keeping a handful of direct references:

B4X:
' in Globals
Dim BTSMarker As Marker
Dim LANDMarker As Marker

OR

B4X:
' in Globals
Dim MarkersById As Map
 
Upvote 0

eurojam

Well-Known Member
Licensed User
Longtime User
I usually use a map where the marker is the key and a customtype holds the values, so i have a complete dataset for each marker.
B4X:
Type POI (id As Long, station As String, teaser As String, lat As Double, lon As Double, audio As Int, video As Int, image As Int, aMarker1 As Marker, aMarker2 As Marker)
Dim Markers1 As Map
Dim Markers2 As Map
in this example I am using two markers. Marker2 is shown after the marker was clicked (an open or closed treasure box for example)

when a marker event like the drag event is fired, or any other event with marker:
B4X:
Sub OnInfoWindowClickListener1_click(Marker1 As Marker)
    Dim p As POI
   If Markers1.Get(Marker1) = Null Then
      p = Markers2.Get(Marker1)
   Else
      p = Markers1.Get(Marker1)
   End If 
   'do something with p
End Sub

Hope this helps...o_O
 
Upvote 0

Roger Daley

Well-Known Member
Licensed User
Longtime User
I've tried a few ways and the more I looked, the more Warwounds Select/Case [Post #5] became the best choice for my use. The code I have used is basically Warwounds.
The other ideas may be preferable for a different project. The info in this thread should be of great help to the next person question dragging markers.

Regards Roger:)
 
Upvote 0
Top