I would like to show the custom marker to google map and cluster them. The marker contains a ImageView that will shows the avatar that is downloaded from network. Here is my target:
Everythings are OK, however, when I implemented the Google Maps Android Marker Clustering Utility, the ImageView shows the same avatar (sometime two wrong avatars).
Here is my custom MarkerRender:
public class MarkerRender extends DefaultClusterRenderer<Image> {
private static final String TAG = MarkerRender.class.getSimpleName();
private IconGenerator clusterGenerator;
private IconGenerator markerGenerator;
private ImageView mImgMarkerThumbnail;
private ImageView mImgMarkerClusterThumbnail;
private TextView txtSizeCluster;
private Activity activity;
private Bitmap mask, background;
private AtomicInteger imageDownloadCounter;
private int totalItem;
private ImageSize imageSize;
public MarkerRender(FragmentActivity activity, GoogleMap mMap, ClusterManager<Image> mClusterManager) {
super(activity, mMap, mClusterManager);
this.activity = activity;
imageDownloadCounter = new AtomicInteger(0);
mask = BitmapFactory.decodeResource(activity.getResources(),
R.drawable.annotation_behind);
background = BitmapFactory.decodeResource(activity.getResources(),
R.drawable.annotation_behind);
setUpClusterIcon();
setUpMarker();
}
private void setUpClusterIcon() {
clusterGenerator = new IconGenerator(activity);
View clusterView = activity.getLayoutInflater().inflate(R.layout.custom_marker_cluster, null);
txtSizeCluster = (TextView) clusterView.findViewById(R.id.tv_number_marker);
mImgMarkerClusterThumbnail = (ImageView) clusterView.findViewById(R.id.img_load);
clusterGenerator.setContentView(clusterView);
clusterGenerator.setBackground(null);
}
private void setUpMarker() {
markerGenerator = new IconGenerator(activity);
View markerView = activity.getLayoutInflater().inflate(R.layout.custom_marker, null);
mImgMarkerThumbnail = (ImageView) markerView.findViewById(R.id.img_load);
markerGenerator.setContentView(markerView);
markerGenerator.setBackground(null);
}
#Override
protected void onBeforeClusterItemRendered(final Image image, final MarkerOptions markerOptions) {
initImageSizeIfNeed();
Bitmap icon = markerGenerator.makeIcon();
PFLogManager.INSTANCE.logE(TAG, "maken icon: " + icon.hashCode());
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
icon.recycle();
}
#Override
protected void onClusterItemRendered(final Image image, Marker marker) {
super.onClusterItemRendered(image, marker);
ImageLoader.getInstance().loadImage(image.getMapImageLink(), imageSize,
new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
Bitmap croppedBitmap = Helpers.makeCroppedBitmap(loadedImage, background, mask);
mImgMarkerThumbnail.setImageBitmap(croppedBitmap);
}
});
}
#Override
protected void onBeforeClusterRendered(Cluster<Image> cluster, MarkerOptions markerOptions) {
initImageSizeIfNeed();
Bitmap icon = clusterGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
icon.recycle();
}
#Override
protected void onClusterRendered(Cluster<Image> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
ArrayList<Image> list = new ArrayList<>(cluster.getItems());
setTextNumberMarker(cluster);
String urlFirstImage = list.get(0).getMapImageLink();
ImageLoader.getInstance().loadImage(urlFirstImage, imageSize,
new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
final Bitmap croppedBitmap = Helpers.makeCroppedBitmap(loadedImage, background, mask);
mImgMarkerClusterThumbnail.setImageBitmap(croppedBitmap);
}
});
}
private void loadClusterThumbnail(String url) {
}
private void setTextNumberMarker(Cluster<Image> cluster) {
int size = cluster.getSize();
if (size > 99) {
txtSizeCluster.setText("99+");
} else {
txtSizeCluster.setText(String.valueOf(cluster.getSize()));
}
}
#Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
return cluster.getSize() > 1;
}
}
I've guess that the issue is I use only one ImageView to show those avatar, so I try to use unique ImageView for each marker (by inflat new one from xml every time needed), but the result is they are all show the blank marker (just the background and there is no avatar).
I've resolved it myself. My solution is use the Marker.setIcon() method after the image is downloaded from netword or got from cache. I dont use the ImageView anymore.
So, i modified the above MarkerRender class:
The setUpClusterIcon() method:
private void setUpClusterIcon() {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(markerWidth, markerHeight);
ImageView marker = new ImageView(activity);
marker.setLayoutParams(params);
clusterGenerator = new IconGenerator(activity);
clusterGenerator.setContentView(marker);
clusterGenerator.setBackground(null);
}
And the onClusterItemRendered() method:
protected void onClusterItemRendered(final Image image, final Marker marker) {
super.onClusterItemRendered(image, marker);
ImageLoader.getInstance().loadImage(image.getMapImageLink(), imageSize,
new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
Bitmap croppedBitmap = Helpers.makeClusterItemBitmap(background, loadedImage, mask);
try {
marker.setIcon(BitmapDescriptorFactory.fromBitmap(croppedBitmap));
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
Also the makeClusterItemBitmap helper method:
public static Bitmap makeClusterItemBitmap(Bitmap background, Bitmap original, Bitmap mask) {
Bitmap croppedOriginal = makeCroppedBitmap(original, mask);
Bitmap result = Bitmap.createBitmap(background.getWidth(), background.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas mCanvas = new Canvas(result);
croppedOriginal = Bitmap.createScaledBitmap(croppedOriginal, croppedOriginal.getWidth() - 20, croppedOriginal.getHeight() - 20, true);
mCanvas.drawBitmap(background, 0, 0, null);
mCanvas.drawBitmap(croppedOriginal, 10, 10, null);
return result;
}
public static Bitmap makeCroppedBitmap(Bitmap original, Bitmap mask) {
original = Bitmap.createScaledBitmap(original, mask.getWidth(),
mask.getHeight(), true);
Bitmap result = Bitmap.createBitmap(original.getWidth(), original.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas mCanvas = new Canvas(result);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas.drawBitmap(original, 0, 0, null);
mCanvas.drawBitmap(mask, 0, 0, paint);
paint.setXfermode(null);
return result;
}
Done, finish three nightmare researchingdays days :P
However, this approach leads new issue: the performance. Cause by drawing new bitmap with many layers, the map is laggy a bit. I'm thinking in improving this :)
Any sugguestion are appriciate :D
Related
I want to implement a drag-and-drop functionality within a recyclerview. Everything goes perfectly until I want to customize the looks of the view being dragged (not the view from which the drag event starts, I want to modify the "shadow" and keep the original view the same).
I've tried to make a bitmap out of the view being passed, but the end result is both the original item and the Shadow are modified AND the original view loses its position on the list... WTF
Here is my code:
public class ImageDragShadowBuilder extends View.DragShadowBuilder {
private Bitmap shadow;
LinearLayout linearLayout;
private ImageDragShadowBuilder() {
super();
}
public static ImageDragShadowBuilder create(Context context, View view) {
ImageDragShadowBuilder builder = new ImageDragShadowBuilder();
builder.linearLayout = (LinearLayout) view.findViewById(R.id.metric_item);
builder.linearLayout.setBackgroundResource(R.drawable.background_item_dragging);
builder.shadow = createBitmapFromView(builder.linearLayout);
return builder;
}
public View getLayout() {
return linearLayout;
}
private static Bitmap createBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
v.layout(0, 0, v.getWidth(), v.getHeight());
v.draw(new Canvas(b));
return b;
}
#Override
public void onDrawShadow(Canvas canvas) {
canvas.drawBitmap(shadow, 0, 0, null);
}
#Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
shadowSize.x = shadow.getWidth();
shadowSize.y = shadow.getHeight();
shadowTouchPoint.x = shadowSize.x / 2;
shadowTouchPoint.y = shadowSize.y / 2;
}
}
Any ideas?
I think that there are 2 problems :
Setting the background on the view attached to the RecyclerView affects the original item and the shadow
Triggering a layout changes the item's children position
Basically you can use the original view, but you should never modify it. A slightly modified version of your shadow builder could be :
public static ImageDragShadowBuilder create(Context context, View view) {
ImageDragShadowBuilder builder = new ImageDragShadowBuilder();
builder.linearLayout = (LinearLayout) view.findViewById(R.id.metric_item);
// do not change the original view
// we will draw the background directly later
// builder.linearLayout.setBackgroundResource(R.drawable.background_item_dragging);
builder.shadow = createBitmapFromView(builder.linearLayout);
return builder;
}
private static Bitmap createBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
// do not change the original view
// v.layout(0, 0, v.getWidth(), v.getHeight());
Canvas c = new Canvas(b);
// draw the background
Drawable background = v.getContext().getDrawable(R.drawable.background_item_dragging);
background.setBounds(0, 0, b.getWidth(), b.getHeight());
background.draw(c);
v.draw(c);
return b;
}
I am using android Espresso. I would like to know how I can check if the drawable being used on a view is the same as what should be used as stated in the specs. I am trying to compare the ConstantStates of the drawable use on the view, and the one in the Resources, but I am not getting anywhere.
Is there a way to do this? Or is this check entirely not needed when it comes to automated testing?
For comparing two images I already used this code:
public class ImageComparator {
public static Matcher<View> withImageResource(final int imageResourceId) {
return new TypeSafeMatcher<View>() {
#Override
public void describeTo(Description description) {
description.appendText("with drawable from resource id: " + imageResourceId);
}
#Override
public boolean matchesSafely(View view) {
Drawable actualDrawable = ((ImageView) view).getDrawable();
final Drawable correctDrawable = view.getResources().getDrawable(imageResourceId);
if (actualDrawable == null) {
return correctDrawable == null;
}
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return areImagesTheSameAfterSdk21(actualDrawable, correctDrawable);
} else {
return areImagesTheSameBeforeSdk21(actualDrawable, correctDrawable);
}
}
};
}
protected static boolean areImagesTheSameBeforeSdk21(Drawable actualDrawable,
Drawable correctDrawable) {
Drawable.ConstantState actualDrawableConstantState = actualDrawable.getConstantState();
Drawable.ConstantState correctDrawableConstantState = correctDrawable.getConstantState();
return actualDrawableConstantState.equals(correctDrawableConstantState);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
protected static boolean areImagesTheSameAfterSdk21(Drawable actualDrawable,
Drawable correctDrawable) {
Bitmap correctBitmap = drawableToBitmap(correctDrawable);
Bitmap actualBitmap = drawableToBitmap(actualDrawable);
return correctBitmap.sameAs(actualBitmap);
}
private static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap bitmap = Bitmap
.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
Hope it will help
I am using MapCustomClustering to show images on the map. The Cluster Icon also shows the number of items in the cluster but it doesn't show in mine. I am loading data from Parse cloud. The example one renders cluster.getSize() but in mine it doesn't work.
#Override
protected void onBeforeClusterRendered(final Cluster<MapPosts> cluster, final MarkerOptions markerOptions) {
// Draw multiple people.
// Note: this method runs on the UI thread. Don't spend too much time in here (like in this example).
final List<Drawable> profilePhotos = new ArrayList<>(Math.min(4, cluster.getSize()));
final int width = mDimension;
final int height = mDimension;
int i = 0;
for (MapPosts p : cluster.getItems()) {
// Draw 4 at most.
i++;
Picasso.with(getApplicationContext())
.load(String.valueOf(p.profilePhoto))
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
drawable.setBounds(0, 0, width, height);
profilePhotos.add(drawable);
MultiDrawable multiDrawable = new MultiDrawable(profilePhotos);
multiDrawable.setBounds(0, 0, width, height);
mClusterImageView.setImageDrawable(multiDrawable);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
if (profilePhotos.size() == 4) break;
}
}
I found the answear :-) -> Make sure you have some TextView like this in your icon style! The IMPORTANT POINT is you name it "text" !!!
<TextView
**android:id="#id/text"**
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/holo_green_dark"
android:paddingLeft="#dimen/custom_profile_padding"
android:paddingRight="#dimen/custom_profile_padding"
android:layout_gravity="center"
android:alpha=".8"/>
I want to chnage the color of marker that are not being clustered and shown as an individual marker on map.
I tried code from a demo project from android but I am not able get it working in my code.I change icon for one marker it chnaged everywhere and cluster disappears.
Here is the original code which I was trying to use
(Only relevant part from the code)
public class CustomMarkerClusteringDemoActivity extends BaseDemoActivity implements ClusterManager.OnClusterClickListener<Person>, ClusterManager.OnClusterInfoWindowClickListener<Person>, ClusterManager.OnClusterItemClickListener<Person>, ClusterManager.OnClusterItemInfoWindowClickListener<Person> {
private ClusterManager<Person> mClusterManager;
private Random mRandom = new Random(1984);
/**
* Draws profile photos inside markers (using IconGenerator).
* When there are multiple people in the cluster, draw multiple photos (using MultiDrawable).
*/
private class PersonRenderer extends DefaultClusterRenderer<Person> {
private final IconGenerator mIconGenerator = new IconGenerator(getApplicationContext());
private final IconGenerator mClusterIconGenerator = new IconGenerator(getApplicationContext());
private final ImageView mImageView;
private final ImageView mClusterImageView;
private final int mDimension;
public PersonRenderer() {
super(getApplicationContext(), getMap(), mClusterManager);
View multiProfile = getLayoutInflater().inflate(R.layout.multi_profile, null);
mClusterIconGenerator.setContentView(multiProfile);
mClusterImageView = (ImageView) multiProfile.findViewById(R.id.image);
mImageView = new ImageView(getApplicationContext());
mDimension = (int) getResources().getDimension(R.dimen.custom_profile_image);
mImageView.setLayoutParams(new ViewGroup.LayoutParams(mDimension, mDimension));
int padding = (int) getResources().getDimension(R.dimen.custom_profile_padding);
mImageView.setPadding(padding, padding, padding, padding);
mIconGenerator.setContentView(mImageView);
}
#Override
protected void onBeforeClusterItemRendered(Person person, MarkerOptions markerOptions) {
// Draw a single person.
// Set the info window to show their name.
mImageView.setImageResource(person.profilePhoto);
Bitmap icon = mIconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(person.name);
}
#Override
protected void onBeforeClusterRendered(Cluster<Person> cluster, MarkerOptions markerOptions) {
// Draw multiple people.
// Note: this method runs on the UI thread. Don't spend too much time in here (like in this example).
List<Drawable> profilePhotos = new ArrayList<Drawable>(Math.min(4, cluster.getSize()));
int width = mDimension;
int height = mDimension;
for (Person p : cluster.getItems()) {
// Draw 4 at most.
if (profilePhotos.size() == 4) break;
Drawable drawable = getResources().getDrawable(p.profilePhoto);
drawable.setBounds(0, 0, width, height);
profilePhotos.add(drawable);
}
MultiDrawable multiDrawable = new MultiDrawable(profilePhotos);
multiDrawable.setBounds(0, 0, width, height);
mClusterImageView.setImageDrawable(multiDrawable);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
Can anyone simplify or explain the process how this works
This is the code for onBeforeClusterRendered which I found after decompiling DefaultClusterRender class
protected void onBeforeClusterRendered(Cluster<T> cluster, MarkerOptions markerOptions) {
int bucket = this.getBucket(cluster);
BitmapDescriptor descriptor = (BitmapDescriptor)this.mIcons.get(bucket);
if(descriptor == null) {
this.mColoredCircleBackground.getPaint().setColor(this.getColor(bucket));
descriptor = BitmapDescriptorFactory.fromBitmap(this.mIconGenerator.makeIcon(this.getClusterText(bucket)));
this.mIcons.put(bucket, descriptor);
}
markerOptions.icon(descriptor);
}
But I can't understand a thing from this.
I work with Google Map cluster using Android-map-utils library from google. In my case, I use Glide to load image from URL:
#Override
protected void onBeforeClusterItemRendered(final FeedsModel feedsModel, final MarkerOptions markerOptions) {
// Draw a single person.
// Set the info window to show their name.
Glide
.with(mActivity.getApplicationContext())
.load(feedsModel.getImages().getThumbnail().getUrl())
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new SimpleTarget<GlideDrawable>() {
#Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
mImageView.setImageDrawable(resource);
Bitmap icon = mIconGenerator.makeIcon();
Marker markerToChange = null;
for (Marker marker : mClusterManager.getMarkerCollection().getMarkers()) {
if (marker.getPosition().equals(feedsModel.getPosition())) {
markerToChange = marker;
}
}
// if found - change icon
if (markerToChange != null) {
markerToChange.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
}
}
});
Bitmap icon = mIconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
#Override
protected void onBeforeClusterRendered(final Cluster<FeedsModel> cluster, final MarkerOptions markerOptions) {
// Draw multiple people.
// Note: this method runs on the UI thread. Don't spend too much time in here (like in this example).
final List<Drawable> profilePhotos = new ArrayList<Drawable>(Math.min(4, cluster.getSize()));
final int width = mDimension;
final int height = mDimension;
int i = 0;
for (final FeedsModel p : cluster.getItems()) {
// Draw 4 at most.
i++;
Glide
.with(mActivity.getApplicationContext())
.load(p.getImages().getThumbnail().getUrl())
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new SimpleTarget<GlideDrawable>() {
#Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
resource.setBounds(0, 0, width, height);
profilePhotos.add(resource);
MultiDrawable multiDrawable = new MultiDrawable(profilePhotos);
multiDrawable.setBounds(0, 0, width, height);
mClusterImageView.setImageDrawable(multiDrawable);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
});
if (i == 4) break;
}
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
With above code, I see that: image load in Item and Cluster wrong when zoom in or zoom out. What is my wrong here ?
Finally, I found solution, I combine with :
protected void onClusterItemRendered(FeedsModel clusterItem, Marker marker)
protected void onClusterRendered(Cluster<FeedsModel> cluster, Marker marker)
these function to load image from URL
#Override
protected void onBeforeClusterItemRendered(Trace trace, MarkerOptions markerOptions) {
// Draw a single person.
// Set the info window to show their name.
mImageView.setImageResource(R.drawable.aa001); //temp image.
icon = mIconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
#Override
protected void onClusterItemRendered(final Trace trace, final Marker marker){
Glide.with(mContext.getApplicationContext())
.load(ApplicationClass.photoServer + trace.image)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.thumbnail(0.1f)
.into(new SimpleTarget<GlideDrawable>() {
#Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
mImageView.setImageDrawable(resource);
icon = mIconGenerator.makeIcon();
marker.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
}
});
}
And for the clusters:
#Override
protected void onBeforeClusterRendered(Cluster<Trace> cluster, MarkerOptions markerOptions) {
super.onBeforeClusterRendered(cluster, markerOptions);
//pick the first media
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
#Override
protected void onClusterRendered(Cluster<Trace> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
//pick the first trace
final Trace trace = cluster.getItems().iterator().next();
Glide.with(mContext.getApplicationContext())
.load(ApplicationClass.photoServer + trace.image)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.centerCrop()
.into(new SimpleTarget<GlideDrawable>() {
#Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
mClusterImageView. setImageDrawable(resource);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
marker.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
}
});
}
This is the solution i found with help of above mentions solution
private class PersonRenderer extends DefaultClusterRenderer<Person> {
private final IconGenerator mIconGenerator = new IconGenerator(getActivity().getApplicationContext());
private final IconGenerator mClusterIconGenerator = new IconGenerator(getActivity().getApplicationContext());
private final ImageView mImageView;
private final ImageView mClusterImageView;
private final int mDimension;
Bitmap icon;
public PersonRenderer() {
super(getActivity().getApplicationContext(), mMap, mClusterManager);
View multiProfile = getLayoutInflater().inflate(R.layout.multi_profile, null);
mClusterIconGenerator.setContentView(multiProfile);
mClusterImageView = (ImageView) multiProfile.findViewById(R.id.image);
mImageView = new ImageView(getActivity().getApplicationContext());
mDimension = (int) getResources().getDimension(R.dimen.custom_profile_image);
mImageView.setLayoutParams(new ViewGroup.LayoutParams(mDimension, mDimension));
int padding = (int) getResources().getDimension(R.dimen.custom_profile_padding);
mImageView.setPadding(padding, padding, padding, padding);
mIconGenerator.setContentView(mImageView);
}
#Override
protected void onBeforeClusterItemRendered(Person person, MarkerOptions markerOptions) {
icon = mIconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(person.name);
}
#Override
protected void onClusterItemRendered(Person clusterItem, final Marker marker) {
Glide.with(getActivity())
.load(clusterItem.profilePhoto)
.apply(new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
.thumbnail(0.1f)
.into(new SimpleTarget<Drawable>() {
#Override
public void onResourceReady(Drawable drawable, Transition<? super Drawable> transition) {
mImageView.setImageDrawable(drawable);
icon = mIconGenerator.makeIcon();
marker.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
}
});
}
#Override
protected void onClusterRendered(final Cluster<Person> cluster, final Marker marker) {
final List<Drawable> profilePhotos = new ArrayList<>(Math.min(4, cluster.getSize()));
final int width = mDimension;
final int height = mDimension;
Bitmap dummyBitmap = null;
Drawable drawable;
final int clusterSize = cluster.getSize();
final int[] count = {0};
for (Person p : cluster.getItems()) {
// Draw 4 at most.
if (profilePhotos.size() == 4) break;
try {
Glide.with(getActivity().getApplicationContext())
.load(p.profilePhoto)
.apply(new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
.into(new SimpleTarget<Drawable>(){
#Override
public void onResourceReady(#NonNull Drawable resource, #Nullable Transition<? super Drawable> transition) {
resource.setBounds(0, 0, width, height);
profilePhotos.add(resource);
MultiDrawable multiDrawable = new MultiDrawable(profilePhotos);
multiDrawable.setBounds(0, 0, width, height);
mClusterImageView.setImageDrawable(multiDrawable);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
marker.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
marker.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
}
#Override
protected void onBeforeClusterRendered(final Cluster<Person> cluster, final MarkerOptions markerOptions) {
}
#Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
// Always render clusters.
return cluster.getSize() > 1;
}
}
Hide the marker in onBeforeClusterRendered. You do this so that the marker icon doesn't flicker between the default icon and your custom icon.
In onClusterItemRendered fetch the icon bitmap, once it is loaded set it as the marker icon and make the marker visible. If bitmap request fails just show the default icon.
Use Picasso for caching.
final String url = "...";
clusterManager.setRenderer(new DefaultClusterRenderer<MapClusterItem>(activity, googleMap, clusterManager) {
#Override
protected void onBeforeClusterItemRendered(MapClusterItem item, MarkerOptions markerOptions) {
markerOptions.visible(false);
}
#Override
protected void onClusterItemRendered(final MapClusterItem clusterItem, final Marker marker) {
Picasso.
with(context).
load(url)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
marker.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));
marker.setVisible(true);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
marker.setVisible(true);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
});
}
});