I am really struggling with google map util these days challenge after challenge and there is not good example or solution on the net.
This is my code:
#Override
protected void onBeforeClusterRendered(Cluster<ItemCluster> cluster,
MarkerOptions markerOptions) {
View marker = (getActivity()
.getLayoutInflater())
.inflate(R.layout.info_windows, null);
Bitmap bitmap = createDrawableFromView(
getActivity(), marker);
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));
}
The problem is before I send the view to this function to make a bitmap for marker, I try to set some data in my info_windows.xml which is included with some ImageViews and TextViews. But the app hangs, do you have any idea how to make this done?
Bitmap bitmap = createDrawableFromView(
getActivity(), marker);
I solve my problem by making an IconGenerator objectand then make the view from that this is how i did it:
first i made the object:
private final IconGenerator mClusterIconGenerator = new IconGenerator(getActivity().getApplicationContext());
and a view which contains our XML view file of our costum marker:
View markerIcon = getActivity().getLayoutInflater().inflate(R.layout.marker_icon, null);
then set the view on icongenerator:
mMarkerIconGenerator.setContentView(markerIcon);
then you need to initiate your imageview, textview, ... then set the values that you want to show inside your costum marker like this for ex:
mMarkerViento = (ImageView) clusterIcon.findViewById(R.id.viento);
then inside the ovveride method of:
#Override
protected void onBeforeClusterItemRendered(ItemCluster item, MarkerOptions markerOptions)
mMarkerViento.setImageResource(R.drawable.viento_ne2);
and at the end you generate your bitmap object from icon generator like this:
mMarkerIconGenerator.setBackground(TRANSPARENT_DRAWABLE); // set the background as transparent
Bitmap bitmap = mMarkerIconGenerator.makeIcon(); // make a bitmap object from the icon object
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap)); // set the bitmap as marker icon
good luck and tanx
Related
I need some help to improve the performance of my algorithm, I'm struggling for days and can't find a good solution.
Goal: My app need to show a marker for each airport in the world (~1k markers), and each marker must show the airport name.
What I did: For the marker, I created an RelativeLayout with the Icon and a TextView to populate the name of aiport.
Also, I wrote a class "AirportCluster" extending DefaultClusterRenderer and inside the overrode method onBeforeClusterItemRendered I just cast the layout to Bitmap so it can be rendered on the map
#Override
protected void onBeforeClusterItemRendered(AirportItem airportItem, MarkerOptions markerOptions) {
RelativeLayout customLayoutMarker = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.custom_airport_marker,null);
String tAirportName = airportItem.getAirport().getAirportName().toLowerCase();
tAirportName = Character.toUpperCase(tAirportName.charAt(0)) + tAirportName.substring(1);
TextView textLabelAirportMarker = (TextView) customLayoutMarker.findViewById(R.id.label_text_airport_marker);
textLabelAirportMarker.setText(tAirportName);
customLayoutMarker.setDrawingCacheEnabled(true);
customLayoutMarker.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
customLayoutMarker.layout(0,0, customLayoutMarker.getMeasuredWidth(), customLayoutMarker.getMeasuredHeight());
customLayoutMarker.buildDrawingCache(true);
Bitmap flagBitmap;
if ( mMemoryCache.get(tAirportName) == null){
flagBitmap = Bitmap.createBitmap(customLayoutMarker.getDrawingCache());
mMemoryCache.put(tAirportName,flagBitmap);
}else{
flagBitmap = mMemoryCache.get(tAirportName);
}
BitmapDescriptor markerAirportWithText = BitmapDescriptorFactory.fromBitmap(flagBitmap);
markerOptions.icon(markerAirportWithText);
//markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.airport_marker));
}
As we can see in the code, I'm trying to cache it on the memory as well, but this is not working that good.
All the markers are being added on the method onMapReady inside a loop for each airport in the list
for (Airport temp : fixedAirports) {
LatLng latLng = new LatLng(temp.getCityLat(), temp.getCityLng());
// create marker
MarkerOptions markerOptions = new MarkerOptions().position(latLng).title("Marker in" + temp.getCityName());
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.airport_marker));
AirportItem offsetItem = new AirportItem(temp.getCityLat(), temp.getCityLng());
offsetItem.setAirport(temp);
mClusterManager.addItem(offsetItem);
}
Issue: I also have a custom image for clustered airports, and when i try to zoom in/out sometimes it take to much to the clustered icon dismiss and show the marker item for an airport, sometimes the icon of the item even overlaps the clustered one, just like on the images below.
What I have to do to these animations (changing from clustered icon from single markers) be more fast and smooth??
Prepare BitmapDescriptors first in background (i.e. Coroutines viewModelScope or another thread or asynctask or Rxjava), then load them to ui. Dont draw anything inside your ClusterRenderer class. Doing so helped me a bit.
I started with the sample code CurrentPlaceDetailsOnMap from here:
CurrentPlaceDetailsOnMap
I changed it adding an image to the info view. and then I tried to load the image in the getInfoContents
#Override
public View getInfoContents(final Marker marker) {
// Inflate the layouts for the info window, title and snippet.
View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents, (FrameLayout)findViewById(R.id.map), false);
TextView title = ((TextView) infoWindow.findViewById(R.id.title));
title.setText(marker.getTitle());
TextView snippet = ((TextView) infoWindow.findViewById(R.id.snippet));
snippet.setText(marker.getSnippet());
final ImageView imageView = ((ImageView) infoWindow.findViewById(R.id.image));
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Bitmap bitmap = getBitmap(MapsActivityCurrentPlace.this, R.drawable.my_bitmap;
imageView.setImageBitmap(bitmap);
}
});
return infoWindow;
}
In the code above I used the Handleronly to simulate what happens when I load the image asynchronously by calling Places.GeoDataApi.getPlacePhotos.
The result is that the image is not shown.
If I call:
Bitmap bitmap = getBitmap(MapsActivityCurrentPlace.this, R.drawable.my_bitmap;
imageView.setImageBitmap(bitmap);
synchronously everything is fine.
It looks like google Map caches the view creating an image of the entire view. From the doc:
Note: The info window that is drawn is not a live view. The view is rendered as an image (using View.draw(Canvas)) at the time it is returned. This means that any subsequent changes to the view will not be reflected by the info window on the map. To update the info window later (for example, after an image has loaded), call showInfoWindow(). Furthermore, the info window will not respect any of the interactivity typical for a normal view such as touch or gesture events. However you can listen to a generic click event on the whole info window as described in the section below.
How can I set the image in the InfoView?
The only solution I found so far is to load the bitmap in advance and to store it in a cache and then assign the bitmap to the infoview.imageView synchronously.
But this means that I have to load the images in advance.
So I'm using a ClusterManagerto cluster my Markers, so that the user can have a better experience.
I have actually implemente Google's code, which I found here. Imagine now that my Marker icon is a ball. I want the background of the icon to be transparent, not white.
On Google's original tutorial they set a ImageView to the IconGenerator, like this:
public class MyClusterManagerRenderer extends DefaultClusterRenderer<ClusteredMarker> {
private final IconGenerator mIconGenerator;
private final ImageView mImageView;
public MyClusterManagerRenderer(Context context, GoogleMap googleMap,
ClusterManager<ClusteredMarker> clusterManager){
super(context, googleMap, clusterManager);
mIconGenerator = new IconGenerator(context);
mImageView = new ImageView(context);
mIconGenerator.setContentView(mImageView);
}
#Override
protected void onBeforeClusterItemRendered(ClusteredMarker item, MarkerOptions markerOptions) {
mImageView.setImageResource(item.iconPicture);
Bitmap icon = mIconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(item.user);
}
...
}
I have tried several ways to make my icon transparent, like calling:
mImageView.setBackgroundColor(Color.TRANSPARENT);
but without success. The only way I managed to find a solution is to directly attach my transparent image to the IconGenerator, like this:
mIconGenerator.setBackground(aContext.getResources().getDrawable(R.drawable.ball));
The downside of this approach is that a ImageView have some interesting methods that I would like to call, like setPadding, while the IconGenerator doesn't have that.
So, is there a way to make my icon transparent, using the ImageView?
Thank you,
The solution I found is this:
private static final Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
// Make the background of marker transparent
mIconGenerator.setBackground(TRANSPARENT_DRAWABLE);
mImageView.setBackgroundColor(null);
That will remove the background and make it transparent. :)
I think I have the same issue with the post on this link
Different markers show same infowindow content android google map v2
I am currently developing an app that integrates Google Maps v2 to allow users to take picture and automatically plotting a marker on the map.
I have a working InfoWindowAdapter but it seems that when I set a Bitmap as you can see below:
ImageView ivIcon = ((ImageView)myContentsView.findViewById(R.id.iconImg));
ivIcon.setImageBitmap(getResizedBitmap(myBitmap.getBp(),100,100));
When taking multiple pictures using my camera (which means it will have respective markers plotted on the map), the markers all share the same image, which is the latest image taken from the camera. I thought creating a Class by checking for difference in Bitmap object name would solve the problem but it did not.
It seems that when applying:
myMap.setInfoWindowAdapter(new MyInfoWindowAdapter());
it applies to all markers.
How do I go around doing it that each marker would have its own custom info window adapter?
Thanks!
======================================== EDIT =================================
I have an application that will allow users to take pictures which will also plot a marker on the map of the location of image capture. The marker will have a custom InfoWindow. I tried the solution but they are vague to me.
Do you mind explaining what did you do to your code such that doing:
googleMap.setInfoWindowAdapter(new InfoWindowAdapter());
will not affect all the markers on the map?
My current code for the CustomInfoBox is as follows:
class MyInfoWindowAdapter implements InfoWindowAdapter{
private final View myContentsView;
MyInfoWindowAdapter(){
myContentsView = getLayoutInflater().inflate(R.layout.custom_info_window, null);
}
#Override
public View getInfoContents(Marker marker) {
//TextView tvTitle = ((TextView)myContentsView.findViewById(R.id.title));
// tvTitle.setText(marker.getTitle());
TextView tvSnippet = ((TextView)myContentsView.findViewById(R.id.snippet));
tvSnippet.setText(marker.getSnippet());
ImageView ivIcon = ((ImageView)myContentsView.findViewById(R.id.badge));
ivIcon.setImageBitmap(getResizedBitmap(myBitmap.getBp(),100,100));
System.out.println("Custom Info Window: " + myBitmap.getBp());
return myContentsView;
}
#Override
public View getInfoWindow(Marker marker) {
// TODO Auto-generated method stub
return null;
}
}
When I call googleMap.setInfoWindowAdapter(MyInfoWindowAdapter);, all markers have the same layout and thus same picture (last picture taken by user!) which is not something that I want.
Any help will be much appreciated! thanks
My activity contains a MapFragment in a LinearLayout. I do the following
in onCreate:
I inflate this layout using setContentView in the onCreate method of
my activity.
Get a handle to the GoogleMap using getMap().
in onStart:
I get some place coordinates from an SQLite Database
add corresponding markers to the map
add these points to a LatLngBounds.Builder
animate the camera using newLatLngBounds(Builder.build(), 10)
According to maps api reference, I shouldn't call newLatLngBounds(LatLngBounds bounds, int padding) before making sure that the map has a size. I indeed get an IllegalStateException at this point. But what is the right method for waiting until the map has a size?
The solution by rusmus didn't work for me. I used this one instead:
map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
map.animateCamera(cameraUpdate);
}
});
If you know the map size, you can avoid waiting and move the camera before the map is displayed. We finally used the display size as an approximation of the map size (but you could find out the exact size if you want to be more precise):
final DisplayMetrics display = getResources().getDisplayMetrics();
final int padding = display.widthPixels / 20;
final CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(
boundsBuilder.build(), display.widthPixels, display.heightPixels, padding);
map.moveCamera(cameraUpdate);
I have succesfully used the following code in the past:
final LatLngBounds.Builder builder = new LatLngBounds.Builder();
final View mapView = fragment.getView();
final GoogleMap map = fragment.getMap():
//Add points to builder. And get bounds...
final LatLngBounds bounds = builder.build();
// Pan to see all markers in view.
// Cannot zoom to bounds until the map has a size.
if (mapView.getViewTreeObserver().isAlive()) {
mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50), 1500, null);
}
});
}
With the latest GoogleServices you can use MapFragment.getMapAsync.
Directly from the docs
Sets a callback object which will be triggered when the GoogleMap instance is ready to be used.