B4A Library GoogleMapsExtras

GoogleMapsExtras is an ongoing project to implement more of the Google Maps Android v2 classes in Basic4Android.

Currently the library allows you to create these objects:

Tutorials for each object will be uploaded to the Google Maps Android v2 tutorial thread.

Martin.
 

Attachments

  • GoogleMapsExtras_v1_71.zip
    59.6 KB · Views: 2,693
  • MapsForgeTileProvider_v1.01.zip
    173.1 KB · Views: 2,567
  • GoogleMapsExtras_v2_0_library_files.zip
    82.5 KB · Views: 2,991
Last edited:

westingenieria

Active Member
Licensed User
Longtime User
Can you help me with this error? I get this error in Release, Debug and Relase(ofuscated) mode:

B4X:
Parsing code.                           0.01
Compiling code.                         0.05
Compiling layouts code.                 0.01
Generating R file.                      0.31
Compiling generated Java code.          Error
B4A line: 62
GoogleMapsExtras1.SetOnMarkerDragListener(mGmap, OnMarkerDragListener1)
javac 1.7.0_02
src\b4a\example\main.java:338: error: package com.google.android.gms.maps does not exist
_googlemapsextras1.SetOnMarkerDragListener((com.google.android.gms.maps.GoogleMap)(mostCurrent._mgmap.getObject()),(com.google.android.gms.maps.GoogleMap.OnMarkerDragListener)(_onmarkerdraglistener1.getObject()));
                                                                       ^
1 error
 

Ignamun

New Member
Licensed User
Longtime User
mapclick event

Hello,

Is there any plan to include mapclick to this library?

Thank you!
 

warwound

Expert
Licensed User
Longtime User

warwound

Expert
Licensed User
Longtime User
I think removing and creating a new Marker is your only option.

The flightradar map uses the javascript Google Maps API which has many more features including the ability to change a Marker Icon on the fly - after it has been created.

In thoery you could use the javascript Google Maps API in a WebView in your B4A project, not something i'd be keen to do - the performance would likely be poor and it'd not look as 'professional' as a proper MapView.

I was going to suggest my OSMDroid library as another solution but having a look at the reference i can't be sure that OSMDroid allows you to change a Marker Icon after it has been created.
If using OSMDroid instead of Google Maps is something you would consider then let me know and i'll check through the source code and see if it's possible to change a Marker Icon without having to recreate the Marker.

Martin.
 

Wembly

Member
Licensed User
Longtime User
Hi

I'm attempting to use the AnimateToBounds method to zoom the map to show the entire route traveled in my app, but it only seems to work in debug mode if I step through the code, but running the app in normal release I get the following error:

"An error has occurred in sub map_map_ready(java line: 421)
java.lang.illegalStateException: Map size should not be 0. Most likely, layout has not yet occurred for the map view."

The AnimateToBound method is attempting to use the map before it has been built with data from google. Any suggestions how to resolve this or does anyone have any examples of using AnimateToBounds?
 

warwound

Expert
Licensed User
Longtime User
Hi there.

This seems to be a problem many developers have faced:

http://stackoverflow.com/questions/...emap-animatecamera-crash-after-ongloballayout

http://stackoverflow.com/questions/...h-cameraupdatefactory-newlatlngbounds-crashes

Until the GoogleMap has been fully rendered it has no layout - it has dimensions of 0px by 0px.

A possible solution would be to use the GoogleMap MoveCamera method to move the map to an arbitary position.
Once MoveCamera has executed the MapFragment will raise an event CameraChange (Position As CameraPosition), and you should now be able to use the GoogleMapsExtras AnimateToBounds method.
(The map should have dimensions after the CameraChange event has been raised).

That's not a perfect solution of course.

Can you tell me which particular line of code causes the illegalStateException?
Does the exception get raised when you initialize a LatLngBounds object?
Or is the exception raised when you call the GoogleMapsExtras AnimateToBounds method?

If the exception occurs in AnimateToBounds then i could probably update that method...
I could update it so that it tries to animate the map to the bounds, if an exception occurs then the method catches the exception, waits until the map has layout and then animates the map to the bounds.

Martin.
 

Wembly

Member
Licensed User
Longtime User
Hi Martin

Thanks for the prompt response.

The error occurs when calling the AnimateToBounds method.

It would be good if this could be fixed in the method but will try the CameraMove work around as you suggest in the meantime.

Thanks again!
 

warwound

Expert
Licensed User
Longtime User
Well updating the AnimateToBounds method so that it (automatically) handles cases where the GoogleMap has no layout has proved pretty much impossible.
There's no way to get the required reference to the View that holds all elements of the map, and without that reference there's no way to attach a listener to the View.
So no way to listen until the View has layout before calling AnimateToBounds.

The other solution suggested is to pass the map width and height to the method instead of presuming that the method can get the map width and height.
So this is the existing AnimateToBounds (java) method:

B4X:
  public static void AnimateToBounds(GoogleMap GoogleMap1, com.google.android.gms.maps.model.LatLngBounds LatLngBounds1, int Padding){
     GoogleMap1.animateCamera(CameraUpdateFactory.newLatLngBounds(LatLngBounds1, Padding));
   }

And a new AnimateToBounds2 method passes the map width and height:

B4X:
  public static void AnimateToBounds2(GoogleMap GoogleMap1, com.google.android.gms.maps.model.LatLngBounds LatLngBounds1, int Width, int Height, int Padding){
     GoogleMap1.animateCamera(CameraUpdateFactory.newLatLngBounds(LatLngBounds1, Width, Height, Padding));
   }

AnimateToBounds would be used when you are sure that the map has layout, otherwise AnimateToBounds2 would be used.

I've recompiled GoogleMapsExtras with the new method, can you give it a try?

I've also added another new (unrelated) method:
Takes a snapshot of the map.
On completion raises the event SnapshotReady(Bitmap1 As Bitmap).
Snapshot(GoogleMap1 As GoogleMap, EventName As String)

I've not yet tested this new Snapshot method, there were a few posts on the forum a month or so back where members were trying to capture the map view, hopefully this new method will work as desired...

Martin.

[edit]I've now uploaded the update as an official update, version 1.35 of GoogleMapsExtras is attached to the first post in this thread.[/edit]
 
Last edited:

warwound

Expert
Licensed User
Longtime User
GoogleMapsExtras updated to version 1.35

This update adds two new methods to the GoogleMapsExtras object:

GoogleMapsExtras
Events:

  • SnapshotReady (Bitmap1 As Bitmap)
Methods:
  • AnimateToBounds2 (GoogleMap1 As GoogleMap, LatLngBounds1 As LatLngBounds, Width As Int, Height As Int, Padding As Int)
    Adjust and animate the map center and zoom level so that it fully contains the LatLngBounds.
    Padding is defined in units of pixels.
    Width and Height should define the dimensions of the GoogleMap.
  • Snapshot (GoogleMap1 As GoogleMap, EventName As String)
    Takes a snapshot of the map.
    On completion raises the event SnapshotReady(Bitmap1 As Bitmap).
The new Snapshot method takes a snapshot of the current map.
The event SnapshotReady is raised when the snapshot has been created, the snapshot passed to your event handling Sub as a Bitmap.
IMPORTANT: In order to use the new Snapshot method you must ensure that your b4a additional libraries folder contains the latest version of google-play-services.jar.
Run the Android SDK Manager utility and check whether or not you have the latest version, i have tested with version 10 of the Google Play services library
.

Your attention is drawn to the notes from the GoogleMap API reference:

Note: Images of the map must not be transmitted to your servers, or otherwise used outside of the application. If you need to send a map to another application or user, send data that allows them to reconstruct the map for the new user instead of a snapshot.

The new AnimateToBounds2 method is an attempt to work around a problem where AnimateToBounds fails and causes an IllegalStateException to be raised.
  • If you call AnimateToBounds before the map has been fully initialized/rendered then the map actually has dimensions of 0 pixels by 0 pixels, attempting to fit the map to a LatLngBounds will cause such an exception.
    (AnimateToBounds tries to get the size of the map and fails).
  • Calling AnimateToBounds2 (manually) passes the map size to the method.
    So instead of the method being unable to determine the map size, you pass the map size and in theory the 'animate to bounds' will succeed - no exception.

I have not properly tested this new method, i am awaiting another member to test it.

Version 1.35 of GoogleMapsExtras is attached to the first post in this thread.

Martin.

[edit]An example showing how to use the new Snapshot method can be found here: http://www.b4x.com/android/forum/threads/google-maps-android-v2-tutorial.24415/page-11#post-186961[/edit]
 
Last edited:
  • Like
Reactions: jhT

Wembly

Member
Licensed User
Longtime User
Just tested the new AnimateToBounds2 method within my app which zooms to show entire route traveled and so far seems to work perfectly - no issues found.

Thank you Martin for this update!
 

warwound

Expert
Licensed User
Longtime User
GoogleMapsExtras updated to version 1.36

This update adds support for both Indoor Maps and Traffic Layer:

  • IsIndoorEnabled (GoogleMap1 As GoogleMap) As Boolean
    Returns whether indoor maps are currently enabled.
  • IsTrafficEnabled (GoogleMap1 As GoogleMap) As Boolean
    Returns whether the map is drawing traffic data.
  • SetIndoorEnabled (GoogleMap1 As GoogleMap, Enabled As Boolean) As Boolean
    Sets whether indoor maps should be enabled.
  • SetTrafficEnabled (GoogleMap1 As GoogleMap, Enabled As Boolean)
    Toggles the traffic layer on or off.

These two layers are not available everywhere.
A list of places where indoor maps are currently available can be found HERE, and a map showing where the traffic layer is available can be found HERE.

Version 1.36 of GoogleMapsExtras is attached to the first post in this thread.

Martin.

[edit]An example project showing these new methods can be found here: http://www.b4x.com/android/forum/threads/google-maps-android-v2-tutorial.24415/page-11#post-187825[/edit]
 
Last edited:

rboeck

Well-Known Member
Licensed User
Longtime User
A short question: what's the problem, if we enable indoor and traffic all the time?
 

warwound

Expert
Licensed User
Longtime User
A short question: what's the problem, if we enable indoor and traffic all the time?

I think there's no problem whatsoever.
These are just additional layers that can be enabled if required - having them enabled will presumably just use a little bandwidth to download the layers.

Google could have hardcoded the map to always show these layers but instead have given developers the option to enable or disable them as desired.

One thing to note from the documentation for setIndoorEnabled:
Currently, indoor maps can only be shown on one map at a time and by default, this is the first map added to your application. To enable indoor maps on another map, you must first disable indoor maps on the original map. If you try to enable indoor maps when it is enabled on another map, nothing will happen and this will return false. When Indoor is not enabled for a map, all methods related to indoor will return null, or false.

So if your app displays more than one map at a time you'd not be able to display indoor maps on both.

Martin.
 
Top